前言
最近做了几个查询天气预报的小案例,也对比了网上现有的一些案例,都是通过API获取json数据或者是从一些天气网站上面抓取。
就拿中国天气网来说,很多教程都是通过城市的地区ID来获取天气信息。
如果通过中国天气网来查询,在不知道城市区域码的情况下能不能只查询地区名称就能获取相应的天气信息呢?
解决方案(仅供学习,请勿用于非法用途)
获取地区码
通过调试工具F12,查看中国天气网的网络请求不难发现,在进行页面请求时有个city.js文件里面保存了地区与地区码的字典关系。
是一个多层级的字典数据,一共1万三千多行,大致的分析一下,发现数据非常的详细,精确到区县,那么我们只需要把这个city.js的文件内容处理一下,就能获取到我们需要的城市名与城市区域ID相对应的字典数据。
下面我们开始处理数据
首先将city.js文件下载到本地,删除掉第一行的 var city_data =,得到我们要处理的多层级字典。
保存成city_dic.json或者city_dic.txt都行。
通过对数据的分析,发现这是一个嵌套三层的字典。接下来我们简单的处理下数据,借助dict.items()方法,不熟悉的同学可以自行学习下。
import json
#打开从中国天气网获取的city.js的内容文件
with open('city_dic.json','r', encoding='UTF-8') as f:
city_info = f.read()
#由于打开读取后为字符串类型的,我们转为json对象
city_dict = json.loads(city_info)
#定义一个空字典用来保存我们最终需要的城市码字典
new_city_dic = {}
#三层循环拿到数据
for i,item1 in city_dict.items():
for j,item2 in item1.items():
for k,item3 in item2.items():
new_city_dic[k] = item3
#将处理好的数据保存成文件,后面我们根据这个文件的字典数据来查询城市的区域码
with open("city.json",'w', encoding='UTF-8') as f:
f.write(str(new_city_dic))
获取最近七天的天气
通过以上地址就能获取七天的天气情况,上面我们已经获得了城市名和城市码的字典,我们只需要替换链接中的ID值就能获取相应城市的天气,下面我们来分析下网页结构,七天的天气都在一个id为7d的div块里,我们使用BeautifulSoup来进行处理数据。
下面是完整的代码,代码中的city.json文件是上文中获取地区码那部分处理好的字典文件
import requests
from bs4 import BeautifulSoup
def get_city_codes():
with open('city.json', 'r', encoding='utf-8') as f:
code_dic = eval(f.read())
return code_dic
def get_html(code):
weather_url = f'http://www.weather.com.cn/weather/{code}.shtml'
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"}
print(weather_url)
resp = requests.get(url=weather_url, headers=header)
resp.encoding = 'utf-8'
return resp.text
def get_page_data(html):
soup = BeautifulSoup(html, 'html.parser')
weather_info = soup.find('div', id='7d')
seven_weather = weather_info.find('ul')
weather_list = seven_weather.find_all('li')
for weather in weather_list:
print('=' * 60)
print(weather.find('h1').get_text())
print('天气状况:', weather.find('p', class_='wea').get_text())
# 判断标签'p','tem'下是否有标签'span',以此判断是否有最高温
if weather.find('p', class_='tem').find('span'):
temp_high = weather.find('p', class_='tem').find('span').get_text()
else:
temp_high = '' # 最高温
temp_low = weather.find('p', class_='tem').find('i').get_text() # 最低温
print(f'天气温度:{temp_low}/{temp_high}')
win_list_tag = weather.find('p', class_='win').find('em').find_all('span')
win_list = []
for win in win_list_tag:
win_list.append(win.get('title'))
print('风向:', '-'.join(win_list))
print('风力:', weather.find('p', class_='win').find('i').get_text())
def main():
code_dic = get_city_codes()
print('=' * 60)
print('\t' * 5, '天气预报查询系统')
print('=' * 60)
city = input("请输入您要查询的城市:")
if city in code_dic:
html = get_html(code_dic[city]['AREAID'])
get_page_data(html)
else:
print('你要查询的地方不存在')
if __name__ == '__main__':
main()
运行结果
后话
这只是简单的处理获取,关于获取实时天气,通过分析这部分是js动态加载的,可以使用webdrive进行动态获取。数据显示方面也可以使用matplotlib进行可视化输出。