仅用不到20行代码爬取 空气质量指数月统计历史数据爬取
效果
目录
空气质量历史数据官网,戳它直达!
前言自雾霾深度调查纪录片《柴静雾霾调查:穹顶之下》的出现后,有关环境问题的各种报道不断涌出,也使得各个学科领域针对环境问题发表诸多文献,如计量经济学中的对某某市的空气质量影响因素的计量经济学分析等等。
但在这其中,有关数据的获取永远是报道、分析的第一步!
下面,就让我们手把手from scratch地爬虫收集齐全国384个地区城市的空气质量指数月统计历史数据
I Package 安装与使用安装:
!pip install lxml -i https://pypi.douban.com/simple
!pip install selenium -i https://pypi.douban.com/simple
!pip install urllib # 这里没加国内镜像是因为没有urllib
使用:(如果你的环境还缺少下述包,请按上述方式进行pip)
import re
import time
import pandas as pd
import requests
from urllib import parse
from selenium import webdriver
除了在环境中安装上述包,只需再下载一个phantomjs,根据你的Windows、Mac、Linux等选对应系统的一路安装,记住最终的安装地址即可。
II Citys 获取网站内的城市名在此,给大家讲一种更简单上手的爬取网站内容的方法,requests + re:
通过requsets获取网页内容
通过re正则抽取信息
2.1 Requset 获取内容
首先获取网页信息,如下图
url = "https://www.aqistudy.cn/historydata/"
url_text = requests.get(url).text
此时,我们已经得到了这个url网页链接内的内容,如上图,可以发现,其中有很多类似的
“<a href=“monthdata.php?city=阿坝州”>阿坝州\r\n”
而这其中的”阿坝州“就是我们想要的城市名称,那我们该怎么在这么复杂繁多的内容中提取出我们想要的信息,“阿坝州”呢?
2.2 Re 抽取信息
pattern = re.compile(r'<a href="monthdata.php\?city=\w+">(\w+)</a>\r\n') # 要在?前加\转义符
citys = pattern.findall(url_text) # 获取384个城市名
print("已获取{}个城市名,第一个城市是{},最后一个城市是{}".format(len(citys),citys[0],citys[-1]))
接下来,我们便可以针对上述例句 “<a href=“monthdata.php?city=阿坝州”>阿坝州\r\n” 进行正则表达式的提取匹配,在此,你只需将例句复制,再把想要的部分换成(\w+)即可,如上述代码的pattern。
使用正则表达式后,我们便可获取所有的城市名称。
2.3 url 需爬取的城市网站链接
获得所有城市名称后,也就获得了需要爬去网站的url网站链接:
你问我怎么知道的,我会告诉你,你多手戳几个城市,看浏览器上面的url就知道目标url的规律了
# 如北京,只需要在base_url + '北京'即可
base_url = 'https://www.aqistudy.cn/historydata/monthdata.php?city='
# 即北京:
beijing_url = base_url + '北京'
请注意,上述代码可行吗?对于人类可行的,不信你试试访问这个链接:
https://www.aqistudy.cn/historydata/monthdata.php?city=北京
但是对于程序而言,它并不能识别中文字符,需要将中文字符转成URL字符:
# from urllib import parse
# 第一步已经导入包了 urllib中的parse可以做到将中文字符转成URL字符:
beijing_url = base_url + parse.quote('北京')
有了目标网页url网页链接,我们可以爬取网站表格数据了
III Webdriver 爬取网站表格数据‘配置你刚刚下载的phantomjs的地址
driver = webdriver.PhantomJS(r'E:\\Tools\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')
在配置好phantomjs后,driver.get(city_url) 获取网页,再只需一步 driver.page_source 即可获取网页内的数据,此时的数据会是一个列表,取[0]即可获取所需DataFrame的内容。
for i,city in enumerate(citys):
city_url = base_url + parse.quote(city) # 城市url网页链接
driver.get(city_url) # 读取网页
time.sleep(2)
dataframe = pd.read_html(driver.page_source)[0] # 读取dataframe
time.sleep(1)
# 改成你需要保存数据的地址
dataframe.to_csv(r'E:\\Data\\%s.csv'% (str(city)),mode='a+',encoding='utf_8_sig')
print("第{}个城市:{} 已收集完".format(i+1,city))
driver.quit()
print('已收集完!')
注意,这里的time.sleep要根据你的网络加载时间延长,笔者第一次使用时只设置了1s,导致最终很多的CSV表格数据都是1KB,没有加载下来。
至此,所有有关数据都被加载成csv保存在你设置的地址中了,不过你会发现有几个城市的csv文件只有1KB,没错,因为那几个城市网站上没有数据,只有图表。
IV 完整代码import re
import time
import pandas as pd
import requests
from urllib import parse
from selenium import webdriver
url = "https://www.aqistudy.cn/historydata/"
url_text = requests.get(url).text
pattern = re.compile(r'<a href="monthdata.php\?city=\w+">(\w+)</a>\r\n') # 要在?前加\转义符
citys = pattern.findall(url_text) # 获取384个城市名
print("已获取{}个城市名,第一个城市是{},最后一个城市是{}".format(len(citys),citys[0],citys[-1]))
base_url = 'https://www.aqistudy.cn/historydata/monthdata.php?city='
driver = webdriver.PhantomJS(r'E:\\Tools\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')
for i,city in enumerate(citys):
city_url = base_url + parse.quote(city)
driver.get(city_url)
time.sleep(2)
dataframe = pd.read_html(driver.page_source)[0]
time.sleep(1)
dataframe.to_csv(r'E:\\Data\\%s.csv'% (str(city)),mode='a+',encoding='utf_8_sig')
print("第{}个城市:{} 已收集完".format(i+1,city))
driver.quit()
print('已收集完!')
如果你足够优秀(懒),可以直接通过笔者上传的资源下载这份数据,如果没有C币可戳我,我免费送给你数据。注:这份数据是我经过人工筛查,并把本身网页没有数据的做出标注0。
ps:你可能会问为什么不用scrapy,因为用scrapy还要新建项目写好几个py文件,就实用性而言,这种方法更投机取巧,但还是劝大家还是多学学scrapy才能更列害。而且已经有类似的博客讲scrapy的实现了,但还没有笔者这么短的…