用python写一个简单的天气查询脚本

数据来自中国天气网

废话不多说,先看下效果
用python写一个简单的天气查询脚本_第1张图片
用python写一个简单的天气查询脚本_第2张图片

代码解析

先导入一些要用到的模块

import requests
import json
import sys
from bs4 import BeautifulSoup

通过的城市名获取一个存有相关地点的json文件

用python写一个简单的天气查询脚本_第3张图片
用python写一个简单的天气查询脚本_第4张图片
通过开发者工具中可以看到,每当输入框中的内容发生变化的时候,浏览器都会发送一个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数据中的地名展示出来,供使用者二次选择

上面说过了,这个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]

通过上面获得的id,查询该地区近一周的天气情况

我们随便查询一个地方的天气就可以发现,展示某地区天气的网址为:
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"))

更多源码

  • 用python爬取王者荣耀官网的英雄皮肤海报(含源码)
  • python爬虫爬取王者荣耀官网全部英雄头像(源码分享)
  • python爬虫爬取王者荣耀官网全部装备图片(源码分享)
  • python爬虫爬取王者荣耀官网全部英雄技能信息(源码分享)

你可能感兴趣的:(用python写一个简单的天气查询脚本)