数据来自中国天气网
import requests
import json
import sys
from bs4 import BeautifulSoup
通过开发者工具中可以看到,每当输入框中的内容发生变化的时候,浏览器都会发送一个get请求,服务器收到这个请求后返回了一个json文件,这个文件存有与输入地名相关的一些地名和对应的编号,图1红色框中的数据就是来自这里。我们用requests,get
的方法模拟浏览器发送这个请求拿到这个json数据稍做处理
# 将输入的 地名 转化 为存有相关地点数据的json数据
def cityNameToJsonData(_cityname):
url = "http://toy1.weather.com.cn/search"
_params = {'cityname': _cityname, 'callback': "success_jsonpCallback"}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0'; 'Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"}
resp = requests.get(url, params=_params, headers=headers)
resp.encoding = 'utf-8'
strdata = resp.text.split('(')[1][:-1]
JsonData = json.loads(strdata)
return JsonData
上面说过了,这个json文件中不仅有相关地点的名字,还有对应的id,我们可以暂时先把相关地名都print出来,通过输入地名序号的方法确定目标地点的id(模拟在浏览器中点击了输入框的弹出选项)
# 把json数据中的相关地名展示出来,进行二次选择 确定查询目标 返回目标地点的id
def getId(jsonData):
cityInfo = []
for data in jsonData:
# ['101010100', 'beijing', '北京', 'Beijing', '北京', 'Beijing', '10', '100000', 'BJ', '北京']
temp = data["ref"].split("~")
# '101010100'
_id = temp[0]
# '北京-北京-北京'
cityName = temp[9] + "-" + temp[4] + "-" + temp[2]
cityInfo.append([_id, cityName])
print("\n请输入下列地名前的序号再次确定:")
for index in range(len(cityInfo)):
print(str(index + 1) + ": " + cityInfo[index][1])
cityNo = int(input())
while cityNo < 1 or cityNo > len(cityInfo):
cityNo = int(input("编号有误,请重新输入\n"))
return cityInfo[cityNo - 1][0]
我们随便查询一个地方的天气就可以发现,展示某地区天气的网址为:
http://www.weather.com.cn/weather/cityId.shtml
cityId为对应地区的id。
例如:
北京近七天的天气情况:http://www.weather.com.cn/weather/101010100.shtml
但是经过测试发现一些id长度大于9的地区的天气网址格式为:
http://forecast.weather.com.cn/town/weathern/cityId.shtml
例如:
河南嵩县大坪村近七天的天气情况为:http://forecast.weather.com.cn/town/weathern/101180907004.shtml
推测应该是县级以下单位采用第二种方法(没有过多测试),因此我们根据id的长度不同分两种方法来获取城市的天气情况,由于网页的布局也是不同的,所以要对两种长度的id分开处理,当然,处理过程还是差不多的(用requests.get
获取到网页的html
文件,用BeautifulSoup
进行一下解析,最后再对数据进行一下筛选与字符串的处理)
def getCityWeaInfoById(cityId):
if len(cityId) <= 9:
url = "http://www.weather.com.cn/weather/%s.shtml" % cityId
resp = requests.get(url)
resp.encoding = 'utf-8'
soup = BeautifulSoup(resp.text, 'lxml')
weaDiv = soup.find('ul', class_="t")
day_weaDiv = weaDiv.find_all('li')
for div in day_weaDiv:
date = div.find('h1').text
wea = div.find('p', class_="wea").text
tem = div.find('p', class_="tem").text
winDiv = div.find('p', 'win')
win = ""
for span in winDiv.find_all('span'):
win += span['title'] + " "
win += winDiv.find('i').text.split(';')[-1]
# 空格
print()
print(date)
print(wea)
print(tem)
print(win)
print("-----------------------------------------------------")
else:
url = "http://forecast.weather.com.cn/town/weathern/%s.shtml" % cityId
resp = requests.get(url)
resp.encoding = 'utf-8'
soup = BeautifulSoup(resp.text, 'lxml')
temdiv = soup.find('div', class_="blueFor-container")
js = temdiv.find('script')
eventDay = js.text.split('[')[-2].replace('"', '').split(']')[0]
eventEight = js.text.split('[')[-1].replace('"', '').split(']')[0]
eventDay = eventDay.split(',')
eventEight = eventEight.split(',')
dateDiv = soup.find('ul', class_="date-container").find_all('li')
dateList = []
for div in dateDiv:
date = div.find('p', class_="date").text
date_info = div.find('p', class_="date-info").text
dateList.append([date, date_info])
weaDiv = soup.find('ul', class_="blue-container")
wea = []
for div in weaDiv.find_all('li', class_="blue-item"):
weather_info = div.find('p', class_="weather-info").text.replace(" ", '').strip()
win_info = div.find_all('i', class_='wind-icon')[0]['title'] + " " + div.find_all('i', class_='wind-icon')[
0]['title'] + " " + div.find('p', class_='wind-info').text.strip()
wea.append(weather_info+"\n"+win_info)
for index in range(len(dateList)):
# 空格
print()
print(dateList[index][0]+" "+dateList[index][1])
print(eventDay[index]+"℃/"+eventEight[index]+"℃")
print(wea[index])
print("--------------------------------------------------------------")
if __name__ == '__main__':
cmd = 1
while cmd:
cityName = input("\n输入城市、乡镇、街道、景点名称 查天气:\n")
jsonData = cityNameToJsonData(cityName)
if len(jsonData) == 0:
print("抱歉未查询到数据。请确认地名无误并尝试重新输入\n")
continue
cityId = getId(jsonData)
getCityWeaInfoById(cityId)
cmd = int(input("输入0退出程序,输入1继续查询\n\n"))