AI 为什么能比你更懂网页?一次关于“语义抽取”的实战实验

81 阅读4分钟

——当抓取遇上 AI,结构规则不再是唯一的出路


一、传统抓取为什么越来越累?

如果你做过一点网页抓取,你大概经历过这种场面:

好不容易把一个站点的结构理清楚,整理了好几行 XPath 或 CSS Selector,终于把标题、评分、评论都抽出来了。
但没高兴几天,网页改版了。

class 名字换了。
div 的层级挪了。
甚至有些字段直接被塞进奇怪的标签里。

于是你的脚本扑通一声倒地,又得重新“考古” HTML。

这个循环会让人怀疑人生 ——
不是在抓数据,而是在和网页结构谈恋爱,而且是极其不稳定的那种。

也就是所谓的,结构驱动的抓取模式,总是有点“脆”。

二、换个视角:如果不是匹配结构,而是让 AI 直接“读”网页呢?

现在的大模型(GPT、Claude、Llama 那些)在处理文本上的能力,比我们想象得更强。

给它一页 HTML,它不仅能读,还能“理解”:

  • 哪段是电影标题?
  • 哪些数字像评分?
  • 评论区域是什么结构?
  • 标签是分类还是描述内容?

它并不是依靠 class 名称,而是靠语义、靠“逻辑感”,甚至靠页面布局的“暗示”。

传统抓取的是标签。
AI 抓的是含义。

这是完全不同的思路。

就好像以前你让一个程序员分析页面结构;现在你把页面扔给一个“读网页经验丰富的人”,让他直接告诉你数据在哪里。

三、跨界混搭的真正爽点:让抓取负责抓页面,让 AI 负责读页面

说实话,这种分工很自然:

  • 抓取模块:负责把 Douban 页面下载下来
  • AI 模块:负责理解结构、抽取字段
  • 代理:负责不被网站骂出局
  • 开发者:只负责问一句,“帮我把电影信息抽出来吧?”

如果说传统抓取是“精确制导”,
那 AI 驱动抓取更像是“语义扫射”。

下面我直接给你看一段可运行的代码,里面包含:

  • 请求 Douban 页面
  • 走代理(亿牛云示例)
  • 把 HTML 丢给 AI 解析
  • 返回结构化 JSON

依然是完整中文注释。

代码示例

import requests
from bs4 import BeautifulSoup
import json
from openai import OpenAI

# ========== 1. 配置你的大模型 ==========
# 你可以换成任何兼容 OpenAI 的模型
client = OpenAI(api_key="你的API密钥")

# ========== 2. 配置代理(亿牛云的示例 www.16yun.cn) =======
proxy_host = "proxy.16yun.com"
proxy_port = "12345"
proxy_user = "your_username"
proxy_pass = "your_password"

# 拼接成 requests 认识的代理字符串
proxies = {
    "http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
    "https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
}

# ========== 3. 抓取 Douban 页面的 HTML ==========
def get_page(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                      "(KHTML, like Gecko) Chrome/123.0 Safari/537.36"
    }
    resp = requests.get(url, headers=headers, proxies=proxies, timeout=15)
    resp.raise_for_status()
    return resp.text


# ========== 4. 用 AI 帮我们“读懂”页面,然后抽取字段 ==========
def extract_movie_info_from_html(html):
    prompt = f"""
我给你一段来自 Douban 的电影页面 HTML。
请你找出并提取以下字段:
- title:电影名称
- rating:豆瓣评分
- comment:一段评论摘要(如果有)
- tags:电影的标签(类型、风格等)

请把结果严格用 JSON 格式返回,不要多说其他话。

这是 HTML:
{html}
"""
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}]
    )

    result = response.choices[0].message.content

    # 尝试解析 JSON
    try:
        return json.loads(result)
    except:
        return {"raw_output": result}


# ========== 5. 主流程:抓 → 交给 AI → 输出 ==========
if __name__ == "__main__":
    url = "https://movie.douban.com/subject/1292052/"  # 例子:肖申克的救赎

    print("开始抓网页……")
    html = get_page(url)

    print("AI 正在帮你分析结构……")
    info = extract_movie_info_from_html(html)

    print("\n=== 解析后的电影信息 ===")
    print(json.dumps(info, indent=4, ensure_ascii=False))

四、这套玩法到底有什么价值?为什么值得这么做?

如果你已经写过不少抓取,你会立刻意识到这个方案的价值:

1. 网页改版不再是灾难

HTML 换个 class?
AI 不在乎。

它看的是“这像是评分的位置”,“这段文字像是标签”。

2. 跨网站也能复用同一套 Prompt

换一个电影网站、换一个新闻网站,逻辑仍然通用。

这种“通用解析能力”是传统抓取做不到的。

3. 你不需要死盯 HTML 结构

以前你要把标签层级啃到牙口发酸;
现在你只需要说:

“帮我把页面里的电影信息提取一下。”

AI 会乖乖地把字段整理好。

4. 抽出来的字段更接近“人读出来的意思”

AI 会自动填补隐性语义:

  • 分数不是纯数字
  • 标签不是随机文本
  • 评论不是所有 <p> 文本混在一起

它理解上下文。

AI 让抓取从“写选择器”升级成“写任务”

以前的抓取逻辑是:

给我标签,我告诉你位置。

现在变成:

给我网页,我告诉你内容。

这就是抓取从“结构解析工具”进化为“语义理解系统”的关键一步。