Java 也能让 AI 自己操作浏览器抓数据

周末想看看 Java 能不能跟上”AI 自己操作浏览器”这波潮流,顺手把 langchain4j 的 Playwright 集成跑了一遍。日志里跳出来的东西让我愣了一下:模型不是简单读懂了网页,而是真的在”操作”:先导航,再决定怎么取文本,最后才开始总结。

Playwright 是什么?

Playwright,微软出的浏览器自动化框架,测试工程师用得多:写脚本控制 Chrome、Firefox、Webkit,模拟点击、输入、截图。在 langchain4j 里,它被包了一层,从”测试工具”变成了大模型的”手脚”。

Playwright 在 langchain 里扮演什么角色

具体分三层,由内而外:

  • BrowserExecutionEngine:浏览器执行引擎接口,定义了”导航””点击””取文本”这些动作的标准形态
  • PlaywrightBrowserExecutionEngine:用 Playwright 的 Java API 把上面的接口实现出来,真正去操控浏览器的是它
  • BrowserUseTool:把引擎再包一层,变成大模型能”看懂”的工具,模型只需要说”我要 NAVIGATE 到某个地址”,剩下的事交给工具去落地

三层叠起来,模型就有了一双能在浏览器里”动手”的手,不用再去拼 XPath、等元素加载。

快速开始

先把依赖加上。这套组合需要两个模块,分别管”引擎”和”工具”:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-browser-execution-engine-playwright</artifactId>
<version>1.16.0-beta26</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-tool-browser-use</artifactId>
<version>1.16.0-beta26</version>
</dependency>

模型这边我用的是 DeepSeek-V4-Flash

1
2
3
4
5
6
7
ChatModel model = OpenAiChatModel.builder()
.baseUrl("https://api.deepseek.com")
.apiKey(System.getenv("DEEPSEEK_API_KEY"))
.modelName("deepseek-v4-flash")
.logRequests(true)
.logResponses(true)
.build();

接下来把浏览器启动起来,包装成引擎和工具,最后塞进 AiServices

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Playwright playwright = Playwright.create();
BrowserType.LaunchOptions options = new BrowserType.LaunchOptions()
.setHeadless(false)
.setChannel("chrome")
.setChromiumSandbox(true)
.setSlowMo(500);
Browser browser = playwright.chromium().launch(options);

Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(model)
.tools(BrowserUseTool.from(
PlaywrightBrowserExecutionEngine.builder().browser(browser).build()))
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();

String question = "open page 'https://pig4cloud.com', and summary the page text";
System.out.println(assistant.chat(question));

链路其实就四步:Playwright.create() 拿到浏览器实例 → 包成 PlaywrightBrowserExecutionEngine → 再包成 BrowserUseTool → 注册进 AiServices,配上一份十条消息容量的对话记忆。最后那句平平无奇的 assistant.chat(question),背后却要跑完一整条”模型自己规划怎么用浏览器”的链路。

setHeadless(false) 我特意留着,开发阶段能看到浏览器窗口真的在自己动,调试的时候比盯着日志直观得多。第一次跑还会顺手把 Chromium、Firefox、Webkit 都下载一遍,加起来快 400MB,建议先去倒杯水。

执行过程分析

真正有意思的是日志里实际发生的事。我让它执行的任务很简单:打开 pig4cloud.com,总结页面内容。但没人告诉它该怎么做,剩下的全靠它自己拆解。

第一轮,模型收到任务后,reasoning_content 里留了一句大白话:

“The user wants me to open the page ‘https://pig4cloud.com‘ and summarize the page text. Let me start by navigating to that URL.”

于是它发起了第一次工具调用:browser_useNAVIGATE 动作,参数是目标网址。工具执行完,回了一句”Action ‘NAVIGATE’ executed successfully”。

第二轮,模型看到导航成功,又琢磨了一句:”Good, the page loaded. Let me get the text content of the page.”紧接着,它发起了 GET_TEXT 调用。这次工具返回的是整段页面正文,从”PIGCLOUD / AI + 微服务开发”的标题一路到底部的版权信息,几千字纯文本原样塞进了对话历史。

第三轮,模型才真正开始”干活”:把刚抓到的文本嚼碎了,整理成一份带小标题、带表格的结构化摘要,从产品定位、核心能力、技术架构一路讲到客户案例这样的数据都原样保留了下来。

把这三轮串起来看,会发现模型其实是在先弄清目标,再选该用哪个动作,看到结果之后再决定下一步。整个过程没有一行硬编码的”页面加载完成就取文本”,全靠模型自己一步步推演。这也是 Agent 和传统脚本式 RPA 最大的差别:脚本把每一步都写死,Agent 只给目标,路径让它自己摸。

写在最后

这套组合的好处很直接:原来需要懂 Selenium、会写 XPath、要处理各种页面加载时序的活儿,现在变成了一句自然语言。对 Java 团队来说,意味着可以把”操作网页”这件事彻底交给模型去规划,自己只需要管好工具的边界和安全沙箱。

它也不是万能的。setSlowMo(500) 这种参数已经在提醒我们:模型每走一步都要经过一次完整的请求-响应往返,速度比写死的脚本慢得多,复杂页面上的元素定位也未必总能一次成功。日志里那次任务,光是”打开页面、抓文本、出摘要”三轮对话就花了将近九秒,换成手写脚本,这点活儿眨眼就完事。