用 browser-use 纯 DOM 提取京东商品:踩坑与一根本地代理解决 Gemini 断连

用 browser-use 纯 DOM 提取京东商品:踩坑与一根本地代理解决 Gemini 断连

最近在折腾用 browser-use 自动抓取京东搜索结果,过程中把”browser-use 必须靠视觉模型””免费模型跑不动 Agent””Gemini 动不动断连”这几个误区逐一踩了一遍。本文记录完整的排查思路和最终可复用的方案,给同样在这条路上卡住的人省点时间。

误区一:browser-use 需要视觉模型才能”看懂”页面?

不是。browser-use 的默认工作模式(use_vision=False)只读 DOM 快照——也就是页面的 HTML 文本结构和元素文本——交给 LLM 做决策和提取。视觉模型(use_vision=True)只是在页面布局特别复杂、需要”看截图”时才加的辅助,每一步还会多烧一次视觉调用。

我们的任务很固定:打开京东搜索页 → 读商品列表。URL 已知、结构已知,LLM 做”下一步点哪、滚不滚、提取完没”的决策在这里其实是冗余开销,但 DOM 提取本身完全不依赖视觉。结论:纯 DOM 模式不仅可行,还比视觉模式省 token

误区二:免费模型撑不住 browser-use Agent?

半对。Agent 每步确实要调一次 LLM 做决策,免费模型连续跑十几步会撞配额。但真正让我前面反复崩溃的,不是限流,是传输层断连——下面详细说。

真正的坑:Gemini genai SDK 经 SOCKS5 的 “Server disconnected”

我的环境出网走本地 SOCKS5 隧道(127.0.0.1:1080,日本 OCI 出口)。genai SDK(google.genai)默认会用 HTTPS_PROXY=socks5://... 直连,问题是它对 Gemini 是长连接,免费档响应慢时连接池被掐断,抛出 ServerDisconnectedError。每步都崩,Agent 自然跑不完。

我用 curl 走同样的 SOCKS5 却稳如老狗——说明隧道本身没问题,是 genai/httpx 的 SOCKS5 长连接实现有坑。

修复:一根无超时的本地 HTTP 代理

写一个纯标准库的小代理,监听 127.0.0.1:8899,把请求经 SOCKS5 转发出去。关键两点:

  1. 不设硬超时:旧版本给每条连接设了 15 秒超时,Gemini 慢响应直接被掐。改成 settimeout(None),让连接活到自然结束。
  2. 正确处理 CONNECT 隧道:HTTPS 走 CONNECT 方法建隧道,双向 pipe 转发,不在应用层解析内容。

genai 改成走 HTTPS_PROXY=http://127.0.0.1:8899,本地 TCP 稳定不断。实测连打 6 次 Gemini:ok=6 fail=0,零断连。

另一个坑:Chrome 不能走这个代理

如果进程级把 HTTPS_PROXY 设成 8899,browser-use 起的 Chrome 也会经由它访问京东——而京东是国内直连 IP,被 HTTP 代理一裹反而连不上,browser-use 的 watchdog 30 秒超时直接崩。

修复:给 Browser 加参数强制 Chrome 直连,只让 genai 走代理:

browser = Browser(
    executable_path=CHROME,
    headless=False,
    args=['--proxy-server=direct://', '--proxy-bypass-list=*'],  # Chrome 直连国内站
    storage_state=STORAGE,
    viewport={'width': 1280, 'height': 800},
)

genai 的环境变量代理和 Chrome 的直连参数各管各的,互不干扰。

登录态与那个无害的警告

browser-use 用 storage_state 注入京东 cookie(一次扫码登录后导出)。它会打印一条警告:

⚠️ BrowserSession was passed both storage_state AND user_data_dir…

意思是它内部自动建了个临时 user_data_dir,和你的 storage_state 撞了。实测无害storage_state 会正确覆盖临时目录的 cookie,登录态正常、商品能提取。显式传 user_data_dir=None 也消不掉这个警告(它内部会再补一个),而且不要为了消警告改用 user_data_dir=真实路径 + storage_state=None,那样会丢登录态

最终方案

import asyncio, os
from browser_use import Browser, Agent
from browser_use.llm.google.chat import ChatGoogle

KEY = open('/Users/ai/.gemini_key').read().strip()
os.environ['HTTPS_PROXY'] = 'http://127.0.0.1:8899'   # genai 走本地代理
os.environ['HTTP_PROXY']  = 'http://127.0.0.1:8899'
os.environ['ALL_PROXY']   = 'http://127.0.0.1:8899'

llm = ChatGoogle(model='gemini-flash-lite-latest', api_key=KEY,
                 temperature=0.0, max_output_tokens=8096, max_retries=10)

browser = Browser(executable_path=CHROME, headless=False,
                  args=['--proxy-server=direct://', '--proxy-bypass-list=*'],
                  storage_state=STORAGE, viewport={'width':1280,'height':800})

agent = Agent(task=task, llm=llm, browser=browser, use_vision=False,
              max_failures=20, max_actions_per_step=2, llm_timeout=180, retry_delay=3)
history = await agent.run(max_steps=12)

运行:

HTTPS_PROXY=http://127.0.0.1:8899 HTTP_PROXY=http://127.0.0.1:8899 \
ALL_PROXY=http://127.0.0.1:8899 NO_PROXY='localhost,127.0.0.1' \
python jd_dom_agent.py

京东商品选择器:列表 .gl-item / #J_goodsList li.gl-item,标题 .p-name,价格 .p-price .price,店铺 .p-shop a。跑出来就是干净的前 10 商品表格,全程零视觉调用、免费 Gemini key 稳定驱动。

小结

  • browser-use 不用视觉模型、纯 DOM 就能干活,文本模型读 HTML 结构足够;
  • Gemini 断连根因是 genai 直连 SOCKS5 长连接不稳,一根无超时本地 HTTP 代理完美绕开;
  • Chrome 必须显式直连国内站,否则会被代理拖崩;
  • “both storage_state AND user_data_dir” 警告无害,别动它。

本文由 AI 辅助生成

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理

滚动至顶部