采集的文章内容不能直接发布(2022全球C++及系统软件技术大会|API信息如下(图))

优采云 发布时间: 2022-03-02 23:15

  采集的文章内容不能直接发布(2022全球C++及系统软件技术大会|API信息如下(图))

  2022全球C++与系统软件技术大会| 3月11-12日上海点击查看详情>>>

  

  概述

  国家统计局的公开数据具有高度真实性、宏观性,与我们的生活息息相关。

  因此,采集这个数据作为数据分析实验的数据再好不过了。

  采集进程

  采集各种公开可用数据的第一步是分析网页。

  

  上图是国家统计局年度数据界面。左边是数据分类的树形菜单,右边是每个菜单点击后显示的数据。您可以设置年份来过滤数据。

  采集数据分类树

  根据页面的情况,首先我们需要采集树形菜单的数据,然后根据菜单的分类,依次是采集右边的数据. 这避免了 采集 的遗漏。

  爬虫采集数据一般有两种情况:

  通过分析网页的加载过程,发现国际统计局的数据有一个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 = 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 = []

with open(tree_data_path, "rb") as f:

tree_data = 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 = get_stat_data(sj, nodeId)

if statData is None:

logging.error("NOT FOUND data for %s", nodeId)

return

# csv 数据

csvData = {"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树形菜单。只有叶子节点有数据,非叶子节点不需要调用数据函数采集到采集数据,默认是采集从1978年的数据开始的结果采集

  这个 采集 的结果有 1917 种不同类型的数据。

  下载链接:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线