数据获取
Contents
数据获取¶
为了能够获得实时数据,我们采用调用网上的开源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还原成真实的时间戳。
将int转换为timedelta
将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获取天气预测信息。 在进行其他操作之前,我们需要清理一下我们的代码,最好写成函数形式,因为未来需要重复调用它们。