跳到主内容

别再死磕接口了:国家统计局开放数据到底怎么采?我实测 403 后换了一条路

结论先说:国家统计局的开放数据能采,但你大概率不该从 data.stats.gov.cn 的 easyquery 接口入手——我实测那条路被 WAF 按 URL 级 ACL 挡了(返回 403,正文写着 reason:UrlACL),连完整浏览器头都没用。真正好用的是主站 www.stats.gov.cn 的发布页:2026-10-16 刚挂出来的《2025 年全国科技经费投入统计公报》,我用几行 Python 就把全文攒下来了,10,587 字符。

起因:为什么要做这件事

起因很土:我要一份「R&D 经费投入」的分省数据做横向对比,百度了半天全是二手转述,数字对不上。既然最权威的口径在国家统计局,那就直接去源头拿。

动手前我给自己定了两条规矩。一是引用必须能回溯——写清发布机关、发布日期、原文链接,别人点回去能看到同一个数字。二是口径要说透,站内那条「务必写明数据来源,并说明用的是相对变化而非绝对规模」说的就是这个,我在好几篇分析里都吃过没写口径的亏。

过程:具体怎么做的

第一站就是 data.stats.gov.cn,也就是大家常说的「国家数据」。它的 easyquery.htm 是页面背后那个 JSON 接口,官方没有对外文档,靠 dbcode(数据库)、rowcode/colcode(行列维度)、dfwds(过滤条件,指标 valuecode 填这儿)这几个参数组起来请求。

参数拼好发出去,403。

踩坑:哪里翻车了

第一个念头是请求头不够像浏览器。补了一套完整的:UA、Accept、Accept-Language、Referer 指向 easyquery 页面、X-Requested-With、Origin、Sec-Fetch-* 全上。还是 403。

换 http 试试,403。改用 curl 那种极简 UA,403。

关键在返回的 291 字节正文里:

403 Forbidden
Client IP: 111.58.76.3
eventID: 1249-1792197700.011-w-waf05fzm
reason: UrlACL

reason:UrlACL 这六个字把事情说清楚了:不是反爬头校验,是 WAF 上挂了一条 URL 级的访问控制规则,路径被整条封了,请求头做得再像浏览器也没人看。同一时间我测了同一域名下的 index.htm、advancequery.htm,返回的是 404 而不是 403——说明请求确实发出去了,只是被挡在特定路径上。

网上不少教程写「加上完整浏览器头就能通」,至少在我这条线路、这个时间点上不成立。下次再看到这类说法,先自己发一次请求验一遍。

解法:怎么爬出来的

换入口。同一个机构的主站 www.stats.gov.cn 是完全可达的,我实测四个入口,结果分别是:

  • https://data.stats.gov.cn/ 首页:200
  • https://data.stats.gov.cn/easyquery.htm:403(UrlACL)
  • https://www.stats.gov.cn/:200,140,940 字节
  • https://www.stats.gov.cn/sj/zxfb/:200,66,363 字节,页面里 57 个 html 链接

所以真正可行的做法是「列表页 → 详情页 → 抽结构化文本」三步,全是静态 HTML,python 标准库就够:

  1. 列表页解析:/sj/zxfb/ 里每个条目是 ./YYYYMM/tYYYYMMDD_XXXXXXX.html 这种相对路径,用 urllib 取回来,正则 href="([^"]+\.html)" 一把全提。
  2. 详情页正文:取回来先剥 <script> 和 <style>,再把标签替换成空格,最后把连续空白折叠成一个,得到干净文本。
  3. 抽数字句:按句号切句,保留同时含数字和单位(亿元 | 万人 | % | 元/人)的句子。这一步过滤完,56,267 字符的年度统计公报只剩十几行有用的。

这里有个取舍要讲清楚:发布页给的是「公报文本」,不是「结构化数据表」。想做长序列分析,它不如接口省事;但好处是零门槛、有原文链接、口径写在句子里。数据集要带保质期这条经验在这儿同样成立——我从列表页同时拿到发布日期,天然就是这串数字的「生产日期」。

验证:拿什么数据证明有效

真拿到了。下面是直接从官方发布页抽出来的原始句子里的数字,发布时间标在后面。

《2025 年全国科技经费投入统计公报》(2026-10-16 发布):全国 R&D 经费 39,288.2 亿元,比上年增加 2,961.3 亿元、增长 8.2%;投入强度 2.80%,提高 0.11 个百分点。分活动类型:基础研究 2,834.6 亿元(+13.3%)、应用研究 4,441.6 亿元(+3.2%)、试验发展 32,012.0 亿元(+8.4%)。基础研究占比 7.21%,应用研究和试验发展占 11.3%、81.5%。

《2025 年国民经济和社会发展统计公报》(2026-02-28 发布):全年国内生产总值 1,401,879 亿元(原文标注「初步核算」),比上年增长 5.0%;人均 GDP 99,665 元;年末全国人口 140,489 万人。

顺手做了一次交叉验证,结果挺有意思。分省 R&D 经费超两千亿元的六个:广东 5,510.4、江苏 4,948.2、北京 3,696.1、浙江 3,177.2、山东 2,825.7、上海 2,580.5 亿元。但投入强度排第一的是北京 7.10%,上海 4.55%、广东才 3.78%。

经费最多的广东,强度排在第三;经费第三的北京,强度是广东的近两倍。只看总额不看强度,或者只看强度不看总额,都会得出相反的结论——这种两组数打架的地方,恰恰是二手文章最容易出错的地方,也跟别信二手数字、回原文自核是同一个道理。

最后提醒三点。采集要控频,同域名限速下总耗时是线性的这是刻意的礼貌取舍,别把间隔调到 0。用途方面,只写方法与示例、不做数据二次分发,引用时写清「国家统计局 + 发布日期 + 原文链接」,数值一律以官方最新公布为准。涉及商业用途的,走正规授权通道,别把「能抓下来」当成「可以随便用」。

常见问题

easyquery 那个接口到底还能不能用?

我这边不能。2026-10-17 实测返回 403 且正文写着 reason:UrlACL,加完整浏览器头、换 http、换 UA 全都不行——这是 WAF 的路径级规则,不是头校验。如果你在项目估算里押了这条路,先发一次请求自测。

那 https://www.stats.gov.cn 上都有什么?

两个最有价值的入口:/sj/zxfb/ 是数据发布(按时间倒序,含各类统计公报),/sj/tjgb/ndtjgb/ 是年度统计公报。都是静态 HTML,标准库直接 GET 就行。

抽出来的文本为什么数字前后有空格?

因为去标签时把标签替换成了空格,句号和不换行空格也会混进来。正则抽句之后按非数字字符清理一遍即可,别急着 replace(" ") 全删,那样会把「39,288.2 亿元」粘成一团。

想做几十年的长序列怎么办?

发布页适合拿最新口径和年度公报,不适合做几十期的时间序列——没有固定的表结构,每年措辞都可能变。要长序列就去换一个明确结构化的数据源,别硬从 HTML 里抠。

引用的时候最低限度要写什么?

三条:发布机关(国家统计局)、发布日期、原文链接。再补一句口径,比如「2025 年 GDP 为初步核算数」。只写数字不写这三项,三个月后你自己都对不上。

相关阅读

分享到:

本文链接:https://www.biyeyuanma.cn/post/340.html

服务热线

加我微信

加我微信