尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CrawlEyes开源:为AI Agent补齐网页视觉感知短板

CrawlEyes开源:为AI Agent补齐网页视觉感知短板 给 AI Agents 一双「眼睛」CrawlEyes 开源了做 Agent 相关开发的朋友应该都有同感模型能力早就不是瓶颈了真正的瓶颈是 Agent 在网页面前是个半瞎子。你给它一段 HTML它读得懂结构却不知道按钮长什么样、弹窗有没有挡住点击区域、页面滚动之后元素跑到哪去了。CrawlEyes 这个项目开源的意义就是把这个半瞎子的视觉缺口补上——它不是爬虫框架也不是又多了一个多模态模型而是夹在浏览器自动化与 LLM 推理之间的一层视觉适配器。这篇文章我会从它要解决的问题出发把设计思路、上手方式、核心机制和我实测踩过的坑完整讲一遍适合正在做网页型 Agent、自动化测试脚本、RPA 类工具的同学参考。1. Agent 缺的不是大模型是看清楚页面的能力先说一个判断我见过非常多团队把 Agent 做不好归结为模型不够聪明然后去换更大的模型、调更长的上下文结果问题根本没解决。因为对于一个需要操作网页的 Agent 来说它最缺的其实是你我都默认拥有、却很少被当作工程问题来对待的一项能力——视觉。人在操作网页时眼睛负责两件事一是定位目标二是确认状态。扫一眼就知道右上角是头像、红色按钮是退出、弹出遮罩说明有弹窗。这件事我们做得毫不费力所以很少意识到想让 Agent 做到同样的程度背后要拆掉多少堵墙。1.1 三种主流方案的短板目前让 Agent 感知网页市面上无非三种思路我挨个说下它们的痛点。第一种是纯 HTML/DOM 解析。把页面源码塞给模型让它从标签里找按钮、找表单。问题在于真实页面的 DOM 噪音极其严重——一堆埋点 div、样式节点、懒加载容器模型要在一两万行标签里揪出真正可交互的元素误判率相当高。而且很多内容是 JavaScript 渲染出来的直接抓 HTML 压根看不到。第二种是整页截图 多模态模型。用视觉语言模型去看截图确实能看见但成本高、延迟大最要命的是精度不稳定。你让模型在 4K 截图上指出确定按钮的像素坐标它经常给你偏出去二三十像素这种误差在真实点击场景里就是点错按钮。第三种是手写 DOM 选择器。用 XPath、CSS Selector 把每个要操作的元素写死。这确实稳但带来一个新的尴尬——你都把选择器写死了还要 Agent 干什么这本质上还是传统自动化脚本LLM 只是扮演了一个参数填充器。1.2 CrawlEyes 选择的位置CrawlEyes 选择了第四条路不替代上面任何一种而是在它们之间做一层融合。它通过浏览器自动化内核拿到实时的 DOM 结构和渲染后的页面截图然后把两者对齐为页面上每一个可交互元素生成一个稳定的、带坐标和区域信息的视觉锚点。Agent 拿到的不再是冰冷的 HTML 字符串而是一张我看得懂、坐标我算得准的页面地图。所以在阅读后面所有内容之前先建立一个基本认知CrawlEyes 不是又一个爬虫也不是模型本身它是一双负责看的手——用工程手段让 Agent 获得接近人类的眼睛同时把看的成本压到纯文本解析的量级。2. 核心设计把网页变成一张 Agent 能理解的视觉坐标地图我在刚接触 CrawlEyes 时最先被吸引的就是它的核心数据结构设计思路。它把整个页面抽象成一张图层叠加的地图而不是简单地把截图和 DOM 扔给模型。这个设计的起点很朴素人类的视觉系统和浏览器的文档结构本来就是两套坐标系。眼睛看到的是像素矩阵而下层代码理解的是节点树。之前的方案要么只看像素截图给模型要么只看文档树文本给模型CrawlEyes 做的事情是把这两套系统对齐到同一个空间里。2.1 视觉锚点到底是什么在 CrawlEyes 里一个视觉锚点Visual Anchor是页面上某个可交互元素的最小完整描述单元。它包含四部分信息元素在截图上的边界框坐标、它在 DOM 树里的路径、它的语义标签以及它周围的视觉上下文摘要。举个例子一个登录按钮在 CrawlEyes 的眼中是这样被描述的{ anchor_id: anchor_8f3a2c, bounding_box: { x: 820, y: 640, width: 120, height: 44 }, dom_path: html/body/div[2]/form/button[1], semantic_label: 登录 / Sign In, context: 位于页面中部表单区域红色主按钮左右无相邻操作项, state: enabled, intersection: { covered_by_modal: false, visible_ratio: 1.0 } }Agent 拿到这一整个快照数组之后再结合任务描述去决定点哪个、怎么点、点完看哪里。这比让它去原始 HTML 里找目标要可靠得多。2.2 DOM 与视觉层对齐的技术关键地图设计里最难的不是截图也不是解析 DOM而是如何让两者对上。这里有一个非常实际的工程难点页面上任何一个元素它的 CSS 位置会受滚动、响应式布局、动态渲染、弹层影响。同一个登录按钮在 1366 宽和 1920 宽的屏幕上坐标完全不同。CrawlEyes 解决这个问题的思路是以渲染结果为基准。它不自己去猜元素在哪而是借助浏览器内核的标准 API 拿到每个元素渲染后的实际几何信息再反算回截图坐标系。这样天然规避了 CSS 布局计算的各种兼容性问题——浏览器自己最清楚自己画出来的是什么。我听作者在社区分享时说最初他们也试过在 Node 端自己实现布局推算后来发现这完全是重复造轮子不同浏览器引擎的布局差异会让所有坐标全废。最终定位策略改成让浏览器自己报坐标稳定性一下子提升了几个量级。3. 从零跑通安装环境与首个看得见的 Agent聊完设计直接上实操。我用的是 Python 3.10 的环境系统是 Ubuntu 22.04浏览器内核基于 Chromium 做渲染。这套组合在 CI 环境里也比较省心。3.1 安装过程里最容易卡住的一步CrawlEyes 的 Python 包本身安装很简单pip install crawleyes但如果你以为装完就能跑那就太天真了。它依赖独立的浏览器内核这一步在不同系统上坑很多。Linux 上最常见的问题是缺系统库实测下来必须装齐下面这些sudo apt-get install -y libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 \ libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 \ libxfixes3 libxrandr2 libgbm1 libasound2 libpango-1.0-0Windows 和 macOS 用户通常不会有这个问题但 Linux 服务器上跑自动化这步几乎是必踩的。我建议从头就用一个干净的 Docker 镜像来装别在已经装了一堆东西的机器上试依赖冲突排查起来会非常痛苦。3.2 最小可运行示例装好之后最简用法大概是这样——给 Agent 打开一个页面生成视觉锚点图from crawleyes import CrawlEyesSession session CrawlEyesSession(headlessTrue) # 打开目标页面 session.goto(https://example.com/login) # 获取视觉锚点快照 snapshot session.capture_snapshot() # 直接查看当前页面里有哪些可以点的元素 for anchor in snapshot.visual_anchors: print(anchor.anchor_id, anchor.semantic_label, anchor.bounding_box)跑通这一步你的 Agent 就算真正睁开眼了。capture_snapshot 返回的 snapshot 对象里除了视觉锚点数组还包括页面标题、URL、当前视口尺寸、页面整体截图以及每个锚点对应的元素文本。我建议你完成的第一个练习是把某个自己常用的网站首页打开打印出所有锚点对照截图看看识别准不准。你会发现在真实站点上锚点的数量和可交互元素的数量几乎一一对应这种感觉比看任何文档都更能建立信任感。4. 功能拆解Agent 是如何盯着页面完成动作的跑通 Demo 之后我们需要理解整个循环的内部机制。只有一个快照不算眼睛真正的眼睛是一个持续运转的闭环看 — 决策 — 操作 — 再看。CrawlEyes 在这个闭环里扮演的是前半个看字以及操作之后的复看。4.1 先看后动的完整流程拿一个最常见的场景举例让 Agent 完成一次登录操作。第一步Agent 收到任务登录后先调 capture_snapshot 拿到当前页面的视觉锚点地图。第二步LLM 根据锚点里的语义标签和坐标决定要点击 id 为 anchor_8f3a2c 的那个元素。第三步Agent 调用 session.click_anchor(anchor_8f3a2c)CrawlEyes 解析出该锚点此刻的真实坐标驱动浏览器点击。注意这里有一个容易忽略的设计点击时不是直接用快照里的坐标而是重新查询元素当前坐标。这很关键因为从快照到执行之间有延迟页面可能因为动画或布局偏移已经把元素挪走了。实时重查坐标可以把这类误差降到最低。第四步Agent 输入完账号密码点登录页面开始跳转。第五步Agent 再次调用 capture_snapshot对比前后两张快照确认是否登录成功。你会发现这个循环里 CrawlEyes 做得最聪明的设计是对状态变化的表达。它不会把整个页面的新旧快照全部交给模型去对比而是直接算出来一张差异清单——哪些元素消失、哪些元素出现、哪些元素位置变了、标题是否改变。模型只需要读这份清单就能判断操作是否生效省掉大量 token也减少了长上下文带来的幻觉。4.2 动作回放与失败自纠另一个让我觉得实用的是动作回放机制。在任务执行过程中CrawlEyes 会把每一步操作都记录成一个可回放的事件序列包含操作类型、目标锚点、执行前后快照摘要。一旦某一步执行失败它不会让 Agent 盲目重试而是把失败位置的快照单独拿出来生成一份重试建议。这个建议不是简单地把报错抛给模型而是说尝试点击登录按钮时目标元素被一个弹窗遮罩覆盖可见率仅为 0.15%建议先关闭弹窗或调整目标。Agent 看到这种反馈下一步决策就会很有方向感而不是瞎猜。这就是眼睛和手配合默契之后的效果——眼睛不仅负责看还要把看到的障碍告诉手。5. 高频踩坑记录动态内容、遮挡元素与误判锚点再好的工具拿到真实环境里都会露馅。我前后在十几个不同站点上跑过 CrawlEyes下面三类问题出现频率最高每个都是真实的坑排查思路分享出来供参考。5.1 动态加载导致的锚点漂移第一个坑是动态内容。现在大量页面采用滚动加载或者接口返回之后才渲染列表项。第一次 capture_snapshot 时列表还没渲染锚点地图里根本没有目标元素。我的做法是配合显式等待机制来用。CrawlEyes 提供了 wait_for_anchor 方法可以指定等待某个语义标签出现。但这里有个坑不要干等而是要等待之后再做一次完整的快照刷新。我会这样组织流程session.wait_for_anchor(用户列表项, timeout10) snapshot session.capture_snapshot() anchors [a for a in snapshot.visual_anchors if a.semantic_label 用户列表项]第一次直接等完就抓结果发现列表项可见但位置全不在预期区域。后来排查明白了——页面先渲染了骨架屏占位元素和内容元素语义标签相近锚点匹配到了骨架屏节点。解决办法是等待条件加细不只是等语义标签还要等元素的 visible_ratio 达到 0.9 以上或者等某个业务特征文本出现。5.2 弹窗遮挡导致点击落空第二个高频坑是弹窗遮挡。页面右下角突然弹出的客服邀请、Cookie 提示条、优惠券弹层都会把目标按钮挡住。CrawlEyes 的锚点对象里有个字段叫 intersection.covered_by_modal但它的判断依赖浏览器对遮挡的精确计算遇到某些用 CSS 动画缓慢出现的弹层第一次检查时可能还没判定为遮挡点下去就落在了弹层上。这个问题我建议用双层校验点击之前先检查锚点的 covered_by_modal 和 visible_ratio如果发现疑似遮挡先执行一次扫除动作——查找页面上是否存在语义为关闭、“我知道了”、“Accept”的按钮并优先点击。这比让模型每次都去分析当前复杂弹窗更省 token实测成功率也更高。5.3 相似元素误判与去重第三个坑在于页面里大量相似元素。电商网站的商品卡片每个卡片都有加入购物车按钮二十个商品的语义标签完全一样。这时候如果 Agent 只是按语义标签去找必然找错。CrawlEyes 的做法是给每个锚点编号Agent 在决策时不能只说点击加购按钮而要说点击 anchor_xx 对应的加购按钮。但模型真的会搞混编号特别是一屏十几个相似卡片疯狂复制时。我做了个小优化在 Agent 的提示词里要求它先描述目标元素的上下文特征比如位于标题为某商品的那个卡片上的按钮再带上 anchor_id。这样即使编号有偏差校验层也能根据上下文二次确认。用表格总结一下这三类问题问题类型表现关键排查点我的处理思路动态加载漂移元素找不到或位置不准锚点匹配到了占位/骨架元素等待条件细化等待后重新生成完整快照弹窗遮挡点击落空或点到弹层遮挡判定滞后于动画点击前校验可见率发现遮挡先扫除弹窗相似元素误判点错同类型按钮锚点编号被模型记混提示词要求带上文描述决策层二次确认6. 开源路线与后续定位为什么这样的项目必须开放最后聊点项目层面的。CrawlEyes 从发布起就直接把核心代码开源了这在我来看不是营销动作而是这类项目天然的正确选择。原因很实际网页环境的复杂度远超任何一家团队的测试覆盖范围。只有开源让各种真实站点、各种浏览器版本、各种作妖的页面进来体检视觉锚点的稳定性才能真正立起来。6.1 开放协作能解决什么举一个例子。我在内测阶段遇到过一个俄罗斯站点页面里嵌了一段非标准 SVG 图标CrawlEyes 生成的锚点区域偏差很大。换做商业闭源项目我只能提工单等排期。但在开源协议下我可以直接看代码定位到它的区域合并算法没有处理 SVG 内嵌套 text 节点的情况自己提一个 PR 就修掉了。这种事在网页自动化领域每天都在发生因为前端技术实在太散、太快、太不守规矩。另一个开放协作的价值在于协议生态。现在 CrawlEyes 的锚点快照格式是公开的意味着任何人都可以基于这个格式去写模型适配层、任务编排层、测试断言层。我是一个 Agent 框架的开发者我只要按这个快照格式做解析就不用关心浏览器内核的琐碎细节直接在上层做自己的调度逻辑。这个标准格式 开源内核的组合让整个生态里的人各干各擅长的部分。6.2 我建议的下一步方向作为一个实际使用者我特别期待两个方向能继续推进。一个是移动端 H5 页面的适配。现在移动端网页的可访问性差异比桌面端更大尺寸适配、触摸事件、软键盘弹出对布局的挤压都会让锚点稳定性变差这需要大量真机测试数据来打磨。另一个是降低接入门槛。目前想用好 CrawlEyes还是需要对快照数据结构和浏览器自动化有一定了解。如果能提供一套开箱即用的 Agent 框架示例——比如一个直接跑在 FastAPI 上的、能接管页面操作的服务——会让非专业爬虫工程师也能快速用起来。我个人在实际部署时还有一个感触不要一上来就让 CrawlEyes 处理重度交互场景。先从信息采集 简单点击这类轻任务开始跑跑顺了再逐步加复杂度。我在生产环境里先用它做了一批定时巡检任务稳定运行两周之后才放开了更多操作权限。这种渐进式上线的思路对任何引入网页自动化能力的团队都适用。
返回列表