翼度科技»论坛 编程开发 python 查看内容

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

10

主题

10

帖子

30

积分

新手上路

Rank: 1

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

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

天气信息肯定与城市相关,因此几乎每个天气网站都会有城市列表。让我们先来抓取这些城市列表并保存起来,以备后续使用。以下是相应的代码:
  1. # 导入urllib库的urlopen函数
  2. from urllib.request import urlopen,Request
  3. # 导入BeautifulSoup
  4. from bs4 import BeautifulSoup as bf
  5. 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'}
  6. req = Request("https://www.tianqi.com/chinacity.html",headers=headers)
  7. # 发出请求,获取html
  8. # 获取的html内容是字节,将其转化为字符串
  9. html = urlopen(req)
  10. html_text = bytes.decode(html.read())
  11. obj = bf(html_text,'html.parser')
  12. # 使用find_all函数获取所有图片的信息
  13. province_tags = obj.find_all('h2')
  14. for province_tag in province_tags:
  15.     province_name = province_tag.text.strip()
  16.     cities = []
  17.     print(province_name)
  18.     next_sibling = province_tag.find_next_sibling()
  19.     city_tags = next_sibling.find_all('a')
  20.     for city_tag in city_tags:
  21.         city_name = city_tag.text.strip()
  22.         cities.append(city_name)
  23.         print(city_name)
复制代码
在上述操作中,主要的步骤是从城市地址页面中获取信息,对其进行解析以获取省份和城市之间的对应关系。目前仅仅进行了简单的打印输出。
城市天气

在获取城市信息之后,接下来的步骤是根据城市信息获取天气信息。在这里,我们仅考虑直辖市的天气情况,而省份的天气信息获取相比直辖市多了一步省份的跳转。我们暂时不进行省份天气信息的演示。现在,让我们一起来看一下代码:
  1. # 导入urllib库的urlopen函数
  2. from urllib.request import urlopen,Request
  3. # 导入BeautifulSoup
  4. from bs4 import BeautifulSoup as bf
  5. 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'}
  6. req = Request(f"https://www.tianqi.com/beijing/",headers=headers)
  7. # 发出请求,获取html
  8. # 获取的html内容是字节,将其转化为字符串
  9. html = urlopen(req)
  10. html_text = bytes.decode(html.read())
  11. obj = bf(html_text,'html.parser')
  12. city_tags = obj.find_all('div',class_='mainWeather')
  13. for city_tag in city_tags:
  14.     a_tags = city_tag.find_all('a', class_=lambda value: value != 'd15')
  15.     for a_tag in a_tags:
  16.         title = a_tag.get('title')
  17.         print(title)
  18. foods = obj.find_all('ul',class_='paihang_good_food')
  19. for food in foods:
  20.     a_tags = food.find_all('a')
  21.     for a_tag in a_tags:
  22.         href = a_tag.get('href')
  23.         print(href)
  24.         title = a_tag.get('title')
  25.         print(title)
  26. weather_info = obj.find_all('dl', class_='weather_info')
  27. for info in weather_info:
  28.     city_name = info.find('h1').text
  29.     date = info.find('dd', class_='week').text
  30.     temperature = info.find('p', class_='now').text
  31.     humidity = info.find('dd', class_='shidu').text
  32.     air_quality = info.find('dd', class_='kongqi').h5.text
  33.     print(f"地点:{city_name}")
  34.     print(f"时间:{date}")
  35.     print(f"当前温度:{temperature}")
  36.     print(humidity)
  37.     print(air_quality)   
复制代码
以上代码不仅仅把天气解析出来,而且将当前地址的天气和各个城区 的天气以及当地美食都解析了出来。当地美食因为链接是变动的,所以将链接和美食做了响应的映射关系保存。
城市美食

在确定天气适宜的情况下,我们通常都会想了解当地有哪些特色美食,毕竟不能总是吃快餐,特色美食才是我们吃货的灵魂所在。
以下是一个示例代码:
  1. # 导入urllib库的urlopen函数
  2. from urllib.request import urlopen,Request
  3. # 导入BeautifulSoup
  4. from bs4 import BeautifulSoup as bf
  5. 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'}
  6. req = Request(f"https://www.tianqi.com/meishi/1737.html",headers=headers)
  7. # 发出请求,获取html
  8. # 获取的html内容是字节,将其转化为字符串
  9. html = urlopen(req)
  10. html_text = bytes.decode(html.read())
  11. obj = bf(html_text,'html.parser')
  12. span_tag = obj.find('span', class_='traffic')
  13. text_content = ''.join(span_tag.stripped_strings)
  14. print(text_content)
复制代码
在这里,我主要解析了当前美食推荐的原因。实际上,链接应该与之前解析的天气信息相关联,但为了演示方便,我在示例代码中使用了固定值。
包装一下

将以上内容单独制作成小案例确实是一种有效的方式,但将其整合成一个简单的小应用则更具实用性,因为这样可以实现更灵活的交互。让我们一起来看一下最终的代码:
[code]# 导入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 import  readkeyfrom 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 = [f'{i + j}:{city_province_mapping[i + j][0]}' 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 = [f'{i + j}:{good_foods[i + j][1]}' 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 = [f'{i + j}:{weather[i + j]}' 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[1][0])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

举报 回复 使用道具