结论先说:国家统计局的开放数据能采,但你大概率不该从 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/首页:200https://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 标准库就够:
- 列表页解析:
/sj/zxfb/里每个条目是./YYYYMM/tYYYYMMDD_XXXXXXX.html这种相对路径,用urllib取回来,正则href="([^"]+\.html)"一把全提。 - 详情页正文:取回来先剥
<script>和<style>,再把标签替换成空格,最后把连续空白折叠成一个,得到干净文本。 - 抽数字句:按句号切句,保留同时含数字和单位(
亿元 | 万人 | % | 元/人)的句子。这一步过滤完,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 为初步核算数」。只写数字不写这三项,三个月后你自己都对不上。

