导读:在传统爬虫开发中,我们花费了80%的时间在与网页结构“搏斗”:编写脆弱的XPath、应对动态渲染的DOM、处理千奇百怪的非结构化文本。一旦网站改版,所有努力付诸东流。2026年,随着多模态大模型(Multimodal LLM)和长上下文窗口的普及,爬虫范式迎来了根本性变革——从“规则匹配”转向“语义理解”。本文将带你构建一个由LLM驱动的 inteligente 爬虫系统,只需一句自然语言指令,即可自动解析复杂页面、提取非结构化数据,并具备极强的抗干扰和自愈能力。


一、传统爬虫的至暗时刻 vs. LLM的新范式

1. 传统痛点

  • 选择器地狱div.container > ul.list li:nth-child(3) span.price,只要前端加个div,整个表达式失效。
  • 动态渲染噩梦:面对React/Vue生成的动态DOM,需要配置Selenium/Playwright,还要等待网络空闲,速度慢且资源消耗大。
  • 非结构化数据无力:想从一段混杂的新闻正文中提取“事件时间、地点、人物”,传统正则表达式几乎无法胜任。

2. LLM驱动的新范式

  • 语义提取:不再关心HTML标签层级,直接告诉AI:“提取页面上所有商品的名称、价格和评分”。
  • 抗干扰强:即使网页布局大变,只要语义信息(文本内容)还在,LLM就能识别。
  • 结构化输出:直接输出JSON,无需后续清洗。

二、核心架构:Prompt + DOM修剪 + 模型推理

直接使用完整HTML发送给LLM是不可行的(Token消耗大、噪声多)。我们需要一套**“精简 - 推理 - 验证”**的流程。

架构图

渲染错误: Mermaid 渲染失败: Parse error on line 8: ... F --> G[LLM API (Qwen/GPT-4o)] G -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

关键技术点

  1. DOM修剪 (DOM Pruning):剔除<script>, <style>, <svg>等无关标签,只保留包含文本内容的节点及其父级路径线索。
  2. 多模态辅助:对于极度复杂的布局(如嵌套表格、Canvas绘图),结合页面截图,利用多模态模型的视觉能力辅助定位。
  3. 结构化约束:使用JSON Schema强制模型输出标准格式,便于程序解析。

三、实战代码:构建智能提取器

我们将使用 Python 结合 BeautifulSoup 进行DOM清洗,调用2026年主流的本地/云端大模型API(以兼容OpenAI格式的接口为例,如Qwen-Max, GLM-Edge等)。

1. 环境准备

pip install beautifulsoup4 lxml httpx pydantic
# 假设使用兼容OpenAI SDK的库
pip install openai

2. DOM智能清洗模块

不要直接把几兆的HTML扔给模型。我们需要提取“语义树”。

from bs4 import BeautifulSoup, NavigableString
import re

class DomPruner:
    def __init__(self, html: str, max_tokens: int = 4000):
        self.soup = BeautifulSoup(html, 'lxml')
        self.max_tokens = max_tokens

    def prune(self) -> str:
        # 1. 移除无用标签
        for tag in self.soup(['script', 'style', 'noscript', 'iframe', 'svg']):
            tag.decompose()
        
        # 2. 简化属性:只保留id, class, name, href, src等关键属性
        for tag in self.soup.find_all(True):
            attrs = dict(tag.attrs)
            keep_attrs = {}
            for attr in ['id', 'class', 'name', 'href', 'src', 'alt', 'title']:
                if attr in attrs:
                    keep_attrs[attr] = attrs[attr]
            tag.attrs = keep_attrs
            
        # 3. 压缩空白字符
        text = self.soup.get_text(separator=' ', strip=True)
        # 简单的截断策略,防止超出Token限制(实际生产需按Token计数)
        if len(text) > self.max_tokens * 4: # 粗略估算 1 token ≈ 4 chars
            text = text[:self.max_tokens * 4] + "...[内容截断]"
            
        return text

    def get_structured_hint(self) -> str:
        # 可选:保留部分DOM结构线索,帮助模型理解层级
        # 这里简化为提取所有链接和标题作为上下文参考
        hints = []
        for h in self.soup.find_all(['h1', 'h2', 'h3']):
            hints.append(f"<Heading>{h.get_text(strip=True)}</Heading>")
        return "\n".join(hints)

3. LLM提取引擎

定义清晰的Prompt和输出Schema。

import json
from openai import OpenAI
from pydantic import BaseModel, Field

# 定义期望的输出结构
class ProductItem(BaseModel):
    name: str = Field(description="商品名称")
    price: float = Field(description="商品价格,纯数字")
    currency: str = Field(description="货币单位")
    rating: float = Field(description="评分,0-5之间", default=0.0)
    url: str = Field(description="商品详情页链接")

class ExtractionResult(BaseModel):
    success: bool
    data: list[ProductItem]
    error_message: str | None = None

class LLMScraper:
    def __init__(self, api_key: str, base_url: str, model: str = "qwen-max-2026"):
        self.client = OpenAI(api_key=api_key, base_url=base_url)
        self.model = model

    def extract(self, html: str, instruction: str) -> ExtractionResult:
        pruner = DomPruner(html)
        clean_content = pruner.prune()
        
        prompt = f"""
        你是一个专业的网页数据提取助手。
        
        【任务目标】
        {instruction}
        
        【网页内容摘要】
        {clean_content}
        
        【要求】
        1. 忽略导航栏、页脚、广告等无关信息。
        2. 如果价格包含符号(如¥, $),请分离数字和单位。
        3. 如果没有找到数据,返回空列表,不要编造。
        4. 必须严格遵循JSON Schema格式输出。
        
        请输出JSON格式结果:
        """

        try:
            response = self.client.beta.parse.completions.create(
                model=self.model,
                messages=[
                    {"role": "system", "content": "你只输出JSON,不包含任何Markdown标记或解释性文字。"},
                    {"role": "user", "content": prompt}
                ],
                response_format=ExtractionResult, # 2026年新特性:强制结构化输出
                temperature=0.0
            )
            return response.choices[0].message.parsed
        except Exception as e:
            return ExtractionResult(success=False, data=[], error_message=str(e))

4. 调用示例

if __name__ == "__main__":
    # 模拟获取到的HTML
    raw_html = requests.get("https://example-shop.com/products").text
    
    scraper = LLMScraper(
        api_key="sk-...", 
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", # 以阿里云为例
        model="qwen-plus"
    )
    
    # 自然语言指令:无需写XPath!
    instruction = "提取页面上所有的手机商品,包括名称、价格、评分和购买链接。"
    
    result = scraper.extract(raw_html, instruction)
    
    if result.success:
        print(f"成功提取 {len(result.data)} 个商品:")
        for item in result.data:
            print(f"- {item.name}: {item.price}{item.currency} (评分:{item.rating})")
    else:
        print(f"提取失败: {result.error_message}")

四、进阶策略:应对复杂场景

1. 动态加载与无限滚动

对于SPA(单页应用),LLM无法直接执行JS。

  • 方案:使用轻量级浏览器(如Playwright)加载页面 -> 等待网络空闲 -> 获取最终HTML -> 交给LLM解析。
  • 优化:利用LLM判断“是否还有下一页”,自动生成点击“下一页”的选择器或指令,形成闭环。

2. 多模态视觉增强

当页面大量使用Canvas或图片展示文字时,纯文本DOM失效。

  • 方案:截取可视区域截图 -> 连同精简后的DOM一起发送给多模态模型(如GPT-4o, Qwen-VL)。
  • Prompt:“结合截图和DOM结构,找出图中红色框选区域对应的商品名称。”

3. 自适应重试机制 (Self-Correction)

LLM偶尔会幻觉或格式错误。

  • 逻辑
    1. 解析返回的JSON。
    2. 如果JSON非法或字段缺失,将错误信息 + 原HTML片段再次发给LLM。
    3. Prompt:“上次提取失败了,原因是XXX。请重新分析并修正。”
      这种“反思链”(Chain of Thought)能显著提高准确率。

五、成本与性能优化

在2026年,虽然模型便宜了,但大规模爬取仍需考虑成本。

  1. 缓存策略:对相同URL的HTML指纹(Hash)进行缓存,避免重复调用LLM。
  2. 小模型蒸馏:对于结构固定的页面,先用大模型生成几次训练数据,然后微调一个7B参数的小模型(如Llama-3-8B-Instruct)专门负责该类网站的提取,成本降低90%。
  3. 分层提取
    • 第一层:用小模型/正则快速判断页面类型和是否有数据。
    • 第二层:只有确认有数据时,才调用大模型进行详细提取。

六、伦理与合规警示

技术越强大,责任越重大。

  • Robots协议:LLM爬虫依然必须遵守robots.txt
  • 频率限制:智能不代表可以无限制高频访问,需设置合理的延迟。
  • 数据隐私:严禁提取个人敏感信息(PII),在Prompt中应加入“忽略个人隐私数据”的指令。
  • 版权意识:提取的数据仅用于分析或学习,严禁直接用于商业转售或构建竞品。

七、结语

LLM驱动的爬虫不是要完全取代传统技术,而是将开发者从繁琐的**“维护选择器”中解放出来,去关注更有价值的“数据逻辑”“业务洞察”**。

在未来,一个优秀的爬虫工程师,不再是XPath大师,而是Prompt工程师数据架构师。你只需要告诉AI“想要什么”,剩下的,交给智能去完成。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐