程序设计过程里的一些心得:
0. 规模较大的程序,往往都是以更小的功能块搭建起来的。如此,为了提升总体程序的构建效率, 笔者发现分“两步走”会比较高效:
A. 遇到需要反复调试的功能块,可先在另一程序中逐一单独测试某一功能块(这有助于突出模块本身的细节问题)
B. 最后像搭积木一样将模块放回主题程序中,进行一些接口性的“磨合”
1. 见招拆招,必备的是灵活的思路
相比于上一篇初代爬虫,进阶爬虫的核心特点在于可以提供未来五天天气情况的预测,而这也是程序实现的关键难点。具体而言有如下两方面:
A. 如何精准获取:
由于要获取的信息较多较细,观察网页html原码,或者参考编译过程中直接用find_all函数获取的结果不难发现,由于网页原码中标签的重复性较大,通过一次find_all获得的可迭代对象可谓是“鱼龙混杂”。
解决方案:多层搜索,缩小目标范围:#以获取list_weather为例
weathers = soup.find_all("td",attrs={"width":"20%", "align":"left"})
list_weather = []
for weather in weathers:#预处理
weather = weather.find("p")#找到除上述标签外还有标签"p"的
weather = weather.find("span")#找到除上述标签外还有标签"span"的
if weather:#排除weather为None的情况
list_weather.append(weather.string)
AT:find_all返回的对象只可用,且可不断用“find”函数
B.如何“完美”输出:
笔者在输出这一步碰上一个麻烦:要实现如下的规整输出,就不得不在一次for循环中将日期、气温、天气的值都输出一遍。
但是!麻烦来了,他们三者在find_all后得到的元素个数并不一样,但for循环的更新一次的依据恰恰是根据迭代一次来进行的(迭代一次,for循环进行一次),因此想要实现“优雅“输出大概没有那么容易。
解决方案:预处理
还是以上面的获取list_weather为例,实际上,之所以要专门建立一个list_weather,恰恰是为了将有效元素留在里面,最终list_weather中只留下干净的五个元素。
完整代码如下:
#请求头headers的值需根据电脑信息自行提供哈,具体方法可参考b站视频讲解哈,此处不再赘述
from bs4 import BeautifulSoup
import requests
from pypinyin import pinyin, Style
import time
import os
if __name__ == '__main__':
headers = { }
mode = 1
while mode != -1:
try:
os.system("cls")
mode = 1
print("----------勇敢虫虫,不怕困难!----------")
print("~让虫虫爬一会~")
response = requests.get("http://qq.ip138.com/weather/", headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.content, "html.parser", from_encoding="utf-8")
provinces = soup.find_all("dd")
# 打印所所有城市名
dict_province = {}
for idx, province in enumerate(provinces):
province_text = province.get_text(strip = True)
print(idx, province_text)
dict_province.setdefault(idx, province_text)
#接收用户选择省份
idx_province = int(input("请选择您关注的省对应序号(虫虫只爬得动省份哈, 至于市、区,请期待一下吧~):"))
province_chosen = dict_province[idx_province]
# pinyin_province = ' '.join([''.join(pinyin(char, style=Style.NORMAL)) for char in province_chosen])
pinyin_list_province = []
for char in province_chosen:
# pinyin函数返回的是一个列表,其中包含了每个音节的列表(对于多音字)
# 使用列表推导式将每个音节的列表转换为用空格分隔的字符串
pinyin_chars = ' '.join([''.join(py) for py in pinyin(char, style=Style.NORMAL)])
pinyin_list_province.append(pinyin_chars)
# 最后,使用join函数将所有汉字的拼音连接起来,用空格分隔
pinyin_province = ''.join(pinyin_list_province)
#省份 #访问对应省份网址
response = requests.get(f"https://qq.ip138.com/weather/{pinyin_province}/", headers=headers)
soup = BeautifulSoup(response.content, "html.parser")
cities = soup.find_all("a", attrs={"class", "title"})
temps = soup.find_all("span", attrs={"class":"temp"})
weathers = soup.find_all("span", attrs={"class":"weather"})
dict_cities = {}
dict_temps = {}
dict_weathers = {}
idx = 1
for city, temp, weather in zip(cities, temps, weathers):
city_text = city.get_text(strip = True)
print(idx, city.string)
dict_cities.setdefault(idx, city_text)
dict_temps.setdefault(idx, temp)
dict_weathers.setdefault(idx, weather)
idx += 1
#接收用户输入城市
while mode == 1:
idx_city = int(input("请选择你要关注的城市对应序号:"))
city_chosen = list(dict_cities[idx_city])
city_chosen = ''.join(city_chosen[:len(city_chosen)-4])
pinyin_list_city = []
for char in city_chosen:
# pinyin函数返回的是一个列表,其中包含了每个音节的列表(对于多音字)
# 使用列表推导式将每个音节的列表转换为用空格分隔的字符串
pinyin_chars = ' '.join([''.join(py) for py in pinyin(char, style=Style.NORMAL)])
pinyin_list_city.append(pinyin_chars)
# 最后,使用join函数将所有汉字的拼音从列表中提取出来并连接起来,用空格分隔
pinyin_list_city = pinyin_list_city[:len(pinyin_list_city)]#去掉末尾“天气预报”对应拼音
pinyin_city = ''.join(pinyin_list_city)
city_temp = dict_temps[idx_city]
city_weather = dict_weathers[idx_city]
print("\n找到啦:\n{0}市今日{1},温度{2}".format(city_chosen, city_weather.string, city_temp.string))
time.sleep(2)
mode = int(input("天气虫虫:看完了这座城,接下来要俺做什么嘞?(请输入:-1:结束一切程序/ 0:看看别的省(市、区)/1:看看本省的其他城市)/2:了解下当前城市未来五天天气发展情况 :"))
if mode == 2:
response = requests.get(f"https://qq.ip138.com/weather/{pinyin_province}/{pinyin_city}.htm", headers=headers)
soup = BeautifulSoup(response.content, "html.parser")
dates = soup.find_all("p", attrs={"class":"date"})
weathers = soup.find_all("td",attrs={"width":"20%", "align":"left"})
# weather = weathers.f
temperatures = soup.find_all("td", attrs={"width":"15%", "align":"center"})
list_weather = []
for weather in weathers:#预处理
weather = weather.find("p")
weather = weather.find("span")
if weather:
list_weather.append(weather.string)
print(f"--------好滴~未来五天,{city_chosen}天气情况见下哦--------")
print("日期".ljust(len("2024-07-01")), "气温".ljust(len("20℃ ~ 28℃ ")), "天气")
for date, temp, wehather in zip(dates, temperatures, list_weather):
print(date.string, end=" | ")
temp = temp.find("p")
print(temp.string, end=" | ")
print(weather.string)
time.sleep(5)
mode = int(input("看完了这座城,接下来要我做什么嘞?(请输入:-1:结束一切程序/ 0:看看别的省(市、区)/1:看看本省的其他城市 :"))
except requests.RequestException as ex:
print(f"网络错误:{ex}")
在vscode上运行可实现如下输出:
~ 本文是笔者超级用心写的,衷心希望能给你带来些许启发! ~
标签:province,city,进阶,虫虫,pinyin,list,python,weather,find From: https://blog.csdn.net/H13420972436/article/details/140111804