通过3.1节,我们知道API提供了全国3181个城市的天气预报,可以通过互联网在线爬取或读取城市列表,然后通过循环语句一次性获取3181个城市的天气预报。通过阅读文档读取API提供的城市,其城市数量是会变动的,因此最好的方式是直接从网上读取,这样就可以省去人工更新城市列表的工作了。
从网上读取数据的第一步是获取城市列表,然后根据城市列表循环,代码如下。
import requests
url = 'https://cdn.heweather.com/china-city-list.txt'
strhtml = requests.get(url)
strhtml.encoding = 'utf8' #设置爬取结果编码格式
data = strhtml.text
data1 = data.split("\n")
for i in range(6): # 因为前6行没数据,删除前6行
data1.remove(data1[0])
for item in data1:
print(item[2:13])
运行上面这段代码可以提取所有的城市代码,如下图所示。
接下来通过requests.get()获取数据,代码如下。
strhtml = requests.get(url)
strhtml.encoding = 'utf8' #设置爬取结果编码格式
data = strhtml.text
print(data)
观察打印出来的数据,可发现并不需要前6行,如图所示。
接下来用split方法将文本转变成列表,然后通过一个循环将前6行内容删除。
然后将一大串文本分割出来,这里可以用换行符将每一行文本分开。在Python中,\n表示换行符。
data1 = data.split("\n")
删除数据使用的是remove方法,并且每次都删除第一行(序号为0)数据。因为每次删除第一行数据,所以第二行数据都会变成下次执行的第一行数据,代码如下。
for i in range(6): # 因为前6行没数据,删除前6行
data1.remove(data1[0])
通过前面的接口信息,可以知道只要获取城市/地区编码就可以了。这里从便捷的角度出发,提取每一行的2到12个字符,然后通过一个列表元素循环,将城市编码打印出来。
for item in data1:
print(item[2:13])
完成了城市编码的提取后吗,下一步就是调用接口获取数据,代码如下。
import requests
import time
url = 'https://cdn.heweather.com/china-city-list.txt'
strhtml = requests.get(url)
strhtml.encoding = 'utf8' #设置爬取结果编码格式
data = strhtml.text
# print(data)
data1 = data.split("\n")
# print(data1)
for i in range(6): # 因为前6行没数据,删除前6行
data1.remove(data1[0])
# print(data1)
for item in data1:
url = 'https://free-api.heweather.net/s6/weather/forecast?location='+item[2:13]+'&key=871a107479f049cca8f7d22b031a1c2d'
# print(item[2:13])
strhtml = requests.get(url)
strhtml.encoding = 'utf8'
time.sleep(1)
print(strhtml.text)
数据以JSON的格式返回的,每一个城市/地区都是一个JSON,如图所示。
这段代码调用了time库,这是为了使用sleep(睡眠)函数,也就是延时函数。因为API提供了3181个城市/地区,这个循环就要智行3181次。为了避免访问服务器过于频繁,保证爬虫的稳定性,这里让程序每次访问后等待1秒钟。在写爬虫的时候不管需要访问的次数是多还是少,最好养成写延时的习惯,延时函数代码如下。
time.sleep(1)
如果要将返回的JSON数据解析出来,可以使用for循环。
import requests
import time
url = 'https://cdn.heweather.com/china-city-list.txt'
strhtml = requests.get(url)
strhtml.encoding = 'utf8' #设置爬取结果编码格式
data = strhtml.text
# print(data)
data1 = data.split("\n")
# print(data1)
for i in range(6): # 因为前6行没数据,删除前6行
data1.remove(data1[0])
# print(data1)
for item in data1:
url = 'https://free-api.heweather.net/s6/weather/forecast?location='+item[2:13]+'&key=871a107479f049cca8f7d22b031a1c2d'
# print(item[2:13])
strhtml = requests.get(url)
strhtml.encoding = 'utf8'
time.sleep(1)
# print(strhtml.text)
dic = strhtml.json()
for item in dic["HeWeather6"][0]["daily_forecast"]:
print(item["cond_code_d"])
代码执行结果如下图所示。
接下来使用JSON在线结构化的工具观察数据结构,网址如下。
http://jsonviewer.stack.hu/
在浏览器查看城市id为CN101010100的返回数据。
将上面的返回数据复制、粘贴到左侧的文本框中,然后单击左侧的Viewer就会得到如图所示的结果。通过观察路径,3天的预报数据是在[HeWeather6][0][daily_forecast]下面,由[0]、[1]和[2]这3个数据节点分别存放3天的数据,而每天的最高温度是在[HeWeather6][0][daily_forecast][n][cond_code_d]路径下,其中[n]表示分节点[0]、[1]、[2]。
如果JSON工具报错,则需要检查复制的内容是否存在多了空格或者少了符号之类的问题,这些都是新手常犯的错误。
request库返回的数据可以编码成JSON格式的数据,只有JSON对象才可以适用上面分析的路径,表现方式如下。
strhtml.json()
完成的代码如下。
import requests
import time
url = 'https://cdn.heweather.com/china-city-list.txt'
strhtml = requests.get(url)
strhtml.encoding = 'utf8' #设置爬取结果编码格式
data = strhtml.text
data1 = data.split("\n")
for i in range(6): # 因为前6行没数据,删除前6行
data1.remove(data1[0])
for item in data1:
url = 'https://free-api.heweather.net/s6/weather/forecast?location='+item[2:13]+'&key=871a107479f049cca8f7d22b031a1c2d'
strhtml = requests.get(url)
strhtml.encoding = 'utf8'
time.sleep(1)
print(strhtml.text)
dic = strhtml.json()
print("日期:" + dic["HeWeather6"][0]["daily_forecast"][0]["date"],
"城市:" + dic["HeWeather6"][0]["basic"]["location"],
"国家:" + dic["HeWeather6"][0]["basic"]["cnty"],
"白天温度:" + dic["HeWeather6"][0]["daily_forecast"][0]["cond_code_d"],
"晚间温度:" + dic["HeWeather6"][0]["daily_forecast"][0]["cond_code_n"],
"天气描述:" + dic["HeWeather6"][0]["daily_forecast"][0]["cond_txt_n"],
"最高温度:" + dic["HeWeather6"][0]["daily_forecast"][0]["tmp_max"],
"最低温度:" + dic["HeWeather6"][0]["daily_forecast"][0]["tmp_min"],
"湿度:" + dic["HeWeather6"][0]["daily_forecast"][0]["hum"],
"压强:" + dic["HeWeather6"][0]["daily_forecast"][0]["pres"],
"降水率:" + dic["HeWeather6"][0]["daily_forecast"][0]["pop"]
)
运行结果如下图所示。