[开源] 做了一个面向 AI 代理的 Web 自动化库:双引擎(HTTP + 浏览器)+ 声明式动作,让 AI 像人一样浏览网页 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
riceball
V2EX    分享创造

[开源] 做了一个面向 AI 代理的 Web 自动化库:双引擎(HTTP + 浏览器)+ 声明式动作,让 AI 像人一样浏览网页

  • /li>  
  •   riceball 48 天前 1802 次点击
    这是一个创建于 48 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近一直在折腾 AI Agent ,发现让 Agent 可靠地与 Web 交互是个大难题,现有工具要么太底层,要么不够灵活。所以动手撸了一个轮子: **@isdk/web-fetcher**,想和大家分享一下,也希望能得到一些反馈。

    解决了什么痛点?

    你可能会问,为啥不用 fetch 或 Playwright/Crawlee ?

    • fetch 拿不到 JS 动态渲染的内容,对现代网页基本没用。
    • Playwright 虽然强大,但需要写大量命令式的过程代码 (await page.click(...) 等),不仅繁琐,而且 AI (比如 LLM) 很难直接生成这种复杂的逻辑。

    我不想重复造轮子,所以底层用了Crawlee来处理。

    我的目标是在 Crawlee 之上构建一个跨引擎一致性:抽象/模拟 HTTP 与 Browser 的共有行为,声明式的“意图层”,让 AI 可以通过生成简单的 JSON 来“指挥”浏览器完成任务,而不是去写具体的执行代码。

    核心功能

    • 双引擎架构: 你可以选择 http 模式(基于 Cheerio )来极速抓取静态内容,也可以用 browser 模式(基于 Playwright )来处理复杂的动态网页。
    • 统一的操作模型 (核心设计): 这是最关键的一点。我抽象了 httpbrowser 模式下的共性行为。无论底层用哪个引擎,你都使用同一套 actions API 。比如 extract (提取数据) 这个操作,在 http 模式下它会通过 Cheerio 解析静态 HTML ,在 browser 模式下它会操作浏览器渲染后的 DOM 。你只需要学习一套 API ,库在内部完成了适配和翻译
    • 声明式操作脚本: 基于统一的模型,你可以用 JSON 定义一个多步骤任务流(登录、填表、点击),AI 生成这个 JSON 的成本远低于生成 JS 代码。
    • 强大的数据提取: 同样是声明式的 Schema ,轻松从页面提取结构化数据。
    • 内置反爬: browser 模式下开启 antibot: true,能处理一些常见的 Cloudflare 挑战。
    • 易于扩展: 可以自己封装常用的操作,比如把“登录知乎”封装成一个 loginToZhihu 的自定义动作。

    快速上手:提取个标题

    注意,下面的代码不关心目标 URL 是静态还是动态的,extract 操作在两种模式下都有效。

    import { fetchWeb } from '@isdk/web-fetcher'; async function getTitle(url: string) { const { outputs } = await fetchWeb({ url, actions: [ { id: 'extract', params: { selector: 'title', // 提取 <title> 标签内容 }, storeAs: 'pageTitle', // 结果存到 outputs.pageTitle }, ], }); console.log('页面标题:', outputs.pageTitle); } getTitle('https://www.v2ex.com'); 

    进阶玩法:多步表单提交 (Google 搜索)

    这个例子展示了如何用 JSON 指挥浏览器执行一系列动作。

    import { fetchWeb } from '@isdk/web-fetcher'; async function searchGoogle(query: string) { const { result } = await fetchWeb({ url: 'https://www.google.com', engine: 'browser', // 显式指定需要浏览器环境 actions: [ // 步骤 1: 找到输入框并填入内容 { id: 'fill', params: { selector: 'textarea[name=q]', value: query } }, // 步骤 2: 提交表单 { id: 'submit', params: { selector: 'form' } }, // 步骤 3: 等待搜索结果容器加载出来 { id: 'waitFor', params: { selector: '#search' } }, ] }); console.log('搜索结果页 URL:', result?.finalUrl); } searchGoogle('V2EX'); 

    项目状态

    项目刚起步,核心架构已经搭好。下一步计划是实现更智能的抓取策略(比如发现 http 模式拿不到内容时,自动升级到 browser 模式)。

    项目是开源的,欢迎大家试用、Star 、提 Issue ,或者狠狠地拍砖!感谢。

    6 条回复    2025-11-03 09:48:10 +08:00
    v2zhao
        1
    v2zhao  
       48 天前
    有意思 已 star
    closedevice
        2
    closedevice  
       48 天前
    有意思,周末看下,另外有对比过 chrome-mcp 的实现么?
    riceball
        3
    riceball  
    OP
       48 天前
    @closedevice chrome-mcp 没看到过,不过看到过基于 playwright 做的 MCP,太过简单.
    zhouxiaodi
        4
    zhouxiaodi  
       47 天前 via iPhone
    大佬,我有点没看懂这个库的用法。它是怎么跟 AI 结合的?我把这个库的语法告诉 AI ,让它给我生成 JSON 格式的代码,最后执行这个代码,是吗?
    riceball
        5
    riceball  
    OP
       47 天前   1
    @zhouxiaodi 对,本质上就是这样,这只是一个底层函数库。最终上面就是封装为 ai 的 tool func ,让它在需要的时候调用。
    defunct9
        6
    defunct9  
       45 天前
    记录一下,回头试试
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1197 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 17:42 PVG 01:42 LAX 09:42 JFK 12:42
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86