4.2 数据提取与结构化输出


文档摘要

4.2 数据提取与结构化输出 本节摘要:让模型"顺便看看"和"正式取证"是两回事。提取类武器配合 Pydantic 字段模型,能把页面信息压成带类型约束的 JSON——字段名你定、格式它守、错了重试。本节给出字段建模模板、提取代码、翻页续取与嵌套结构三个实战形态。 从"随口汇报"到"记录在案" 问模型"这页卖什么",它回一段话,读着挺顺,可你没法把一段话塞进数据库。第 3 章说过观察拍负责"看见",本节是把看见的东西记录在案:先定义证据格式(有哪些字段、什么类型、哪些必填),再让模型按格式填。这套机制的可靠性来自约束——不是求模型好好说话,而是让它只有一种说话方式。

4.2 数据提取与结构化输出

本节摘要:让模型"顺便看看"和"正式取证"是两回事。提取类武器配合 Pydantic 字段模型,能把页面信息压成带类型约束的 JSON——字段名你定、格式它守、错了重试。本节给出字段建模模板、提取代码、翻页续取与嵌套结构三个实战形态。

从"随口汇报"到"记录在案"

问模型"这页卖什么",它回一段话,读着挺顺,可你没法把一段话塞进数据库。第 3 章说过观察拍负责"看见",本节是把看见的东西记录在案:先定义证据格式(有哪些字段、什么类型、哪些必填),再让模型按格式填。这套机制的可靠性来自约束——不是求模型好好说话,而是让它只有一种说话方式。

图:结构化提取的管道——从页面到可入库数据

图:结构化提取的管道——从页面到可入库数据

字段建模三原则

合同立得不好,提取就废。三条原则:

  1. 字段名即任务:写"价格"模型会犹豫含不含运费,写"页面标示的到手价"就没歧义——字段名同时是给模型的需求说明;
  2. 能窄则窄:价格用数值型别用字符串,数量用整型别用文本,类型越窄复核越有力;
  3. 可缺字段给默认:页面上不一定有的信息(如"是否限时")声明为可选并给默认值,别让一个缺项卡死整单。
from pydantic import BaseModel class 商品条目(BaseModel): 名称: str # 页面上显示的商品全名 到手价: float # 页面标示的当前售价,不含运费 是否包邮: bool = False # 有"包邮"标识则为真,缺省按不包邮 评分: float | None = None # 部分商品无评分,允许为空 class 商品列表(BaseModel): 条目: list[商品条目] # 整页多条,套一层列表

提取任务全码

把合同交给 Agent,任务单只负责划定范围:

from browser_use import Agent, Browser from browser_use import Controller from langchain_openai import ChatOpenAI controller = Controller(exclude_actions=[]) # 提取靠内置提取动作,无需自定义 agent = Agent( task=( "打开演示商城的搜索结果页(关键词:机械键盘)," "提取第一页全部商品的名称、到手价、是否包邮、评分," "不要点进任何商品详情页" ), llm=ChatOpenAI(model="gpt-4o", temperature=0.1), browser=Browser(), controller=controller, structured_output=商品列表, # 挂上合同:产出必须符合商品列表结构 ) result = agent.run(max_steps=8) print(result)

预期输出为符合合同的 JSON(示意):

{"条目": [ {"名称": "素盾K87", "到手价": 99.0, "是否包邮": true, "评分": 4.6}, {"名称": "铁臂K100", "到手价": 149.0, "是否包邮": false, "评分": null} ]}

拿到这串东西,直接序列化入库,不需要任何正则清洗。

翻页续取与嵌套结构

翻页续取用 3.3 的粒度拆解:一页一仗,仗仗交割,主循环里把各页 JSON 拼起来。比"一单翻五页"稳定得多——某页翻失败只重打那一页。

all_rows = [] for page in range(1, 6): agent = Agent( task=( f"打开搜索结果第{page}页,提取本页商品(字段同前)," "只提取不点击" ), llm=llm, browser=browser, structured_output=商品列表, ) r = agent.run(max_steps=8) all_rows.extend(解析出条目(r)) # 解析函数按实际返回结构写 print(len(all_rows)) # 预期:与五页实际条目总数一致

嵌套结构(商品加评论、订单加明细)是同一套打法的加深:外层模型套内层模型,字段名照旧写清语义。但别贪深——层级超过两层,模型的填表错误率明显上升,此时该考虑先提外层、再开子任务提内层。

取舍段

提取类武器适合"量不大、结构杂、页面常变"的场景:几十个页面、字段五花八门、明天就改版——模型提取的适应性完胜写死的选择器。不适合"量大海且结构稳定"的场景:十万条同构列表页,一个选择器脚本的成本是它的百分之一。记得 1.3 的口诀,两者从来是搭档而不是对手。

提取三问

**问:字段越多越好吗?**不是。每加一个字段,填表错误率就抬一分,尤其可选字段多的时候——模型会倾向"都填点什么"。原则:入库要什么就定什么,"顺便也拿一下"的字段全部砍掉。真要扩展,改合同重跑的成本很低,别在一张合同上贪大求全。

**问:数字拿回来变成字符串怎么办?**先查合同——字段声明为 float 时框架会强制转换,转不了的会打回重试。若你自己写的是字符串类型又想排序计算,那就是合同的锅不是模型的锅。类型收紧是免费的质检,别浪费。

**问:空值算失败还是算正常?**在合同里显式表态:允许为空的字段给默认值并写明语义("无评分时为空"),不允许为空的字段不设默认——缺了就打回。最怕的是既没默认也没约束,空值静默入库,到分析阶段才发现整列是空的,6.3 里那个"静默漂移"病例就是这么来的。

什么时候该放弃提取、改用导出

很多站点自带导出功能(下载报表、发送邮件)。能用导出就用导出:一次下载的数据完整性远高于逐字段提取,成本还低。提取武器的主场是"页面根本不提供导出"的场景——判断顺序永远是:先接口(1.3),再导出按钮,最后才是模型逐页提取。

合同也要迭代:版本化的习惯

字段合同不是一次定稿的宪法,它随业务理解加深而改版——这周发现还需要"促销标签",下周发现"评分"其实没人用。给合同留版本习惯:改动记一行(日期、改了什么、为什么),旧版存档。别小看这一行字:三个月后数字对不上时,"合同什么时候改的"永远是第一个要查的问题。合同版本与巡检基准(5.3)配合时更是刚需——字段变了,基准比对逻辑必须同步知道。

武器库最后一件:给军械库添自造装备——自定义动作,顺便把危险操作锁进人工闸门。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U