数据获取

为了能够获得实时数据,我们采用调用网上的开源API来获取。一贯的,我不推荐采用爬虫获取数据。

感谢国内大神的提供:https://www.7timer.info/.

通过这个网站,我们可以输入地理位置(纬度和经度)来获取未来的天气预测。 比如,对于上海来说,它的入口地址为: https://www.7timer.info/bin/api.pl?lon=121.474&lat=31.23&product=civil&output=json

需要说明的是: 这个网站提供了多个产品,用于查询天气信息,最常用的就是民用 - CIVIL,如果你有需要就可以使用其他API获取更多信息

发生请求Request

对一个网站的API获取信息的方式就是发送请求,有超级多的模块可以帮你完成这个任务,最常用的就是requests。这个几乎是鼻祖级别的,其他的无非是打包一些新特色。

首先我们需要安装requests, 使用pip即可。

同样需要注意的是:不能拼错,记得新闻里面提到过有黑客采用障眼法,弄了一个以假乱真的requests 包

! pip install requests

对于requests 包(任何一个包),查看他们的quickstart就可以实战了。

https://docs.python-requests.org/en/latest/user/quickstart/

import requests
url = 'https://www.7timer.info/bin/api.pl?lon=121.474&lat=31.23&product=civil&output=json'
r = requests.get(url)
print(r)
print(r.encoding)
print(type(r.text))
<Response [200]>
UTF-8
<class 'str'>

对于响应的数据,我们需要把它解析成比较方便处理的python对象,比如dict或者更高级的DataFrame。

默认情况下,requests 返回的是json格式。

Python自带有json模块,可以帮助我们通过loads 转换为其他dict。

import json
text_j= json.loads(r.text)
print(type(text_j))
<class 'dict'>

我们可以查看一下text_j的内容

text_j.keys()
dict_keys(['product', 'init', 'dataseries'])
text_j['product']
'civil'
text_j['init']
'2022020200'
text_j['dataseries'][0]
{'timepoint': 3,
 'cloudcover': 9,
 'lifted_index': 15,
 'prec_type': 'rain',
 'prec_amount': 1,
 'temp2m': 4,
 'rh2m': '75%',
 'wind10m': {'direction': 'NE', 'speed': 3},
 'weather': 'lightrainday'}

解析数据

我们注意到最有用的信息包含在dataseries元素中,对于这种list of dict格式的数据,我们建议采用DataFrame 来解析,应为它很像excel一个表格的内容。

关于每个字段的含义,可以参考 https://github.com/Yeqzids/7timer-issues/wiki/Wiki

import pandas as pd
weather_info = pd.DataFrame(text_j['dataseries'])
weather_info.head(5)
timepoint cloudcover lifted_index prec_type prec_amount temp2m rh2m wind10m weather
0 3 9 15 rain 1 4 75% {'direction': 'NE', 'speed': 3} lightrainday
1 6 9 15 rain 2 4 70% {'direction': 'NE', 'speed': 3} lightrainday
2 9 9 15 rain 2 4 71% {'direction': 'NE', 'speed': 3} lightrainday
3 12 9 15 rain 2 3 86% {'direction': 'NE', 'speed': 3} lightrainnight
4 15 9 15 rain 2 3 92% {'direction': 'NE', 'speed': 3} lightrainnight

数据变换

字符串转时间

“init” 时间戳非常重要,但是它存储为str格式。 所以我们需要还原为datetime格式。而且,我们决定采用DataFrame来转换原始数据,为了一致性,我们采用 pd.to_datetime 函数而不是 datetime 模块来进行变换.

start_time = pd.to_datetime(text_j['init'],format='%Y%m%d%H')
start_time
Timestamp('2022-02-02 00:00:00')

int转timedelta

timepoint 列表示未来N个小时,起始从init 开始算起。同样的,我们需要将这个timepoint还原成真实的时间戳。

  1. 将int转换为timedelta

  2. 将timedelta变成时间戳

# convert timepoint to timestamp
weather_info['timepoint'] = pd.to_timedelta(weather_info['timepoint'],unit='h')
weather_info['timestamp'] = start_time+ weather_info['timepoint']
weather_info.head(5)
timepoint cloudcover lifted_index prec_type prec_amount temp2m rh2m wind10m weather timestamp
0 0 days 03:00:00 9 15 rain 1 4 75% {'direction': 'NE', 'speed': 3} lightrainday 2022-02-02 03:00:00
1 0 days 06:00:00 9 15 rain 2 4 70% {'direction': 'NE', 'speed': 3} lightrainday 2022-02-02 06:00:00
2 0 days 09:00:00 9 15 rain 2 4 71% {'direction': 'NE', 'speed': 3} lightrainday 2022-02-02 09:00:00
3 0 days 12:00:00 9 15 rain 2 3 86% {'direction': 'NE', 'speed': 3} lightrainnight 2022-02-02 12:00:00
4 0 days 15:00:00 9 15 rain 2 3 92% {'direction': 'NE', 'speed': 3} lightrainnight 2022-02-02 15:00:00

从城市名获取地理位置

如果你想输入城市名,然后直接获取天气信息呢? 那么我们就需要通过城市名先获取地理位置。幸运的是,已经有模块可以帮我们完成这个任务geopy

如果你需要的话,可以安装。

pip install geopy

关于geopy可以参考: https://geopy.readthedocs.io/en/stable/

from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent='baidu')
location = geolocator.geocode("shanghai")
print(location.address)
print((location.latitude, location.longitude))
上海市, 黄浦区, 上海市, 200001, 中国
(31.2322758, 121.4692071)

小结

到目前为止,我们一步一步的实现如何输入城市名,然后调用api获取天气预测信息。 在进行其他操作之前,我们需要清理一下我们的代码,最好写成函数形式,因为未来需要重复调用它们。