乐于分享
好东西不私藏

从官网批量下载全部国家法律法规

从官网批量下载全部国家法律法规

 AI  1 天时间,批量下载了全部国家法律法规,踩了 10 个坑后终于搞定

一次用 AI 做自动化爬虫的真实记录——从想法到完成,全程靠 AI 写代码,失败了 N 次,最终成功了。

起因:一个简单的需求

把国家法律法规数据库(flk.npc.gov.cn)里的法律法规 Word 文件全部下载下来,同时整理一份索引表格,方便后续导入单位数据库。

网站上有将近 3 万条记录,分 294 页,每页 100 条。如果手动点,按每页 2 分钟算,要连续点 10 小时,还不算中途可能出错。

所以:让 AI 来写自动化脚本干这个活。 AI 平台:WorkBuddy

下面把整个过程,特别是踩坑经历,原原本本写出来,希望对有类似需求的人有帮助。

 1 个坑:想走捷径,直接调 API,失败了

一开始,让 AI 帮分析网站的网络请求,想直接找后端 API 接口,绕过浏览器,直接把数据抓下来。理论上这样最快,不需要模拟点击,直接请求数据。但失败了。

原因是:

网站有会话验证,批量下载和批量导出的按鈕,必须通过浏览器点击才能触发,后端不接受直接的接口调用。用 curl  fetch 发请求,服务器要么返回空,要么直接拒绝。

教训:

用验证码防爬的网站,想绕过浏览器直接调 API,大概率行不通。踏踏实实用浏览器自动化。

 2 个坑:浏览器自动化,以为可以静默运行,又失败了

换成浏览器自动化(Playwright),默认用的是 headless 模式——就是浏览器在后台跑,不弹出窗口。

脚本运行起来了,也点击了下载按鈕,日志显示下载成功,但是输出目录里没有任何文件。

没有报错,没有提示,就是没有文件。这种静默失败最难排查。

原因是:

这个网站有浏览器环境检测,headless 模式下被识别为机器人,下载请求虽然发出去了,但服务器不响应,或者下载行为被拦截。

解决方法:

强制用有界面模式(headless: false),让真实的 Chrome 窗口弹出来,模拟真人操作。这个坑浪费了将近半天时间。

 3 个坑:脚本一旦崩溃,就得从头来

换成有界面模式后,终于开始真正下载了。但是网站不稳定,隔一会儿就出现请求错误页面,脚本遇到错误就停了,下载到一半断掉,要重新开始。

这个问题的解决思路是加断点续传:每下完一页,就把进度写入一个 JSON 文件。下次启动,直接从上次中断的地方继续,不用从第 1 页重新来。

{

“currentPage”: 85,

“totalPages”: 294,

“completed”: [1, 2, 3, …, 84],

“errors”: []

}

有了这个,哪怕脚本崩 100 次,总进度不会丢。

 4 个坑(最危险):守护进程 + 异常处理写错了,Chrome 开了 N 个,系统死机

为了让脚本崩溃后自动重启,加了一个守护进程,专门监视下载脚本,崩了就重启。但是代码里有一个致命错误:

// 这段代码差点让电脑死机

process.on(‘uncaughtException’, (err) => {

console.error(‘出错了:’, err);

main(); // ← 问题在这里!

});

每次出现未捕获的异常,代码里会再调用一次 main(),而 main() 会启动一个新的 Chrome 浏览器。如果异常频繁触发,Chrome 进程就会指数级增加:1→2→4→8……

当时看着任务管理器里 Chrome 的进程数量从十几个涨到几十个,内存从 8G 涨到满载,最后系统直接假死。

正确的写法:

process.on(‘uncaughtException’, (err) => {

console.error(‘出错了:’, err);

process.exit(1); // 直接退出,让外部守护进程负责重启

});

自己永远不要重启自己。守护进程和业务进程要分开,守护进程管重启,业务进程管干活

 5 个坑:后台运行时守护进程莫名消失

修好了 Chrome 倍增的问题,把守护进程放到后台跑,结果过一段时间发现进程没了,日志里也没有报错。

原因:

当守护进程监听子进程(下载器)的输出,并把这些输出转发到自己的标准输出时,如果终端窗口关闭,输出通道(pipe)断裂,任何写操作都会触发一个 EPIPE 错误,Node.js 的默认行为是崩溃退出。

触解决方法:

子进程的输出不要转发给父进程,直接写到日志文件里:

// 不这样做

child.stdout.pipe(process.stdout);

// 这样做

child.stdout.on(‘data’, (data) => {

fs.appendFileSync(‘child_output.log’, data);

});

这个 bug 很难发现,因为没有任何报错,程序就是静默消失了。

 6 个坑:下载的文件互相覆盖

等以为大功告成,检查输出目录,发现只有一个《批量下载文件.zip》,300 多页全都下载成了同一个文件名,只剩最后一页的内容。

原因:

网站每次下载都用相同的文件名,浏览器会直接覆盖同名文件。

触解决方法:

在下载事件里,给每个文件加上页码前缀:

page001_批量下载文件.zip

page002_批量下载文件.zip

page003_批量下载文件.zip

这样不仅不会覆盖,还能一眼看出哪页对应哪个文件,排查漏页非常方便。

 7 个坑:文件名包含非法字符,解压失败

下载全部完成后,开始解压 ZIP 文件,结果有 13 个文件报错:Errno 22: Invalid argument

原因:

一些法律法规的名称里包含 < 符号,这两个字符在 Windows 文件系统里是非法字符,无法创建同名文件。

触解决方法:

解压时对文件名做一次清理,把非法字符替换为全角字符:

name = name.replace(‘<‘, ‘‘).replace(‘>’, ‘‘)

name = name.replace(‘:’, ‘‘).replace(‘”‘, ‘″’)

全角字符看起来一样,但在文件系统里是完全合法的,完美解决。

 8 个坑:XLSX 文件被 Python 损坏,无法读取

下载下来的 .xlsx 文件,用常见的Python  openpyxl 读取,报错:File is not a zip file(文件不是 zip 格式)。

这个错误很迷惑——明明扩展名是 .xlsx,为什么说不是 zip

原因:

现代的 .xlsx 格式本质上是 ZIP 压缩包,但这个网站导出的 .xlsx,实际上是老版 Excel 格式(.xls),只是套了一个 .xlsx 的扩展名。两种格式底层完全不同,openpyxl 只支持新格式,所以报错。

触解决方法:

改用 xlrd 库来读取(xlrd 支持老版 xls 格式),再用 openpyxl 写出新格式的 xlsx

读取(用 xlrd 处理 OLE2/xls 格式)

import xlrd

wb = xlrd.open_workbook(‘page001_xxx.xlsx’)

写出(用 openpyxl 生成新格式)

from openpyxl import Workbook

new_wb = Workbook()

经验:

不要相信文件扩展名,处理来自网站的文件时,最好先检查一下文件实际格式。

 9 个坑:Ctrl+C 停不掉后台进程

Windows 后台运行的隐藏进程,按Ctrl+C 完全没用,而直接 kill 进程又担心丢失当前的下载进度。

触解决方法:

实现一个文件信号机制——在输出目录里创建一个名为 .stop 的空文件:

New-Item -Path “D:\workbuddy\law20260430\.stop” -ItemType File -Force

守护进程和下载器每秒检查这个文件是否存在,存在就优雅退出:先保存当前进度,关闭浏览器,然后退出。进度不会丢。

 10 个坑:Python 不在系统 PATH 

自动后处理需要调用 Python,但是Windows  Python 安装路径没加入 PATH,直接调用 python 命令失败。

触解决方法:

用完整路径,并支持环境变量配置:

const pythonCmd = process.env.PYTHON_PATH

|| ‘C:\\Users\\admin\\AppData\\Local\\Programs\\Python\\Python313\\python.exe’;

最终成果

踩完这 10 个坑,经过十几个版本的迭代,最终的自动化程序稳定跑完了全部 294 页:

指标

数值

法律法规总数

29,317 

下载 Word 文件数

28,854 

合并索引(去重后)

29,033 

发现并去除重复

302 

整个下载过程完全无人値守,自动重启、自动断点续传、完成后自动解压合并。

最终架构(简化版)

整个系统分三层:

守护进程

└── 负责:监视 + 崩溃自动重启

下载器

└── 负责:控制浏览器逐页下载

每页:全选 → 下载zip → 导出 xlsx →翻页

每页保存一次进度(断点续传)

后处理脚本

└── 下载全部完成后自动觥发

├── 解压所有 zip → law/ 目录

└── 合并所有 xlsx → law_index.xlsx(去重)

给有类似需求的人几点建议

有些网站,需要点击才能触发的下载,不要想着调 API,直接用浏览器自动化

headless 模式不是万能的,遇到下载失败先试试有界面模式

守护进程和业务进程分离,异常处理里不要自己重启自己

每个关键步骤完成后立即保存进度,断点续传是长时间任务的标配

文件命名加上序号/页码,排查问题方便十倍

处理来自网站的文件,不要相信扩展名,不要假设文件名合法

 Windows 上做后台任务,Ctrl+C 不可靠,要设计专门的停止机制

结语

这次项目最大的感受是:AI 写代码确实快,但排查 bug 还是需要人理解逻辑。每一个坑,AI 都能给出解决方案,AI 是个非常能干的执行者,但发现问题在哪这件事,人机协作效果最好。

整个项目从提需求到最终完成,8小时。

代码已整理为可复用的自动化技能skill,下次直接套用。

skill 和所有法律文件(截止2026-04-30)下载链接:

https://pan.baidu.com/s/1dMPLaHaJYkn5qLwQGr0aTw?pwd=love