在法律数据分析、案例研究等场景中,裁判文书网的文书爬取是高频需求。本文将手把手教你搭建一套完整的裁判文书网自动化爬取系统,核心基于 Playwright 实现浏览器自动化、ddddocr 实现验证码自动识别、MCP(Model Context Protocol)实现工具化封装,最后通过 Ollama LLM 完成爬取结果的 AI 结构化整理。

一、技术栈与核心能力

1. 核心技术栈

技术 / 库 作用
Playwright 浏览器自动化(模拟登录、搜索、页面操作)
ddddocr 验证码自动识别(无需手动输入)
Pydantic 数据模型定义与参数校验
BeautifulSoup4 HTML 页面解析,提取文书信息
MCP(FastMCP) 工具化封装,提供标准化调用接口
Ollama(qwen3-vl:4b) AI 整理爬取结果,生成结构化回答

注意:ollama的模型选用需要具备调用工具能力,即具有tools标签

2. 核心能力

  • 自动完成裁判文书网登录(账号密码输入 + 验证码自动识别);
  • 关键词搜索 + 文书列表解析(去重 + 数量控制);
  • MCP 标准化接口封装,支持客户端便捷调用;
  • AI 自动整理爬取结果,输出易读的结构化内容;
  • 完善的异常处理,预留手动操作兜底时间

二、环境准备

1. 依赖安装

# 基础依赖
pip install playwright pydantic beautifulsoup4 ddddocr langchain-ollama mcp

# 安装Playwright浏览器(Chromium)
playwright install chromium

# 启动Ollama并拉取模型(需提前安装Ollama)
ollama run qwen3-vl:4b

三、核心代码解析

1. 项目结构

├── mcp_serve.py  # 服务端:MCP工具封装+核心爬取逻辑
└── client.py     # 客户端:调用MCP服务,接收用户输入并展示结果

2. 服务端核心代码(mcp_serve.py)

(1)数据模型定义

通过 Pydantic 定义标准化的数据模型,实现参数校验和类型约束:

# 用户认证模型(适配登录流程)
class UserAuth(BaseModel):
    username: str = Field(description="登录账号/手机号")
    password: str = Field(description="登录密码")
    verify_code: Optional[str] = Field(default="", description="验证码(自动识别)")

# 法律文书模型(存储爬取结果)
class LegalDoc(BaseModel):
    title: str = Field(description="法律文书的名称")
    url: str = Field(description="法律文书的详情页完整链接")
    summary: str = Field(description="法律文书的理由")

# 爬取响应模型(标准化返回结果)
class CrawlResponse(BaseModel):
    success: bool = Field(description="是否爬取成功")
    message: str = Field(description="结果说明")
    data: Optional[List[LegalDoc]] = Field(default=None, description="文书列表")
    detail: Optional[Dict] = Field(default=None, description="爬取详情")
(2)浏览器初始化(规避反爬检测)

Playwright 初始化时禁用自动化特征,模拟真实浏览器环境:

@classmethod
async def init_browser_context(cls) -> Tuple[Playwright, Browser, BrowserContext]:
    playwright = await async_playwright().start()
    # 启动Chromium,关闭无头模式,禁用自动化检测
    browser = await playwright.chromium.launch(
        headless=False,
        args=["--disable-blink-features=AutomationControlled", "--start-maximized"]
    )
    # 设置中文环境、自定义UA、最大化窗口
    context = await browser.new_context(
        viewport=None, locale="zh-CN",
        user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0"
    )
    # 移除webdriver标识,避免被反爬检测
    await context.add_init_script("""
        Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
    """)
    return playwright, browser, context

(3)验证码自动识别

通过 ddddocr 识别登录页面的验证码,无需手动输入:

@classmethod
async def capture_verify_code(cls, page: Page) -> str:
    try:
        # 等待验证码图片加载
        verify_code_selector = "img[src*='verifyCode']"
        await page.wait_for_selector(verify_code_selector, timeout=10000)
        
        # 临时文件保存验证码截图
        with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_file:
            temp_path = temp_file.name
        
        # 截图验证码区域并识别
        await page.locator(verify_code_selector).screenshot(path=temp_path)
        with open(temp_path, "rb") as f:
            verify_code = ocr.classification(f.read())
        
        os.unlink(temp_path)  # 删除临时文件
        return verify_code
    except Exception as e:
        logger.error(f"验证码识别失败:{str(e)}")
        return ""

(4)核心爬取流程

整合登录、搜索、页面解析全流程:

@classmethod
async def crawl_legal_docs(cls, auth: UserAuth, keyword: str, doc_count: int = 5) -> CrawlResponse:
    playwright, browser, context = None, None, None
    try:
        # 1. 初始化浏览器
        playwright, browser, context = await cls.init_browser_context()
        page = await context.new_page()
        
        # 2. 访问裁判文书网
        await page.goto("https://wenshu.court.gov.cn", wait_until="networkidle")
        
        # 3. 执行登录+搜索
        await cls.handle_operations(page, auth, keyword)
        
        # 4. 等待文书列表加载并解析
        await page.wait_for_selector(".LM_list", timeout=30000)
        page_content = await page.content()
        soup = BeautifulSoup(page_content, "html.parser")
        docs, parse_detail = cls.parse_doc_page(soup, doc_count)
        
        # 5. 返回成功结果
        return CrawlResponse(
            success=True,
            message=f"成功爬取到 {len(docs)} 条法律文书(关键词:{keyword})",
            data=docs,
            detail=parse_detail
        )
    except Exception as e:
        # 异常处理
        return CrawlResponse(
            success=False,
            message=f"爬取失败:{str(e)}",
            detail={"error": str(e), "status": "failed"}
        )
    finally:
        # 释放浏览器资源
        if context: await context.close()
        if browser: await browser.close()
        if playwright: await playwright.stop()

(5)MCP 工具封装

将爬取逻辑封装为 MCP 工具,提供标准化调用接口:

mcp_server = FastMCP("legal_crawler")

@mcp_server.tool(
    name="crawl_legal_docs",
    description="爬取裁判文书网的法律文书并返回AI整理后的结果,需要用户提供账号密码、关键词和数量(验证码自动识别)"
)
async def mcp_crawl_legal_docs(request: CrawlToolRequest) -> AIResponse:
    # 1. 参数校验
    if not request.keyword:
        return AIResponse(final_answer="❌ 请提供爬取关键词")
    if not request.account or not request.password:
        return AIResponse(final_answer="❌ 请提供完整的账号和密码")
    
    # 2. 转换参数模型
    crawl_request = CrawlRequest.from_tool_request(request)
    
    # 3. 执行爬取
    crawl_response = await LegalDocCrawler.crawl_legal_docs(
        auth=crawl_request.auth,
        keyword=crawl_request.keyword,
        doc_count=crawl_request.doc_count
    )
    
    # 4. AI整理结果
    final_answer = LegalDocCrawler.ai_format_crawl_result(crawl_response, crawl_request.user_query)
    
    # 5. 返回AI整理后的结果
    return AIResponse(final_answer=final_answer)

# 启动MCP服务
if __name__ == "__main__":
    mcp_server.run(transport="streamable-http")

3. 客户端核心代码(client.py)

客户端负责接收用户输入、调用 MCP 服务、展示结果:

async def main():
    # 1. 配置MCP客户端
    client = MultiServerMCPClient(
        {
            "legal_crawler": {
                "transport": "streamable-http",
                "url": "http://localhost:8000/mcp",
                "timeout": 300.0,  # 延长超时,适配登录/爬取耗时
            }
        }
    )

    # 2. 循环接收用户输入
    while True:
        user_input = input("\n请输入你的需求(示例:账号13800138000,密码123456,关键词合同纠纷,数量3):")
        if user_input.strip().lower() in ["退出", "break", ""]:
            break
        
        # 3. 解析用户输入
        try:
            account = re.search(r'账号[::]?\s*(\S+)', user_input).group(1)
            password = re.search(r'密码[::]?\s*(\S+)', user_input).group(1)
            keyword = re.search(r'关键词[::]?\s*([^,,]+)', user_input).group(1)
            count = int(re.search(r'数量[::]?\s*(\d+)', user_input).group(1))
        except:
            print("❌ 输入格式错误,请按示例格式输入!")
            continue
        
        # 4. 调用MCP爬取工具
        tools = await client.get_tools()
        crawl_tool = next(tool for tool in tools if tool.name == "crawl_legal_docs")
        result = await crawl_tool.ainvoke({
            "request": {
                "account": account,
                "password": password,
                "keyword": keyword,
                "count": count
            }
        })
        
        # 5. 展示结果(AI二次优化格式)
        llm = OllamaLLM(model="qwen3-vl:4b", base_url="http://localhost:11434", temperature=0.3)
        optimized_result = llm.invoke(f"整理以下结果为分条格式:{result}")
        print("🎯 爬取结果:\n", optimized_result)

if __name__ == "__main__":
    asyncio.run(main())

四、运行步骤

1. 启动 Ollama 服务

确保本地 Ollama 已启动,且qwen3-vl:4b模型已拉取,在终端输入:

ollama serve  # 启动Ollama服务
ollama pull qwen3-vl:4b  # 拉取模型(首次需执行)

2. 启动 MCP 服务端

3. 启动客户端

按照提示输入爬取需求(示例:账号13800138000,密码123456,关键词合同纠纷,数量3),等待爬取完成即可看到 AI 整理后的结果。

五、关键注意事项

1. 反爬规避

  • Playwright 禁用了AutomationControlled特征,移除了webdriver标识,降低被检测概率;
  • 所有操作添加了合理的sleep间隔,模拟真人操作节奏;
  • 验证码识别失败时,预留 10 秒手动输入时间,登录失败时预留 15 秒手动登录时间。

2. 稳定性优化

  • 页面元素等待使用wait_for_selector,避免因加载慢导致的操作失败;
  • 文书解析时做了去重处理(按标题去重),确保结果唯一性;
  • 所有浏览器资源在finally块中释放,避免内存泄漏。

3. 兼容性调整

  • 页面选择器(如登录按钮、搜索框、验证码图片)需根据裁判文书网页面结构实时调整;
  • 若 Ollama 模型调用失败,会自动降级展示原始爬取结果,保证核心功能可用。

六、扩展方向

  1. 多页爬取:当前仅爬取第一页结果,可扩展分页逻辑,支持更多文书获取;
  2. Cookie 持久化:登录成功后保存 Cookie,避免重复登录;
  3. 代理池集成:添加 IP 代理池,规避单 IP 访问频率限制;
  4. 结果导出:将爬取结果导出为 Excel/JSON 格式,方便后续分析;
  5. 可视化面板:基于 Streamlit/FastAPI 搭建可视化界面,降低使用门槛。

总结

本文实现的裁判文书网爬取系统,整合了浏览器自动化、验证码识别、MCP 工具化、AI 结果整理等核心能力,既保证了爬取的自动化和稳定性,又通过 MCP 封装和 AI 整理提升了易用性。无论是法律案例研究、数据分析,还是工具化封装,这套方案都具备较高的实用价值,可根据实际需求灵活扩展。

效果讲解:

不知道是什么原因,测试发现能够提取关键信息,但是无法定位到输入框,因此无法自动输入账号密码、关键词等,需要手动输入

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐