LLM驱动爬虫:利用大语言模型自动解析动态DOM与智能提取非结构化数据
导读:在传统爬虫开发中,我们花费了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消耗大、噪声多)。我们需要一套**“精简 - 推理 - 验证”**的流程。
架构图
关键技术点
- DOM修剪 (DOM Pruning):剔除
<script>,<style>,<svg>等无关标签,只保留包含文本内容的节点及其父级路径线索。 - 多模态辅助:对于极度复杂的布局(如嵌套表格、Canvas绘图),结合页面截图,利用多模态模型的视觉能力辅助定位。
- 结构化约束:使用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偶尔会幻觉或格式错误。
- 逻辑:
- 解析返回的JSON。
- 如果JSON非法或字段缺失,将错误信息 + 原HTML片段再次发给LLM。
- Prompt:“上次提取失败了,原因是XXX。请重新分析并修正。”
这种“反思链”(Chain of Thought)能显著提高准确率。
五、成本与性能优化
在2026年,虽然模型便宜了,但大规模爬取仍需考虑成本。
- 缓存策略:对相同URL的HTML指纹(Hash)进行缓存,避免重复调用LLM。
- 小模型蒸馏:对于结构固定的页面,先用大模型生成几次训练数据,然后微调一个7B参数的小模型(如Llama-3-8B-Instruct)专门负责该类网站的提取,成本降低90%。
- 分层提取:
- 第一层:用小模型/正则快速判断页面类型和是否有数据。
- 第二层:只有确认有数据时,才调用大模型进行详细提取。
六、伦理与合规警示
技术越强大,责任越重大。
- Robots协议:LLM爬虫依然必须遵守
robots.txt。 - 频率限制:智能不代表可以无限制高频访问,需设置合理的延迟。
- 数据隐私:严禁提取个人敏感信息(PII),在Prompt中应加入“忽略个人隐私数据”的指令。
- 版权意识:提取的数据仅用于分析或学习,严禁直接用于商业转售或构建竞品。
七、结语
LLM驱动的爬虫不是要完全取代传统技术,而是将开发者从繁琐的**“维护选择器”中解放出来,去关注更有价值的“数据逻辑”与“业务洞察”**。
在未来,一个优秀的爬虫工程师,不再是XPath大师,而是Prompt工程师和数据架构师。你只需要告诉AI“想要什么”,剩下的,交给智能去完成。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)