简介:本资源是一款面向法学研究者、法律数据分析人员及Python初学者的裁判文书网自动化采集工具,解决公开司法数据获取难、人工下载效率低、验证码阻碍批量抓取等核心痛点。系统基于Python3开发,集成分类检索、DocID精准查询、时间范围过滤、法院地域切割及图形验证码自动识别功能,支持按年份、案由、法院层级与行政区划定向采集文书,显著提升法律实证研究的数据准备效率。压缩包共22个文件(79KB),含2个核心爬虫脚本(.py)、2个前端交互逻辑(.js)、11张验证码训练样本(.jpg)、README说明文档(.md)、需求清单(.txt)及附赠法律分析模板(.docx),结构清晰,即装即用。目前已有118人学习下载,提供完整可运行代码、典型文书下载示例、验证码识别训练素材及详细使用指引,助力用户快速开展区域司法差异分析、类案检索或判决趋势建模。
1. 为什么我会做一个“裁判文书网采集分析系统”
先说背景。我做法律相关的数据分析,经常需要把裁判文书网上的公开文书批量整理成结构化数据。以前靠手工一篇篇下载,再复制粘贴到表格里,几百篇之后基本就要崩溃——文书页面上有大量噪音信息,标题、案号、当事人、法院、时间、正文混在一起,复制下来还要自己做清洗。后来发现同事在用Python3写爬虫,把下载、解析、入库一次搞定,我才动了手搓一个完整系统的念头。
这个项目标题很长,但拆开看就几个核心点:基于Python3的爬虫工具、支持分类检索DocID查询、文书下载、验证码识别、时间条件过滤、法院地域切割,最后落到用于法律研究和数据分析。整套系统其实就是一个“垂直领域的数据采集与分析流水线”。对做法律研究、社会学分析、舆情分析的人来说,这类工具能把最耗时间的“找数据、洗数据”环节自动化,腾出精力去做真正有价值的研判和建模。
这套系统解决的不只是“下载文书”这一个动作,而是把采集、清洗、检索、切片分析串成了一条线。DocID相当于每篇文书的身份证,有了它就能做精确去重、增量更新;时间过滤和法院地域切割则是为后续统计分析预设好的数据切片维度。项目里还包含验证码识别,这是过程中最麻烦也最有趣的部分。
适合谁来参考?一是刚接触Python爬虫、想做一个完整项目练手的人;二是法律或社科领域的研究者,需要把裁判文书变成可分析的数据集;三是做通用数据采集平台的开发人员,可以从中提取一套可复用的模块设计思路。整个项目不依赖多高深的技术,Python3加requests、BeautifulSoup、lxml、OpenCV、TensorFlow/Keras、SQLite就能搭起来,关键是模块怎么划分、异常怎么处理、字段怎么解析,这些比单纯“能爬”重要得多。
2. 系统整体架构与模块拆分
我把系统拆成六个模块:调度器、下载器、验证码识别服务、解析器、存储层、查询分析层。最开始我没有做调度器,直接写循环发请求,结果跑了几百个请求就被限制,而且中途断网就得从头再来。后来才意识到,这种采集系统本质上是一个“生产者-消费者”模型,调度器负责控制节奏和任务分配,消费者只负责具体干活。
模块职责是这样的:
- 调度器:从任务队列取任务,判断是“按关键词搜索”还是“按DocID精确查询”,分发到下载器;记录每个任务的执行状态;控制整体请求频率和超时重试。
- 下载器:负责构造HTTP请求、处理会话Cookie、调用验证码识别服务获取参数,拿到HTML或JSON响应。这里我用requests.Session保持会话,避免每次新建连接。
- 验证码识别服务:独立成一个HTTP服务或本地函数,输入验证码图片,输出文本。独立出来是为了后续换模型不影响主流程。
- 解析器:用BeautifulSoup/lxml解析HTML,按文书详情页的DOM结构抽取案号、案件名称、法院、日期、正文等字段。
- 存储层:使用SQLite做本地存储,表结构按“案件基础信息表”“文书正文表”“采集日志表”拆分,方便后续查询。
- 查询分析层:基于SQL和pandas,提供按时间、地域、案由、文书类型筛选,输出DataFrame或Excel。
下面是我在实际项目里画的一张简化数据流(用文字描述):任务配置(关键词、日期范围、法院列表)进入调度器,调度器生成检索任务,下载器先请求检索页,如果遇到验证码就调用识别模块,拿到结果后回填请求参数;检索结果列表解析出DocID和摘要,再进入详情页下载任务;详情页下载完成后交给解析器,提取结构化字段写入SQLite;查询分析层读取SQLite生成分析报表。
技术选型上,我的建议表如下:
| 功能 | 可选方案 | 我最终选择 | 原因 |
|---|---|---|---|
| 语言 | Python3 | Python3.8+ | 生态全,写爬虫和数据分析无缝衔接 |
| 请求库 | requests / httpx | requests | 简单稳定,Session管理方便 |
| HTML解析 | BeautifulSoup / lxml | BeautifulSoup+lxml | bs4做遍历,lxml做底层解析速度 |
| 验证码识别 | Tesseract / CNN / 打码平台 | CNN + Tesseract兜底 | 自研可控,不依赖外部服务 |
| 存储 | SQLite / MySQL / PostgreSQL | SQLite | 单机研究和中等数据量足够,零配置 |
| 分析 | pandas / Excel | pandas | 清洗聚合方便 |
这套架构最大的好处是每个模块可以单独替换。比如验证码识别从Tesseract换成CNN,下载器无需改动;存储从SQLite换成MySQL,解析器无需改动。我一开始没有做模块化,所有代码揉在一个脚本里,后来增加“时间过滤”和“法院地域切割”需求时,差点重构到崩溃。
3. DocID与分类检索:最难的是理解业务数据
裁判文书网每篇文书都有一个唯一编号,标题里的DocID就是它。最初我把它当成普通参数,后来发现DocID里藏着很多信息规律。虽然没有官方公开的编码规则,但通过大量样本对比,大致可以推断出它包含案件类型、法院代码、年份、内部序号等信息。我在系统里把DocID设计为主键,所有去重、增量、跟踪都围绕它展开。
DocID的作用有三块:第一,精确检索,不需要再通过搜索页关键词匹配,直接拼URL就能下载指定文书;第二,去重,采集日志里记录DocID,下次遇到直接跳过,不会重复下载;第三,增量更新,通过比较最新DocID或日期字段,只抓新增文书。
分类检索则是另外一个关键功能。裁判文书网的搜索页支持关键词、案由、法院层级、地域、文书类型、审判程序、时间范围等条件。我在系统里将这些条件映射成结构化请求参数,比如:
params = { "keyword": "民间借贷纠纷", "caseType": "民事案件", "courtLevel": "中级人民法院", "province": "河南省", "startTime": "2020-01-01", "endTime": "2023-12-31", "pageNum": 1, "pageSize": 10, }这样做的意义在于,检索条件变成了可编程的查询对象,而不是手工在网页里点。配合时间过滤和地域切割,我可以在代码里批量生成多个组合任务,例如“河南省2020年民间借贷纠纷的判决书”和“上海市2021年民间借贷纠纷的裁定书”,自动打包下载。
分类检索的实现并不复杂,核心是维护好条件映射表和翻页逻辑。需要注意两个坑:一是不同查询条件下,搜索结果的字段名可能变化,需要做兼容;二是分页参数有些是从0开始,有些从1开始,要用实际抓包结果确认。我用的方式是先手动用浏览器开发者工具抓一两个请求,对比URL和表单参数变化,确认规律后再写代码,而不是靠猜。
DocID查询的实现更简单,但也更讲究:需要支持批量导入DocID列表,从Excel或文本读取,逐个下载对应文书,同时把下载失败的DocID记录下来,方便后续重试。这部分我设计成一个独立的“DocID导入下载”入口,因为法律研究者经常会拿到一批案号或DocID清单,需要精确补全文书全文。
4. 验证码识别模块:从二值化到CNN的演进
这是整套系统里技术含量最高的部分。裁判文书网的验证码大多是数字字母组合,有干扰线和噪点,颜色不固定。最开始我用Tesseract直接识别,效果惨不忍睹,准确率不到60%。后来优化图片预处理,把灰度、二值化、去噪、分割做完之后,Tesseract准确率能到70%左右,但对粘连字符和带旋转的字符依然不行。真正稳定下来是在我改用CNN分类器之后,准确率提升到95%左右。
我把自己做验证码识别的过程拆成三步,供你参考。
第一步,图片预处理。用OpenCV把彩色图转灰度,再用大津法二值化,去掉背景色。然后通过轮廓检测找到每个字符的外接矩形,按位置排序后切分成单字符图片。切割的关键是处理字符粘连,我采用“垂直投影法”,统计每列的黑点数量,两个波峰之间的波谷就是字符边界。如果字符本身有断裂,还可以用形态学闭运算补全。
第二步,生成训练数据,构建CNN模型。要训练识别模型,需要大量标注好的字符图片。我手工标注了300张验证码,切分后得到约1200个单字符样本,但这还远远不够。于是我又写了一个数据增强脚本,对每张单字符做平移、旋转、缩放、加噪声,把样本量扩到20000多张。模型结构很简单,就是卷积层加全连接层,输出36类(数字0-9加字母A-Z,排除易混淆的O和0、I和1)。用Keras搭,训练几十个epoch就稳定收敛。
第三步,模型集成和容错。识别流程变成:先用CNN识别,如果置信度过低或者连续重试几次失败,就切换到Tesseract作为第二方案,再不行就把验证码图片弹出来人工输入。这里关键是设置“重试上限”,比如同一个请求最多重试3次,不然会陷入死循环。
def recognize_captcha(image_path): chars = preprocess_and_split(image_path) text = "" confs = [] for char_img in chars: pred, conf = cnn_predict(char_img) if conf < 0.85: # 备用方案:Tesseract pred = tesseract_fallback(char_img) text += pred confs.append(conf) return text, min(confs)这里要特别强调合规问题。验证码机制是网站为了保护访问安全而设计的,我做这套识别模块的初衷是降低自动化采集中人工介入的频率,但前提是不得用于绕过或破坏网站的访问控制。如果你是出于研究OCR、深度学习的目的是完全没问题的,但如果用来大规模突破反爬限制、影响目标站正常服务,那就不合适了。我本人在测试时也严格设置了请求间隔,验证码识别只作为“降低人工成本”的手段,而不是“无限制采集”的帮凶。
另一个经验是:验证码识别模块最好做成独立服务,别和主程序耦合太深。我用Flask起了一个本地服务,传入验证码图片URL返回识别结果。这样即使识别模型升级,也不影响采集主程序。
5. 时间过滤与法院地域切割:为法律分析做的数据切片
法律研究经常需要按时间段和地域维度看数据分布。比如研究“近五年民间借贷纠纷中利率认定标准的变化”,就需要把裁判文书按年份切块,再分别统计各年份的利率支持比例。又比如比较“江苏和广东两省在劳动争议案件中的胜诉率”,就需要把法院地域作为分组维度。这两个需求在系统里对应两个重要功能:时间条件过滤和法院地域切割。
时间条件过滤不只是对“裁判日期”做大于小于判断那么简单。文书里有多个时间字段,包括立案日期、裁判日期、发布日期。分析时选错了字段,结果可能差很多。我一般默认用“裁判日期”,因为它才代表判决作出的时间。下载后的结构化数据中,日期字段可能有“2020年5月12日”“2020-05-12”“2020/5/12”等多种格式,解析时要统一成标准化日期。我在系统里写了一个专门的parse_date函数,处理各种常见且不常见的日期格式:
import re from datetime import datetime def parse_date(s): if not s: return None s = s.strip() m = re.match(r"(\d{4})[年\-/.](\d{1,2})[月\-/.](\d{1,2})日?", s) if m: y, mo, d = int(m.group(1)), int(m.group(2)), int(m.group(3)) return datetime(y, mo, d) return None时间过滤还牵扯到查询边界问题。比如从1月1日到12月31日,我在构造请求参数时统一用闭区间,但有些系统是半开区间,导致边界日期重复或缺失。我在代码里专门做了二重校验:搜索时用起止时间查询,入库后仍然保存原始日期字段,后续统计用SQL的BETWEEN或pandas的布尔索引,保证边界一致。
法院地域切割,我认为是这套系统里最能体现业务价值的设计。裁判文书中的法院名称是一串字符串,比如“河南省郑州市中级人民法院”“广东省深圳市南山区人民法院”。要做地域切割,就要从这串名称里解析出省级、市级、区县级和法院级别。我维护了一张行政区划映射表,通过关键词匹配提取:
def parse_court(name): province = "" city = "" district = "" level = "基层" for p in province_list: if name.startswith(p): province = p break # 在此基础上匹配市级、区县级 if "高级人民法院" in name: level = "高级" elif "中级人民法院" in name: level = "中级" return {"province": province, "city": city, "district": district, "level": level}地域切割之后,数据就可以按“省-市-区-法院级别”四个维度做下钻。我在导出功能里增加了“按地域分组统计”选项,直接输出每个区域的文书数量、案件类型分布、平均审理时长等指标。某种程度上,这已经超出了爬虫工具的范畴,变成一个轻量级的裁判文书BI分析平台。
这里我踩过一个坑:部分法院名称包含“铁路运输法院”“知识产权法院”“金融法院”等专门法院,它们无法简单归入行政区划。我的解决方案是把它们单独归类为“专门法院”,不强行切到某个区县。这类细节虽然不影响主体分析,但在数据总量较大时,会对统计结果产生明显偏差。
6. 批量、增量、垂直:三种爬虫模式在这套系统里的实际应用
爬虫圈经常提三个词:批量型爬虫、增量型爬虫、垂直型爬虫。很多人分不清,其实这套系统里三种都占了。
批量型爬虫的典型场景是:一次性把所有符合条件的文书全部下载下来。比如“把2020年所有民间借贷纠纷判决书都抓下来”,这就是一个批量任务。批量任务的特点是范围明确、量大、可断点续跑。我在调度器里为批量任务设计了任务队列,每抓完一个DocID就标记为完成,程序中断后重启会从完成集的尾部继续,不会重复抓。
增量型爬虫解决的是“今天抓完了,明天有新文书怎么办”的问题。裁判文书网的文书是持续更新的,法律研究往往需要追踪最新动态。增量抓取的核心是保存一个“最近抓取时间”或“最后DocID”,每次启动时只抓该时间点之后发布的文书。我结合时间过滤条件,把“采集频次”做成配置项,可以设置每天定时抓取当天新增文书。
垂直型爬虫指专注于某一特定领域、特定网站或特定数据结构的爬虫。裁判文书网本身就是一个垂直站点,而我的系统还进一步垂直——它只处理文书详情页和搜索结果页,不关心网站其他板块,也不做通用搜索引擎抓取。垂直的好处是解析规则可以写得很精细,提取字段更准确。
三者结合产生的效果是:系统既能一次性回补历史数据,又能持续跟踪最新文书,同时保持领域数据结构化的高质量。下面这张表是我实际运行时的配置示例:
| 任务类型 | 触发方式 | 时间范围 | 频率 | 备注 |
|---|---|---|---|---|
| 全量回补 | 手动执行 | 2015-01-01 至今 | 一次 | 按省份分批跑 |
| 每日增量 | 定时任务 | 当天日期 | 每天8:00 | 增量任务 |
| 定向补充 | DocID导入 | 不限定 | 手动 | 从Excel导入DocID清单 |
在实现批量任务时,我特别强调“限速”和“暂停恢复”。裁判文书网对请求频次有比较严格的控制,正常阅读速度下,几秒钟一页是合理的,我不建议用高并发去硬刚,稳定的低频调用远比“短时间抓几百页然后被封锁”有价值。我的做法是给每个请求之间加2到3秒的随机延迟,每个批次跑完500条后暂停30秒。实际跑下来一天的采集量是几万篇,完全够研究用。
关于去重,除了DocID主键,我还对“案号+裁判日期”做联合索引,防止同一文书被多个搜索条件重复抓取。因为裁判文书网存在同一文书通过不同关键词都能搜到的情况,只靠DocID去重没问题,但在入库前用案号和日期双重校验可以更快地提前跳过。
7. 踩过的坑和最终建议
这个项目前前后后改了三版,踩过的坑想专门总结一下,希望能帮你少走弯路。
第一个坑是网页结构变化导致解析器失效。裁判文书网的HTML结构调整过几次,字段的标签和CSS类名变了,原来写好的解析规则直接作废。我的解决办法是:在解析器前加一层“页面结构检测”,检测页面里是否包含预期的关键节点,如果没有就记录异常并保存原始HTML,而不是直接报错退出。这样即使解析规则过期,原始数据还在,可以后补解析逻辑。
第二个坑是编码问题。有些页面的编码是GBK或GB2312,直接用requests的response.text会乱码。我的解决方案是统一用response.content拿到字节流,再用apparent_encoding或chardet识别编码后解码。入库前统一转成UTF-8,避免SQLite里面出现乱码。
第三个坑是SQLite并发写锁。如果用多线程下载,多个线程同时写SQLite会报“database is locked”。我改用单线程写库,下载和解析可以多线程,但写入操作全部进队列,由独立的写线程负责。这个设计虽然简单,但避免了很多烦恼。
第四个坑是验证码识别准确率在实际环境里不稳定。我训练的CNN模型在测试集上准确率95%,但到线上识别包含背景干扰的新验证码时,准确率会掉到90%左右。这很正常。后来我加入了在线难例挖掘:每轮人工确认的验证码会存入“难例库”,定期增量训练模型。虽然增量训练不能每次让模型完美,但确实能逐步提升鲁棒性。
第五个坑是数据合规意识不够。刚开始我只关注技术,不太关注爬虫的使用边界。后来我给自己定了几条铁律:只采集公开数据,设置合理请求频率,不碰个人隐私敏感信息,采集数据仅用于研究分析,不用于商业用途或公开发布原始全量数据。法律研究本身是正当需求,但采集行为必须以不损害网站正常运行为前提。这条经验实际比任何技术细节都更重要。
如果你也想搭一套类似系统,我的建议是:先从小规模跑通,选一个案由、一个省份、一个年份,手动把一条完整链路走通,再去扩展。先把下载、验证码、解析、入库跑起来,再去研究时间过滤、地域切割这些高级功能。这个项目最好的地方在于,你不需要一开始就有完整的架构设计,而是随着研究需求加深,自然长出新的模块。我就是这么一步步把当初的脚本变成了一个还算耐用的采集分析系统。
本文还有配套的精品资源,点击获取