本次实验以爬取“国家统计局”首页中的【上海市城乡居民收支基本情况】为例,国家统计局(https://data.stats.gov.cn/index.htm)其他页面的爬取方法大同小异
1.爬虫基本流程发起请求:通过http/https库向目标站点发起请求,即发送一个request,请求可以包含额外的headers等信息,等待服务器响应
获取相应内容:如果服务器能正常响应,会得到一个response,response的内容便是所要获取的页面内容,类型可能有HTML,json字符串,二进制数据(如图片视频)等类型
解析内容:得到的内容可能是HTML,可以用正则表达式,网页解析库进行解析,可能是json,可以直接转为json对象,可能是二进制数据,可以做保存或者进一步的处理
(本次实验得到的解析内容是json)
保存数据:可以存为文本,也可以保存至数据库,或者特定格式的文件
2.打开网页并分析国家统计局的网站很奇怪,明明是https却会告警不安全,首次打开界面如下(本人使用的是谷歌浏览器)
点击“高级”-“继续前往”,方可进入首页
选择“季度数据”-“分省季度数据”
选择“人民生活”-“城乡收支情况”
地区修改为“上海市”
按下F12,进入浏览器调试模式
刷新重新获取网页信息,找到easyquery.htm?m=Query Data&dbc...的文件。可以先选中"XHR"过滤条件,缩小查找范围
怎么确认这个文件就包含有我们要找的数据呢?点击“response”板块,向右拖动滑块可以看到表格数据可以一一对应(但数据并没有连续出现)
注意:这里的data和strdata看上去一样,但实际格式不一样,data是int或double格式,strdata是str格式,这个表格有一些空数据行,字符串格式方便做判断,字符串转数字使用eval()即可
3.完整代码及解析注:缺少的库可以在命令行使用pip命令安装,如缺少requests库,可以在命令行输入命令
pip install requests
import urllib3 \# 使用urllib3.disable_warnings()在关闭SSL认证(verify=False)情况下 \# 将requests请求禁用安全请求警告 import requests # 使用Requests发送网络请求 import time # 用来获取时间戳(计算当前时间,用于网页验证) import json # 处理json文件 import numpy as np # 处理数组 import pandas as pd # np.array()转换成pd.DataFrame格式,再使用to_excel()写入excel表格 \# 获取毫秒级时间戳,用于网页验证 def getTime(): return int(round(time.time() * 1000)) \# 数据预处理,获取json列表中层层包裹的strdata元素(数据) def getList(length): List=[] for i in range(length): temp = js[\'returndata\'][\'datanodes\'][i][\'data\'][\'strdata\'] \# 城乡居民收支列表中,原网站有同比增长数据为空,若直接使用eval()会报错,需要先判断 if(len(temp)!=0): \# eval()数字转字符串 List.append(eval(temp)) return List if __name__ == \'__main__\': \# 请求目标网址(链接?前面的东西) url=\'https://data.stats.gov.cn/easyquery.htm\' \# 请求头,User-Agent: 用来证明你是浏览器,满足一定格式即可,不一定和自己的浏览器一样 headers={\'User-Agent\':\'Mozilla/5.0(Windows;U;Windows NT6.1;en-US;rv:1.9.1.6) Geko/20091201 Firefox/3.5.6\'}#浏览器代理 \# 构造参数键值对,具体数值从网页结构参数中获取 key={} key[\'m\']=\'QueryData\' key[\'dbcode\']=\'fsjd\' key[\'rowcode\']=\'zb\' key[\'colcode\']=\'sj\' key[\'wds\']=\'[{"wdcode":"reg","valuecode":"310000"}]\' key[\'k1\']=str(getTime()) \# "wdcode":"reg" 地区栏 \# 上海 310000 key[\'dfwds\']=\'[{"wdcode":"zb","valuecode":"A0300"},{"wdcode":"sj","valuecode":"LAST6"}]\' \# "wdcode":"zb" 选取左侧哪个条目,"wdcode":"sj"选项框中选取"最近6季度" \# 禁用安全请求警告 requests.packages.urllib3.disable_warnings() \# 发出请求,使用post方法,这里使用前面自定义的头部和参数 \# !!!verify=False,国家统计局20年下半年改用https协议,若不加该代码无法通过SSL验证 r = requests.post(url, headers=headers, params=key,verify=False) \# 使用json库中loads函数,将r.text字符串解析成dict字典格式存储于js中 js = json.loads(r.text) \# 得到所需数据的一维数组,利用np.array().reshape()整理为二维数组 length=len(js[\'returndata\'][\'datanodes\']) res=getList(length) \# 总数据划分成6行的格式 array=np.array(res).reshape(len(res)//6,6) \# np.array()转换成pd.DataFrame格式,后续可使用to_excel()直接写入excel表格 df_shanghai=pd.DataFrame(array) df_shanghai.columns=[\'2020年第三季度\',\'2020年第二季度\',\'2020年第一季度\',\'2019年第四季度\', \'2019年第三季度\',\'2019年第二季度\'] df_shanghai.index=[\'居民人均可支配收入累计值(元)\', \'城镇居民人均可支配收入累计值(元)\', \'农村居民人均可支配收入累计值(元)\', \'居民人均消费支出累计值(元)\', \'城镇居民人均消费支出累计值(元)\', \'农村居民人均消费支出累计值(元)\'] print(df_shanghai)