ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

DeerFlow web_capture 实现计划与源码解析:基于 Browserless 的网页截图取证工具

DeerFlow web_capture 实现计划与源码解析:基于 Browserless 的网页截图取证工具 DeerFlow web_capture 实现计划与源码解析基于 Browserless 的网页截图取证工具【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow本文基于 DeerFlow 仓库中的实现计划文档 2026-06-29-community-browserless-web-capture.md完整呈现web_capture工具的设计目标、配置契约、Browserless/screenshotAPI 映射、文件与 Artifact 边界、错误处理策略以及 TDD 执行任务并结合已落地的 browserless_client.py 与 tools.py 源码说明计划如何转化为可运行的代码与测试。目标与总体架构该计划要解决的问题很具体为 DeerFlow 增加一个可选启用opt-in的社区工具web_capture它调用 Browserless 的/screenshot接口用无头 Chrome 渲染目标 URL把 PNG/JPEG/WebP 截图保存到当前线程的 outputs 目录并将文件以 DeerFlow 标准 Artifact 路径暴露给用户。计划中定义的架构分工计划文档 Architecture 一节BrowserlessClient负责 HTTP 请求构造与二进制响应处理tools.py负责 DeerFlow 运行时/配置解析、输出文件名生成、文件持久化和 artifact 状态更新不发明新的 artifact 通道而是复用既有的 thread-data outputs 语义。技术栈为Python 3.12、LangChain tool 装饰器、LangGraphCommand、httpx.AsyncClient、Browserless REST/screenshot、pytest。当前仓库中该计划已完整落地代码位于deerflow.community.browserless包内包导出见init.pyfrom .browserless_client import BrowserlessClient from .tools import web_capture_tool, web_fetch_tool __all__ [BrowserlessClient, web_capture_tool, web_fetch_tool]用户可见的工具契约配置块工具通过config.yaml的tools列表声明计划给出的契约如下与当前 config.example.yaml 中的注释块一致tools: - name: web_capture group: web use: deerflow.community.browserless.tools:web_capture_tool base_url: http://localhost:3032 timeout_s: 30 output_format: png full_page: true viewport_width: 1280 viewport_height: 720 # token: $BROWSERLESS_TOKEN # wait_for_selector: main # wait_for_selector_timeout_ms: 5000 # wait_for_timeout_ms: 1000 # best_attempt: true仓库实际提供的示例配置还补充了两个安全相关项见 config.example.yaml# - name: web_capture # group: web # use: deerflow.community.browserless.tools:web_capture_tool # base_url: http://localhost:3032 # Browserless instance URL (Docker: http://browserless:3000) # # token: $BROWSERLESS_TOKEN # Required for Browserless Cloud; optional for self-hosted # timeout_s: 30 # Request timeout in seconds (timeout also accepted) # output_format: png # png, jpeg, or webp # full_page: true # Capture entire page instead of viewport only # viewport_width: 1280 # viewport_height: 720 # # wait_for_selector: main # CSS selector to wait for before capturing # # wait_for_selector_timeout_ms: 5000 # # wait_for_timeout_ms: 1000 # Extra wait after navigation in milliseconds # # best_attempt: true # Continue with current page state if waits time out # # allow_private_addresses: false # SSRF guard: keep false in production. Set true ONLY to # # # capture internal/private targets (loopback, RFC1918, etc.)其中allow_private_addresses是计划落地过程中加入的 SSRF 防护开关详见下文安全加固一节。模型可调用的函数签名计划刻意把暴露给模型的参数面收窄async def web_capture_tool( runtime: Runtime, url: str, tool_call_id: Annotated[str, InjectedToolCallId], filename: str | None None, full_page: bool | None None, output_format: str | None None, viewport_width: int | None None, viewport_height: int | None None, ) - Command:对应行为约定只接受显式的http:///https://URL截图保存到runtime.state[thread_data][outputs_path]指向的目录返回一个Command向状态追加虚拟 artifact 路径/mnt/user-data/outputs/filename和一条简短的ToolMessage可选参数缺省时回落到工具配置默认值Browserless 凭证优先读配置的token否则读BROWSERLESS_TOKEN环境变量。tools.py 的实现与契约逐项对应tool(web_capture, parse_docstringTrue)装饰器声明工具名_get_browserless_client(web_capture)内部先查BROWSERLESS_TOKEN再被配置块中的token覆盖_resolve_timeout()同时接受timeout_s和兄弟 providercrawl4ai/jina_ai常用的timeout键避免用户照抄其他 provider 片段时因键名不同而静默落到默认值——这是从源码注释中可以直接读到的兼容性设计。Browserless API 映射Browserless 官方接口的请求形态是POST /screenshotJSON 体形如{ url: https://example.com/, options: { fullPage: true, type: png } }响应为二进制图片流Content-Type依options.type取image/png、image/jpeg或image/webp。waitForSelector、waitForTimeout、bestAttempt等共享字段位于请求体顶层。本期支持字段计划明确支持字段来源url模型入参options.fullPage模型入参或配置full_pageoptions.type模型入参或配置output_formatoptions.quality仅 jpeg/webp 且配置了quality时viewport配置/入参的宽高组合waitForSelector配置wait_for_selectorwaitForTimeout配置wait_for_timeout_msbestAttempt配置best_attemptcapture_screenshot() 的载荷构造与这张表一一对应quality仅在非空时写入optionsviewport、waitForSelector包装为{selector: ..., timeout: ...}、waitForTimeout、bestAttempt按顶层字段追加。本期刻意不暴露的字段计划明确不支持inlinehtml、addScriptTag、addStyleTag、认证 profile、任意启动参数、代理参数。理由写得直接这些字段虽然有用但直接暴露给 agent 会显著提高产生意外副作用或凭证/会话泄漏的概率后续如确有需求可置于显式配置之后再加。从源码结构看这一约束是硬边界——capture_screenshot()的参数列表里没有对应入口agent 无法绕过。认证方式token 作为查询参数与同包的fetch_html_with_status()把 token 放进 JSON 载荷不同capture_screenshot()遵循当前 Browserless/screenshot文档把 token 作为查询参数发送params {token: self.token} if self.token else None ... resp await client.post( f{self.base_url}/screenshot, jsonpayload, paramsparams, ... )文件与 Artifact 边界工具写入的位置由ThreadDataMiddleware提供的宿主机侧 outputs 路径决定文件写入经asyncio.to_thread卸载到线程池避免阻塞事件循环thread_data runtime.state.get(thread_data) or {} outputs_path thread_data.get(outputs_path)最终面向用户的 artifact 路径固定为/mnt/user-data/outputs/safe-filename.ext计划规定的文件名规则显式给了filename时剥掉目录部分并归一化为安全 stem未给时从 URL 的 host/path 派生可读 stem再追加 UTC 时间戳扩展名一律由output_format决定最终 basename 只允许 ASCII 字母、数字、点、连字符、下划线。tools.py 的实现完整继承了这些规则并在此之上又加了一层计划未写的防撞机制——_dedupe_output_name()同名文件已存在时依次尝试-1、-2后缀上限 1000 次探测确保显式文件名永远不会静默覆盖更早的截图探测上限被触顶时回落到带微秒时间戳的后缀。此外默认 stem 由 URL 的 netloc 路径段以连字符拼接并截断到 80 字符_default_capture_stem最终 stem 截断到 100 字符超出字符经_SAFE_FILENAME_RE替换为下划线。错误处理与结果模型计划规定BrowserlessClient.capture_screenshot()不抛出预期内的 API/网络错误而是返回一个小的结果对象客户端对外失败时返回以Error:开头的字符串与既有fetch_html()的字符串契约保持一致dataclass(frozenTrue) class BrowserlessScreenshotResult: content: bytes content_type: str target_status_code: str target_status: str final_url: str预期失败场景均返回Error:字符串非 200 的 Browserless 响应、空的图片响应、超时、请求错误。工具层把任何错误字符串原样转成ToolMessage且不改动 artifacts意外异常被记录日志后以Error: ...形式返回。源码与计划逐条对应并额外利用了 Browserless 的X-Response-*响应头target_status_code/target_status取自X-Response-Code/X-Response-Statusfinal_url取自X-Response-URL。这一点很重要因为 Browserless 对渲染请求本身返回 200即使目标页面是 4xx/5xx 或反爬拦截页。为此 tools.py 中的_target_status_warning()会在成功消息后追加(warning: target page responded 404 Not Found)之类的提示防止 agent 把渲染成功误判为页面正常。安全加固SSRF 防护原计划对 URL 的约束只是只接受显式 http(s)落地实现在此之上引入了完整的 SSRF 守卫。_validate_capture_url() 委托给deerflow.community.url_safety.validate_public_http_url配合真实 DNS 解析器resolve_host_addresses默认拒绝解析到回环、私网、链路本地含云元数据端点 169.254.169.254、保留、多播或 unspecified 地址的请求只有运维显式配置allow_private_addresses: true才放行。CONFIGURATION.md 对该默认行为有专门说明生产环境应保持false仅在确有内部目标时才开启。这一层校验发生在任何 Browserless 调用之前——非法 URL 不会消耗一次远程请求。TDD 测试策略计划要求以 TDD 方式推进测试集中在 test_browserless_client.py当前该文件包含 95 处与web_capture/capture_screenshot/Browserless相关的断言与用例。客户端测试断言capture_screenshot向/screenshot发送url、options.fullPage、options.type、viewport与各 wait 字段token 通过token查询参数发送非 200 状态返回带状态码与响应片段的错误字符串空二进制内容返回明确错误。工具测试断言成功调用时字节写入outputs_path且Command.update[artifacts]含 artifact 路径工具读取的是web_capture配置块而非web_fetch非法 URL 在调用 Browserless 之前即被拒绝运行时缺少线程 outputs 时返回清晰错误且不写任何文件不安全文件名被归一化为 outputs 下的 basename。工具测试的构造方式按计划使用假 runtimestate{thread_data: {outputs_path: str(tmp_path)}}并打补丁_get_browserless_client()与_get_tool_config()使整个测试在不需要真实 Browserless 实例的情况下可离线运行。配置、Doctor 与文档联动计划列出的配套更新在仓库中均已就位config.example.yaml新增注释态web_capture配置块与 Jina/Crawl4AI 等web_fetchprovider 并列且注明 Docker 部署应把base_url指向服务名如http://browserless:3000。backend/docs/CONFIGURATION.md工具列表中加入web_capture并给出自托管 Browserless 的完整操作链路——用 Docker 起实例容器内 3000 端口映射到 3032与默认base_url对齐新版镜像强制 token需显式设置、导出BROWSERLESS_TOKEN、用curl直接打/screenshot验证实例可达docker run -d --name browserless -p 3032:3000 -e TOKENlocal-dev-token ghcr.io/browserless/chromium export BROWSERLESS_TOKENlocal-dev-token curl -sS http://localhost:3032/screenshot?tokenlocal-dev-token \ -H Content-Type: application/json \ -d {url: https://example.com, options: {type: png}} \ -o /tmp/browserless-check.png # 成功时写出一张 PNGscripts/doctor.py新增check_web_capture()检查项web capture configured并把web_capture纳入 provider 令牌映射browserless → BROWSERLESS_TOKEN/ 配置内token对自托管实例base_url不含browserless.io会标记 token 为可选避免误报。init.py导出web_capture_tool。执行任务与验证清单计划把实现拆成 6 个 TDD 任务每个任务都标注了目标文件与预期红/绿状态任务内容目标文件Task 1先写失败客户端测试预期红状态为AttributeError: BrowserlessClient object has no attribute capture_screenshotbackend/tests/test_browserless_client.pyTask 2实现BrowserlessScreenshotResult与capture_screenshot()保持fetch_html()行为不变browserless_client.pyTask 3写失败工具测试假 runtime 打补丁客户端/配置backend/tests/test_browserless_client.pyTask 4实现web_capture_tool及配置查找、URL 校验、格式校验、文件名清洗、虚拟 artifact 路径等辅助函数tools.py、init.pyTask 5更新config.example.yaml、scripts/doctor.py、CONFIGURATION.md 与中英文前端文档配置/脚本/文档Task 6验证与自审—Task 6 的验证命令cd backend uv run pytest tests/test_browserless_client.py -q cd backend uv run ruff check packages/harness/deerflow/community/browserless tests/test_browserless_client.py cd backend uv run ruff format --check packages/harness/deerflow/community/browserless tests/test_browserless_client.py计划还附了一份人工审查清单其中每一条都能映射到已落地的实现约束上改动不越出范围文件、不产生提交web_capture只读web_capture配置块工具不暴露 inline HTML、脚本/样式注入与 Browserless profile文件只写入当前线程 outputs 路径错误路径不改动 artifacts。小结这篇计划文档的价值在于它把一个给 agent 装眼睛的社区功能拆到了可验证的粒度窄参数契约防 agent 滥用、显式支持/拒绝的 API 字段清单防凭证与会话泄漏、固定虚拟 artifact 路径复用既有 outputs 语义而非新建通道、字符串化的错误契约与既有 provider 工具一致以及配套的配置示例、doctor 检查与自托管验证命令。对照 browserless 包源码 可以看到实现还在此之上补了两处计划未覆盖但工程上必要的加固——SSRF 守卫与目标页状态码告警——使web_capture既能安全地指向公网又不会把渲染服务的 200 误当作目标页面的成功。【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表