致我逝去的青春 发表于 2024-3-18 08:55:53

爬虫实战:从外地天气到美食推荐,探索干饭人的世界

今天是第二堂课,我们将继续学习爬虫技术。在上一节课中,我们已经学会了如何爬取干饭教程。正如鲁迅所说(我没说过),当地吃完饭就去外地吃,这启发了我去爬取城市天气信息,并顺便了解当地美食。这个想法永远是干饭人的灵魂所在。
今天我们的目标是学习如何爬取城市天气信息,因为要计划去哪里玩耍,首先得了解天气情况。虽然我们的手机已经装有许多免费天气软件,但是也不妨碍我们学习。
在我们开始学习爬虫技术之前,首先需要找到一个容易爬取数据的天气网站。并不要求特定网站,只要易于爬取的网站即可。毕竟我们目前并不需要爬取特定网站来抢票或抢购商品,我们的主要目的是学习爬虫技术。
天气爬虫

在进行爬虫操作时,如果不确定一个网站是否易于爬取,可以先尝试输入该网站的首页地址,查看能否成功解析出HTML网页。如果解析出来的页面与实际浏览的页面一致,那么说明该网站可能没有设置反爬虫机制;反之,如果解析出来的页面与实际不同,那么该网站很可能设置了反爬虫措施。在学习阶段,建议选择较为容易爬取的网站进行练习,避免过早挑战难度过大的网站。
好的,废话不多说,我们现在就开始抓取该网站上的所有城市信息。
城市列表

天气信息肯定与城市相关,因此几乎每个天气网站都会有城市列表。让我们先来抓取这些城市列表并保存起来,以备后续使用。以下是相应的代码:
# 导入urllib库的urlopen函数
from urllib.request import urlopen,Request
# 导入BeautifulSoup
from bs4 import BeautifulSoup as bf

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}
req = Request("https://www.tianqi.com/chinacity.html",headers=headers)
# 发出请求,获取html
# 获取的html内容是字节,将其转化为字符串
html = urlopen(req)
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
# 使用find_all函数获取所有图片的信息
province_tags = obj.find_all('h2')
for province_tag in province_tags:
    province_name = province_tag.text.strip()
    cities = []
    print(province_name)
    next_sibling = province_tag.find_next_sibling()
    city_tags = next_sibling.find_all('a')
    for city_tag in city_tags:
      city_name = city_tag.text.strip()
      cities.append(city_name)
      print(city_name)在上述操作中,主要的步骤是从城市地址页面中获取信息,对其进行解析以获取省份和城市之间的对应关系。目前仅仅进行了简单的打印输出。
城市天气

在获取城市信息之后,接下来的步骤是根据城市信息获取天气信息。在这里,我们仅考虑直辖市的天气情况,而省份的天气信息获取相比直辖市多了一步省份的跳转。我们暂时不进行省份天气信息的演示。现在,让我们一起来看一下代码:
# 导入urllib库的urlopen函数
from urllib.request import urlopen,Request
# 导入BeautifulSoup
from bs4 import BeautifulSoup as bf

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}
req = Request(f"https://www.tianqi.com/beijing/",headers=headers)
# 发出请求,获取html
# 获取的html内容是字节,将其转化为字符串
html = urlopen(req)
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
city_tags = obj.find_all('div',class_='mainWeather')
for city_tag in city_tags:
    a_tags = city_tag.find_all('a', class_=lambda value: value != 'd15')
    for a_tag in a_tags:
      title = a_tag.get('title')
      print(title)
foods = obj.find_all('ul',class_='paihang_good_food')
for food in foods:
    a_tags = food.find_all('a')
    for a_tag in a_tags:
      href = a_tag.get('href')
      print(href)
      title = a_tag.get('title')
      print(title)
weather_info = obj.find_all('dl', class_='weather_info')
for info in weather_info:
    city_name = info.find('h1').text
    date = info.find('dd', class_='week').text
    temperature = info.find('p', class_='now').text
    humidity = info.find('dd', class_='shidu').text
    air_quality = info.find('dd', class_='kongqi').h5.text
    print(f"地点:{city_name}")
    print(f"时间:{date}")
    print(f"当前温度:{temperature}")
    print(humidity)
    print(air_quality)   以上代码不仅仅把天气解析出来,而且将当前地址的天气和各个城区 的天气以及当地美食都解析了出来。当地美食因为链接是变动的,所以将链接和美食做了响应的映射关系保存。
城市美食

在确定天气适宜的情况下,我们通常都会想了解当地有哪些特色美食,毕竟不能总是吃快餐,特色美食才是我们吃货的灵魂所在。
以下是一个示例代码:
# 导入urllib库的urlopen函数
from urllib.request import urlopen,Request
# 导入BeautifulSoup
from bs4 import BeautifulSoup as bf

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}
req = Request(f"https://www.tianqi.com/meishi/1737.html",headers=headers)
# 发出请求,获取html
# 获取的html内容是字节,将其转化为字符串
html = urlopen(req)
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
span_tag = obj.find('span', class_='traffic')
text_content = ''.join(span_tag.stripped_strings)
print(text_content)在这里,我主要解析了当前美食推荐的原因。实际上,链接应该与之前解析的天气信息相关联,但为了演示方便,我在示例代码中使用了固定值。
包装一下

将以上内容单独制作成小案例确实是一种有效的方式,但将其整合成一个简单的小应用则更具实用性,因为这样可以实现更灵活的交互。让我们一起来看一下最终的代码:
# 导入urllib库的urlopen函数from urllib.request import urlopen,Requestimport urllib,string# 导入BeautifulSoupfrom bs4 import BeautifulSoup as bffrom random import choice,samplefrom colorama import initfrom os import systemfrom termcolor import coloredfrom readchar importreadkeyfrom xpinyin import Pinyinp = Pinyin()city_province_mapping = []province_sub_weather = []good_foods = []FGS = ['green', 'yellow', 'blue', 'cyan', 'magenta', 'red']def clear():    system("CLS")def get_city_province_mapping():    print(colored('开始搜索城市',choice(FGS)))    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}    req = Request("https://www.tianqi.com/chinacity.html",headers=headers)    # 发出请求,获取html    # 获取的html内容是字节,将其转化为字符串    html = urlopen(req)    html_text = bytes.decode(html.read())    obj = bf(html_text,'html.parser')    # 使用find_all函数获取所有图片的信息    province_tags = obj.find_all('h2')    for province_tag in province_tags:      province_name = province_tag.text.strip()      cities = []      next_sibling = province_tag.find_next_sibling()      city_tags = next_sibling.find_all('a')      for city_tag in city_tags:            city_name = city_tag.text.strip()            cities.append(city_name)      city_province_mapping.append((province_name,cities))def get_province_weather(province):    print(colored(f'已选择:{province}',choice(FGS)))    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}    req = Request(f"https://www.tianqi.com/{province}/",headers=headers)    # 发出请求,获取html    # 获取的html内容是字节,将其转化为字符串    html = urlopen(req)    html_text = bytes.decode(html.read())    obj = bf(html_text,'html.parser')    city_tags = obj.find_all('div',class_='mainWeather')    # city_tags = obj.find_all('ul',class_='raweather760')    province_sub_weather.clear()    print(colored('解析主要城市中',choice(FGS)))    for city_tag in city_tags:      a_tags = city_tag.find_all('a', class_=lambda value: value != 'd15')      for a_tag in a_tags:            title = a_tag.get('title')            province_sub_weather.append(title)    foods = obj.find_all('ul',class_='paihang_good_food')    print(colored('解析热搜美食中',choice(FGS)))    for food in foods:      a_tags = food.find_all('a')      for a_tag in a_tags:            href = a_tag.get('href')            title = a_tag.get('title')            good_foods.append((href, title))    weather_info = obj.find_all('dl', class_='weather_info')    print(colored('解析完毕',choice(FGS)))    for info in weather_info:      city_name = info.find('h1').text      date = info.find('dd', class_='week').text      temperature = info.find('p', class_='now').text      humidity = info.find('dd', class_='shidu').text      air_quality = info.find('dd', class_='kongqi').h5.text      print(colored(f"地点:{city_name}",choice(FGS)))      print(colored(f"时间:{date}",choice(FGS)))      print(colored(f"当前温度:{temperature}",choice(FGS)))      print(colored(humidity,choice(FGS)))      print(colored(air_quality,choice(FGS)))   def search_food(link):    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}    req = Request(f"https://www.tianqi.com{link}",headers=headers)    # 发出请求,获取html    # 获取的html内容是字节,将其转化为字符串    html = urlopen(req)    html_text = bytes.decode(html.read())    obj = bf(html_text,'html.parser')    span_tag = obj.find('span', class_='traffic')    text_content = ''.join(span_tag.stripped_strings)    print(colored(text_content,choice(FGS)))def print_menu():    for i in range(0, 4, 3):      names = }' for j in range(3) if i + j < 4]      print(colored('\t\t'.join(names),choice(FGS)))def print_food():    if not good_foods:      print(colored('请选择城市,才可查看',choice(FGS)))      return    for i in range(0, len(good_foods), 3):      names = }' for j in range(3) if i + j < len(good_foods)]      print(colored('\t\t'.join(names),choice(FGS)))def print_hot(weather):    if not weather:      print(colored('请选择城市,才可查看',choice(FGS)))      return    for i in range(0,len(weather), 3):      names = }' for j in range(3) if i + j < len(weather)]      print(colored('\t\t'.join(names),choice(FGS)))get_city_province_mapping()# get_province_weather('beijing')# search_food(good_foods)init() ## 命令行输出彩色文字print(colored('已搜索完毕!',choice(FGS)))print(colored('m:返回首页',choice(FGS)))print(colored('h:查看当前城区天气',choice(FGS)))print(colored('f:查看当地美食',choice(FGS)))print(colored('q:退出天气',choice(FGS)))my_key = ['q','m','c','h','f']while True:    while True:      move = readkey()      if move in my_key:            break    if move == 'q': ## 键盘‘Q’是退出      break   if move == 'c': ## 键盘‘C’是清空控制台      clear()    if move == 'h':          print_hot(province_sub_weather)    if move == 'f':          print_food()      num = int(input('请输入美食编号:=====>'))      if num
页: [1]
查看完整版本: 爬虫实战:从外地天气到美食推荐,探索干饭人的世界