概述
國家統計局的公開資料真實性強,宏觀且與我們的生活息息相關,
因此,采集此資料作為資料分析實驗的資料再好不過,
采集程序
采集各種公開資料的第一步就是分析網頁,

上面的圖是國家統計局年度資料的界面, 左邊是資料分類的樹形選單,右邊是每個選單點擊之后顯示的資料,可以設定年份來過濾資料,
采集資料分類樹
根據頁面的情況,首先,我們需要采集樹形選單中的資料,然后再根據選單的分類來依次采集右邊的資料, 這樣可以避免采集的遺漏,
爬蟲采集資料一般有 2 種情況:
- 采集 html 頁面,然后分析其中的結構,提取出資料
- 查看是否存在獲取資料的 API,直接從 API 中提取資料
通過分析網頁的加載程序,發現國際統計局的資料是有 API 的,這就節省了很多時間, API 資訊如下:
host: "https://data.stats.gov.cn/easyquery.htm"
method: POST
params: id=zb&dbcode=hgnd&wdcode=zb&m=getTree
通過 python 的 requests 庫模擬 POST 請求就可以獲取到樹形選單中的資料了,
def init_tree(tree_data_path):
data = https://www.cnblogs.com/wang_yb/archive/2021/04/09/get_tree_data()
with open(tree_data_path,"wb") as f:
pickle.dump(data, f)
def get_tree_data(id="zb"):
r = requests.post(f"{host}?id={id}&dbcode=hgnd&wdcode=zb&m=getTree", verify=False)
logging.debug("access url: %s", r.url)
data = r.json()
for node in data:
if node["isParent"]:
node["children"] = get_tree_data(node["id"])
else:
node["children"] = []
return data
直接呼叫上面的 init_tree 函式即可,樹形選單會以 json 格式序列化到 tree_data_path 中,
序列化的目的是為了后面采集資料時可以反復使用,不用每次都去采集這個樹形選單,(畢竟選單是基本不變的)
根據分類采集資料
有了分類的選單,下一步就是采集具體的資料, 同樣,通過分析網頁,資料也是有 API 的,不用采集 html 頁面再提取資料,
host: "https://data.stats.gov.cn/easyquery.htm"
method: GET
params: 引數有變數,具體參見代碼
采集資料稍微復雜一些,不像采集樹形選單那樣訪問一次 API 即可,而是遍歷樹形選單,根據選單的資訊訪問 API,
# -*- coding: utf-8 -*-
import logging
import os
import pickle
import time
import pandas as pd
import requests
host = "https://data.stats.gov.cn/easyquery.htm"
tree_data_path = "./tree.data"
data_dir = "./data"
def data(sj="1978-"):
tree_data = https://www.cnblogs.com/wang_yb/archive/2021/04/09/[]
with open(tree_data_path,"rb") as f:
tree_data = https://www.cnblogs.com/wang_yb/archive/2021/04/09/pickle.load(f)
traverse_tree_data(tree_data, sj)
def traverse_tree_data(nodes, sj):
for node in nodes:
# 葉子節點上獲取資料
if node["isParent"]:
traverse_tree_data(node["children"], sj)
else:
write_csv(node["id"], sj)
def write_csv(nodeId, sj):
fp = os.path.join(data_dir, nodeId + ".csv")
# 檔案是否存在, 如果存在, 不爬取
if os.path.exists(fp):
logging.info("檔案已存在: %s", fp)
return
statData = https://www.cnblogs.com/wang_yb/archive/2021/04/09/get_stat_data(sj, nodeId)
if statData is None:
logging.error("NOT FOUND data for %s", nodeId)
return
# csv 資料
csvData = https://www.cnblogs.com/wang_yb/archive/2021/04/09/{"zb": [], "value": [], "sj": [], "zbCN": [], "sjCN": []}
for node in statData["datanodes"]:
csvData["value"].append(node["data"]["data"])
for wd in node["wds"]:
csvData[wd["wdcode"]].append(wd["valuecode"])
# 指標編碼含義
zbDict = {}
sjDict = {}
for node in statData["wdnodes"]:
if node["wdcode"] == "zb":
for zbNode in node["nodes"]:
zbDict[zbNode["code"]] = {
"name": zbNode["name"],
"cname": zbNode["cname"],
"unit": zbNode["unit"],
}
if node["wdcode"] == "sj":
for sjNode in node["nodes"]:
sjDict[sjNode["code"]] = {
"name": sjNode["name"],
"cname": sjNode["cname"],
"unit": sjNode["unit"],
}
# csv 資料中加入 zbCN 和 sjCN
for zb in csvData["zb"]:
zbCN = (
zbDict[zb]["cname"]
if zbDict[zb]["unit"] == ""
else zbDict[zb]["cname"] + "(" + zbDict[zb]["unit"] + ")"
)
csvData["zbCN"].append(zbCN)
for sj in csvData["sj"]:
csvData["sjCN"].append(sjDict[sj]["cname"])
# write csv file
df = pd.DataFrame(
csvData,
columns=["sj", "sjCN", "zb", "zbCN", "value"],
)
df.to_csv(fp, index=False)
def get_stat_data(sj, zb):
payload = {
"dbcode": "hgnd",
"rowcode": "zb",
"m": "QueryData",
"colcode": "sj",
"wds": "[]",
"dfwds": '[{"wdcode":"zb","valuecode":"'
+ zb
+ '"},{"wdcode":"sj","valuecode":"'
+ sj
+ '"}]',
}
r = requests.get(host, params=payload, verify=False)
logging.debug("access url: %s", r.url)
time.sleep(2)
logging.debug(r.text)
resp = r.json()
if resp["returncode"] == 200:
return resp["returndata"]
else:
logging.error("error: %s", resp)
return None
代碼說明:
- tree_data_path = "./tree.data" : 這個是第一步序列化出的樹形選單資料
- 采集的資料按照樹形選單中的每個選單的編號生成相應的 csv
- 樹形選單的每個葉子節點才有資料,非葉子節點不用采集
- 呼叫 data 函式來采集資料,默認是從 1978 年的資料開始采集的
采集結果
本次采集的結果有 1917 個不同種類的資料,
下載地址: https://databook.top/data/de9d8cc6-2bab-4ef1-b09f-8dcf83c32648/detail
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/274350.html
標籤:其他
