本次實驗以爬取“國家統計局”首頁中的【上海市城鄉居民收支基本情況】為例,國家統計局(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)
4.部分代碼說明
數據提取
得到表格中的數據需要先分析提取到的js文件,打印內容如下:
將五層列表層層剝開,得到需要的strdata
請求網站
請求目標網址(''?''前面的東西)
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())
key['dfwds']='[{"wdcode":"zb","valuecode":"A0300"},{"wdcode":"sj","valuecode":"LAST6"}]'
部分參數可以從下圖所示位置查看到,有些不顯示的為默認,如果需要顯示相同頁面,需選取選項框中的相應選項
5.數據保存到excel表格
爬蟲爬到的數據現以panda.dataframe格式存儲,可以利用to_excel()函數,直接保存在excel表格中
# write對象為該Excel工作簿,使用該方法保存多個工作表
write = pd.ExcelWriter('F:/Ivory_Tower/norm/分省季度數據_城鄉居民收支.xls') #該路徑自己設置即可,沒有該文件的話會自行創建一個,存在的話寫入會覆蓋原內容
df_shanghai.to_excel(write,sheet_name='上海')
#如果爬多個省份的數據,可以寫入多個工作表,且必須要加上save()保存
write.save()
6.表格優化(可選)
可以借助python代碼,優化表格格式,如上圖所示的結果不盡人意,至少還需要自動調整列寬。
這里本人采用xlwings庫,需要先在命令行下載相應的庫
pip install xlwings
pip install pywin32
# 使用xlwings庫,利用python編輯整理Excel表格
import xlwings as xw
if __name__ == '__main__':
app=xw.App(visible=False,add_book=False) #過程不可見,不添加新工作表
wb=app.books.open(r'F:/Ivory_Tower/norm/分省季度數據_城鄉居民收支.xls')
# wb就是新建的工作簿(workbook)
# 對8個工作表,分別進行操作
for i in range(8):
rng=wb.sheets[i].range('A1:H20') # 選中這些單元格
rng.api.HorizontalAlignment = -4108 # 文字水平方向居中
rng.autofit() # 自動調整行高列寬
wb.save()
wb.close()
app.quit()
運行代碼,即可得到以下效果 (后續多爬了其他一些省份,在key處修改相應參數即可)
7.參考資料
史上超詳細python爬取國家統計局數據:https://blog.csdn.net/qq_41988893/article/details/103017854
如果報其他各種各樣莫名其妙的錯,可以評論或私信詢問哦~