Java 让 AI 自己爬网页存数据MCP 这个新玩意儿真好用一、又是我这次想让 AI 帮我扒数据前阵子搞个小需求每天从竞品网站抓一些公开的产品参数整理后写进数据库然后让 AI 帮我做分析。传统做法很无聊写个爬虫把数据跑下来清洗好再拼成 Prompt 喂给大模型。整个过程我管 80% 的脏活累活AI 就最后动动嘴皮子。我就在想能不能让 AI 直接去扒数据你说“去把 XX 页面的价格爬下来存库里”它自己就去干了全程我不管。还真能。最近 Anthropic 搞了个东西叫MCPModel Context Protocol说白了就是一套让大模型调用外部工具的协议。你把“爬虫”包装成工具AI 就能直接用了。今天就结合 Java 把这条链路跑一遍代码都给你。二、MCP 是什么说人话别被名词吓住。MCP 就干一件事定义了一套 Client 和 Server 之间的通信标准让 AI 模型可以像调函数一样调用你写好的“工具”。架构长这样你的 Java 应用AI 模型 ←— MCP Client —→ MCP Server你写的工具MCP Server 里可以注册多个工具比如web_fetch爬取网页文本save_to_db存数据库web_search联网搜索AI 模型能自己决定在什么时候调用哪个工具。你只需要用 Java 实现这些工具注册到 Server 上剩下全交给模型。最关键的是它和模型无关。你用 GPT、Claude、DeepSeek只要是支持 Function Calling 的模型都能接。三、动手前的技术选型目前 Java 生态里有两个选择用 Spring AI 的 MCP 支持Spring AI 1.0 M3 之后内置了 MCP Client 和 Server 的抽象适合 Spring 项目直接用官方 SDKAnthropic 提供了 Java 的 MCP SDKio.modelcontextprotocol不挑框架。我这为了最快出活用了官方 SDK Spring Boot。Spring Boot 负责起服务和依赖注入MCP Server 单独跑一个端口。整体依赖!-- MCP Server 官方SDK --dependencygroupIdio.modelcontextprotocol/groupIdartifactIdmcp-server/artifactIdversion0.4.0/version/dependency!-- 爬虫用 Jsoup --dependencygroupIdorg.jsoup/groupIdartifactIdjsoup/artifactIdversion1.18.1/version/dependency!-- 数据库随便我用 MyBatis-Plus --dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.7/version/dependency四、写一个 MCP Server注册工具MCP Server 启动后会通过 JSON-RPC 跟 Client 通信。我们要做的是定义工具并注册进去。先写工具类把爬虫和存储逻辑都放在里面importorg.jsoup.Jsoup;importorg.jsoup.nodes.Document;importorg.springframework.stereotype.Component;importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importjavax.annotation.Resource;ComponentpublicclassWebTools{ResourceprivateProductDataMapperproductDataMapper;/** * 工具爬取网页纯文本 */publicStringfetchWebPage(Stringurl){try{DocumentdocJsoup.connect(url).userAgent(Mozilla/5.0).timeout(10000).get();// 只取正文文本去掉 script/stylereturndoc.body().text();}catch(Exceptione){return爬取失败: e.getMessage();}}/** * 工具将产品数据存入数据库 */publicStringsaveProductData(StringproductName,Stringprice,StringsourceUrl){ProductDatadatanewProductData();data.setProductName(productName);data.setPrice(price);data.setSourceUrl(sourceUrl);data.setCreateTime(LocalDateTime.now());productDataMapper.insert(data);return已保存productName 价格price;}/** * 工具查询已存的产品列表 */publicStringqueryProducts(Stringkeyword){ListProductDatalistproductDataMapper.selectList(newQueryWrapperProductData().like(product_name,keyword));if(list.isEmpty())return没找到相关产品;returnlist.stream().map(p-p.getProductName() : p.getPrice()).collect(Collectors.joining(\n));}}然后在配置类里启动 MCP Server把这些方法注册为工具importio.modelcontextprotocol.server.*;importio.modelcontextprotocol.server.transport.StdioServerTransport;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importjavax.annotation.PostConstruct;ComponentpublicclassMcpServerStarter{AutowiredprivateWebToolswebTools;PostConstructpublicvoidstart(){McpServerserverMcpServer.create();// 注册工具爬取网页server.addTool(McpTool.newBuilder().name(web_fetch).description(爬取指定URL的网页文本内容).inputSchema(JsonSchema.builder().addProperty(url,JsonType.STRING,要爬取的网页地址).required(url).build()).handler(params-{Stringurlparams.get(url).getAsString();StringresultwebTools.fetchWebPage(url);returnToolCallResult.success(newTextContent(result));}).build());// 注册工具保存数据server.addTool(McpTool.newBuilder().name(save_product).description(将产品信息保存到数据库).inputSchema(JsonSchema.builder().addProperty(productName,JsonType.STRING,产品名称).addProperty(price,JsonType.STRING,价格).addProperty(sourceUrl,JsonType.STRING,来源URL).required(productName,price,sourceUrl).build()).handler(params-{StringresultwebTools.saveProductData(params.get(productName).getAsString(),params.get(price).getAsString(),params.get(sourceUrl).getAsString());returnToolCallResult.success(newTextContent(result));}).build());// 注册工具查询数据库server.addTool(McpTool.newBuilder().name(query_products).description(按关键字查询已保存的产品数据).inputSchema(JsonSchema.builder().addProperty(keyword,JsonType.STRING,产品名称关键字).required(keyword).build()).handler(params-{StringresultwebTools.queryProducts(params.get(keyword).getAsString());returnToolCallResult.success(newTextContent(result));}).build());// 使用 STDIO 传输启动也可用 HTTP SSEserver.start(newStdioServerTransport());}}到这里MCP Server 已经跑起来了。它通过标准输入输出跟客户端通信也可以用 HTTP SSE但 STDIO 最简单。五、让 AI 调用这些工具MCP Client 我直接用 Python 写了因为很多 MCP Client 库最成熟负责连接上面的 Java Server并调用大模型。但按你公众号的尿性你们肯定要 Java 的。Java 侧的 MCP Client 示例importio.modelcontextprotocol.client.McpClient;importio.modelcontextprotocol.client.transport.StdioClientTransport;publicclassAiClient{publicstaticvoidmain(String[]args){// 连接刚才的 Java MCP Server启动命令McpClientclientMcpClient.withTransport(newStdioClientTransport(java -jar your-mcp-server.jar)).build();// 列出可用工具client.listTools().forEach(t-System.out.println(t.getName(): t.getDescription()));// 调用工具示例StringpageContentclient.callTool(web_fetch,Map.of(url,https://example.com/product/123));System.out.println(pageContent);}}但要让 AI 自动决策就得把 MCP 工具列表发给大模型比如 GPT-4让模型根据用户指令自己选工具。这部分标准流程是这样的把工具列表转成 Function Calling 的定义用户说“去XX网站爬下价格存起来”发给大模型模型返回它想调的工具名和参数你用 MCP Client 执行该工具把结果再发给模型模型根据结果回复用户“已经存好了XX 价格是 XX”。这些逻辑可以封装在一个 Service 里。因为篇幅不展开但核心就是MCP 负责工具的统一调用AI 负责决策。六、进阶用 MCP 实现“AI 上网自由”上面是最小闭环。更高级的玩法是注册一个web_search工具接上 Bing API 或 SearXNG那 AI 就真能自主搜索爬取存储了。我前几天就试了一次对它说“帮我把最近一周‘Java 25 新特性’的文章标题和链接抓过来存库里”它自己搜、自己爬、自己存我就喝茶等着。那一刻感觉真值。踩坑提醒MCP Server 如果用 STDIO 模式启动命令必须非常可靠否则 Client 连不上爬虫注意遵守 robots.txt别给人家服务器压力大模型挑选工具有时会抽风Prompt 里最好加一句“优先使用 web_fetch 工具”数据库操作记得加事务爬了半天下不来别写个残废数据进去。七、总结以前给 AI 加能力得写一堆胶水代码拼 JSON。现在 MCP 出来把“工具”标准化了Java 这边实现一次多种 AI 都能用。核心就三步用 Java 写工具类爬虫、存库注册到 MCP Server定义好参数 SchemaAI 通过 MCP Client 调用这些工具自主决策。对于后端来说这玩意儿就是“可以让 AI 调你的业务接口”的工程化方案一点都不虚。别再手动抓数据拼 Prompt 了把爬虫扔给 AI你会发现自己像个在幕后操控一切的大反派爽得很。