做过新闻类分析的同学,大多都经历过这种循环:
“帮我把这个页面的标题、时间、正文抓出来。”
“又改版了,再修一下 XPath 吧。”
“嗯?这个栏目怎么又换模板了?”
于是问题就来了:
有没有可能,不用我们自己盯着 DOM 结构写解析器,而是让 LLM 来生成解析规则?
这篇文章,就是把“Prompt → Parser 自动构建”这件事整理成一份速查指南。
随用随查,复制后基本就能跑。
本文以 第一财经(yicai.com)头条财经新闻页面 为例,演示完整流程。
1. 能用它做什么?
1)把自然语言变成解析规则
你说一句“帮我提取标题、作者、时间、正文”,
LLM 能反推出对应的 XPath / CSS 选择器。
2)生成可运行的 Python 解析器
它能自动拼装一个 parse(html),字段错了还会给 fallback。
3)自动识别网页特征
例如第一财经的新闻正文结构不太规整,有广告、有空段落,但 LLM 能识别出来并避开。
4)解析失败可自动修复
字段提不出来?丢回去再问一次就行。
5)能把 Prompt 转成一个长期可复用的 Parser 文件
适合新闻、资讯类站点这种常年改模板的网站。
2. Prompt 模板
下面是实践中效果最稳定的 Prompt 结构。
生成字段解析规则
请根据下面的财经新闻 HTML,生成一份字段解析规则。
字段:标题(title)、作者(author)、发布时间(pub_time)、正文内容(content)
输出 JSON,格式为 {"title": "...", "author": "...", "pub_time": "...", "content": "..."}
HTML:
{HTML_CONTENT}
生成可执行 parse(html) 的 Python 函数
根据上面的字段解析规则,生成一个 Python 函数 parse(html),返回 dict。
要求:
- 使用 XPath
- 解析失败返回 None,不报错
- 正文允许合并多个段落
解析失败自动修复
以下字段解析失败,请根据页面结构重写相应 XPath:{字段列表}
HTML:
{HTML_CONTENT}
3. 完整示例:抓第一财经头条 + LLM 自动生成解析器
示例内容包括:
- 用 Playwright 抓第一财经最新头条
- 通过爬虫代理访问
- 调用 LLM 自动生成解析规则
- 用生成的规则提取标题、作者、时间、正文
下面的代码可以直接运行。
import asyncio
import json
from playwright.async_api import async_playwright
from openai import AsyncOpenAI
from lxml import etree
# ============ 亿牛云代理配置(示例 www.16yun.cn)===========
PROXY_HOST = "proxy.16yun.cn" # 代理域名
PROXY_PORT = "3100" # 代理端口
PROXY_USER = "your_username" # 代理用户名
PROXY_PASS = "your_password" # 代理密码
# ============================================
# ============ LLM 调用:自动生成解析规则 ============
client = AsyncOpenAI(api_key="YOUR_API_KEY")
async def generate_parser(html):
"""让 LLM 读懂第一财经新闻页面,并自动生成解析规则"""
prompt = f"""
下面是一篇来自第一财经(yicai.com)的财经新闻 HTML,请为它生成解析规则。
字段:标题(title)、作者(author)、发布时间(pub_time)、正文内容(content)
输出 JSON 格式,不要写解释文字。
HTML:
{html}
"""
resp = await client.chat.completions.create(
model="gpt-4.1",
messages=[{"role": "user", "content": prompt}]
)
return json.loads(resp.choices[0].message.content)
# ============ 解析执行逻辑 ============
def run_parser(html, rules):
"""根据 LLM 提供的规则执行字段提取"""
tree = etree.HTML(html)
data = {}
for field, xpath in rules.items():
try:
res = tree.xpath(xpath)
# 正文经常是多段落,特殊处理
if field == "content" and isinstance(res, list):
cleaned = [x.strip() for x in res if isinstance(x, str)]
data[field] = "\n".join(cleaned) or None
else:
data[field] = res[0].strip() if res else None
except:
data[field] = None
return data
# ============ Playwright 抓取第一财经头条 ============
async def fetch_page(url):
"""使用 Playwright 抓取第一财经页面内容(走代理)"""
proxy_config = {
"server": f"http://{PROXY_HOST}:{PROXY_PORT}",
"username": PROXY_USER,
"password": PROXY_PASS
}
async with async_playwright() as pw:
browser = await pw.chromium.launch(
headless=True,
proxy=proxy_config
)
page = await browser.new_page()
await page.goto(url, timeout=30000)
html = await page.content()
await browser.close()
return html
# ============ 主流程:抓 → 解析器生成 → 解析 ============
async def main():
url = "https://www.yicai.com/news/latest.html" # 第一财经最新头条
print("正在抓取第一财经头条网页……")
html = await fetch_page(url)
print("正在让 LLM 分析 HTML 并自动生成解析器……")
rules = await generate_parser(html)
print("生成的解析规则:", rules)
print("正在执行解析……")
result = run_parser(html, rules)
print("结果:\n", result)
if __name__ == "__main__":
asyncio.run(main())
4. 一些配置经验
LLM 的 prompt 一定要清晰
越结构化越准确,尤其是:
- 指定字段名
- 指定输出 JSON
- 指定 XPath
- 明确“不报错、返回 None”
模糊的指令经常导致格式混乱、字段缺失。
第一财经的页面结构特点
做过第一财经的都知道,页面结构有几个小坑:
- 正文
<p>有时混入广告段落 - 作者标签不固定,有些文章没有
- 发布时间格式不统一
- 有时正文被包装在嵌套 div 中
LLM 对这些结构异常其实识别得挺准,用它来生成 XPath 会省不少人工调试时间。
XPath 比 CSS 更稳
新闻站点结构复杂,XPath 的容错性更好。
代理选长连接更稳定
Playwright 会保持长连接,代理稳定性极其关键。
普通短连接代理很容易导致超时或中断。
5. 最快 5 分钟验证是否可用
如果你只想验证“LLM 生成解析器是否靠谱”,按这四步即可:
第一步:抓 HTML
html = await fetch_page("https://www.yicai.com/news/latest.html")
第二步:自动生成解析规则
rules = await generate_parser(html)
第三步:执行解析
result = run_parser(html, rules)
第四步:打印
print(result)
通常第一次就能提到标题、时间和部分正文。
不准?把失败字段扔回 LLM,它会自己修。
最后的一点想法
网站解析这件事,本质是“页面一变 → 解析器就得跟着改”。
但现在我们有了一个新的思路:
- 以前是我们去看 DOM,再写 XPath
- 现在是让 LLM 去看 DOM,再写 XPath
这不仅减少工作量,还能做出更“适配多模板”的解析器。