
每天上班第一件事就是打开十几个网页查招标公告、盯政策补贴、刷一下企业有没有新增诉讼再搜一圈行业竞品动态。这些动作重复、耗时而且特别适合交给程序——但传统爬虫脚本只能抓“定死的页面”页面结构一变就失效更不用说从杂乱网页里提炼出“这条信息和我的业务有没有关系”。这次我们要解决的就是让 AI 自己完成这个流程定时上网、搜索目标关键词、阅读网页内容、用大模型做结构化提取最后把结果汇总成一份可读的报告。它不是某个现成的商业软件而是一套可以自己搭建的 AI Agent 自动化方案。整套系统以 Python 为主依赖浏览器自动化和 LLM API可以跑在本地电脑上也可以放到服务器里长期运行。本文会拆解这套“AI 自动上网找项目、找钱、查风险”系统的完整技术方案先看核心能力与适用边界再给出环境准备、代码实现、定时任务配置、API 封装和批量任务扩展。所有代码都是可直接改用的通用模板你需要替换成自己的目标站点、搜索关键词和 LLM API Key。如果你的目标不只是信息搜集还想研究多智能体协作和 Agent 长期记忆文末也会给出一个开源项目作为扩展参考。1. 核心能力速览能力项说明项目类型AI Agent 自动化信息搜集与结构化分析核心功能定时上网搜索、网页内容抓取、LLM 信息提取、结果汇总与通知技术栈Python Playwright/Selenium LLM API 定时任务调度硬件要求调用云端 LLM 时本地不需要独立显卡本地跑模型时需按模型规格确认显存启动方式命令行脚本运行配合 cron / APScheduler / Windows 任务计划定时触发接口能力可以封装为 FastAPI 服务对外提供 HTTP 接口批量任务支持多关键词、多站点、多轮调度和结果去重合并适用场景项目线索搜集、招投标信息监控、政策补贴跟进、企业风险舆情合规边界仅用于合法信息搜集数据来源需遵守目标网站协议结果需人工复核这套方案的最大特点是不需要从零训练模型网页抓取由 Playwright 这类浏览器自动化工具完成信息理解交给 LLM API你的核心工作只是把“任务定义”写清楚——搜索什么、关注什么、输出成什么格式。因此部署门槛比大多数人想象的低。2. 适用场景与使用边界2.1 适合解决什么问题对商务、创业者、投融资人员和风险相关岗位来说每天的信息搜集工作可以拆成三个固定动作找项目线索、找资金和补贴信息、查目标对象的经营风险。这三个动作都很适合做成 AI Agent 的日常任务。找项目每天自动搜索招标信息、政府采购公告、产业园区招商通知等。找钱定时跟政策申报网站、基金公告、补贴公示等页面。查风险监控企业新增诉讼、行政处罚、经营异常、股权变更等信息。如果把这些任务做成脚本每天早上自动跑一轮输出一份 Markdown 或 JSON 格式的晨报能省下至少一小时的重复劳动。2.2 不适合什么场景这套方案不擅长获取需要账号权限才能访问的数据也不适合对抓取结果做一锤定音的判断。LLM 会存在幻觉网页解析可能漏字段所以它定位是“信息搜集助手”不是“自动决策系统”。如果要用在正式风控报告、投资决策或招投标制作环节最终判断必须由人来复核。2.3 合规与安全边界自动上网抓取数据时必须注意以下几点遵守目标网站的 robots 协议和用户条款不抓取登录墙后的受保护内容。控制抓取频率不对目标站点造成访问压力。不破解验证码、不绕过访问控制。遇到验证码时应该暂停任务人工介入或换用合规数据源。涉及企业工商信息、个人数据时确认数据来源是否允许再加工和存储。抓取的内容只用于合法商业决策不对外二次贩卖。3. 技术方案与系统设计整套系统的设计可以拆成四层每一层职责单一方便单独替换和调试。3.1 任务调度层调度层负责决定“什么时候跑、跑哪些任务”。最简单的是直接用操作系统的 cron或者用 Python 的 APScheduler。任务定义通常用配置文件管理包含任务名、搜索关键词、目标 URL、执行频率、通知渠道。3.2 数据采集层采集层负责“上网拿内容”。这里优先推荐 Playwright因为它基于真实 Chromium 内核不容易被基础的反爬规则拦截也能处理 JavaScript 动态渲染的页面。如果是纯静态页面用 requests BeautifulSoup 更轻量能减少内存占用。3.3 信息提取层采集到的 HTML 不能直接丢给大模型因为 token 消耗会很大。建议先用可读性分析把网页正文提取出来做敏感信息截断再交给 LLM 做结构化提取。让模型输出固定的 JSON 格式例如{title: ..., date: ..., risk_type: ..., summary: ...}。3.4 结果存储与通知层每轮任务的结果先写入本地文件或 SQLite避免程序中断丢数据。然后生成汇总摘要推送到钉钉机器人、飞书机器人、企业微信群机器人或邮件。推送内容不宜过长给关键字段和原文链接即可。下面按这个分层结构给出完整的部署与实现步骤。4. 本地部署环境准备4.1 系统与语言环境Windows、macOS、Linux 都可以运行。需要提前装好 Python 3.10 或更高版本并保证终端里可以执行python命令。python --version4.2 安装依赖建议创建独立虚拟环境避免依赖冲突。python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate然后安装核心依赖pip install playwright openai apscheduler beautifulsoup4 httpx playwright install chromium说明playwright负责浏览器自动化和网页抓取。openai虽然包名是 openai但现在大多数国内 LLM 服务都兼容 OpenAI 格式换 Base URL 就能用。apscheduler负责定时任务调度。beautifulsoup4负责解析 HTML、提取网页正文。httpx用于请求接口和发送通知。如果你的目标站点全部是静态页面不装 Playwright 也可以直接用requests就行。但从通用性考虑Playwright 更能应对动态页面。4.3 配置 LLM API Key去你选择的模型服务商控制台申请 API Key记录 Base URL 和模型名称。常见的推理模型、对话模型都能完成结构化提取任务关键在于提示词要写清楚输出格式。export LLM_API_KEYyour-api-key export LLM_BASE_URLhttps://api.example.com/v1 export LLM_MODELyour-model-name也可以把这些变量写入.env文件用python-dotenv加载。4.4 目录结构规划建议用下面的结构组织工程避免运行几天后文件到处乱放ai_agent_scout/ ├── config.yaml ├── requirements.txt ├── agent.py ├── scheduler.py ├── api_server.py ├── data/ │ ├── results/ │ └── logs/ └── tasks/ ├── project_search.py └── risk_monitor.py无头模式下抓取的数据都落在data/results日志统一写到data/logs。这样排查问题时会省很多时间。5. 核心代码实现5.1 任务配置用 YAML 管理多任务是最方便的方式。新增一个监控方向时不需要改代码直接加配置即可。# config.yaml tasks: - name: project_tender keywords: - 智慧园区 招标 - 数字化 政府采购 target_urls: - https://example.com/tender schedule: 0 8 * * * output_format: json - name: risk_monitor keywords: - 目标公司名 经营异常 - 目标公司名 行政处罚 target_urls: - https://example.com/company schedule: 0 9 * * * output_format: json llm: api_key_env: LLM_API_KEY base_url_env: LLM_BASE_URL model_env: LLM_MODEL temperature: 0.1 storage: result_dir: data/results log_dir: data/logs注意temperature要设低一点结构化提取任务需要确定性输出温度越高越容易编造内容。5.2 搜索与网页抓取模块这里用 Playwright 打开搜索引擎或目标站点取回页面内容。核心是两件事定位搜索框、输入关键词、回车、等待结果。# agent.py import asyncio from playwright.async_api import async_playwright async def search_page(keyword: str, search_url: str) - str: async with async_playwright() as p: browser await p.chromium.launch(headlessTrue) page await browser.new_page() try: await page.goto(search_url, timeout60000) await page.fill(input[nameq], keyword) await page.press(input[nameq], Enter) await page.wait_for_timeout(3000) content await page.content() return content finally: await browser.close()如果你的目标站点是固定的结果页 URL可以跳过搜索框定位直接把关键词拼进 URL 访问这样更稳定# 示例把关键词做 URL 编码后拼接到搜索地址 from urllib.parse import quote def build_search_url(base_url: str, keyword: str) - str: return f{base_url}?q{quote(keyword)}5.3 网页正文提取模块拿到 HTML 之后先清洗去掉 script、style 标签再取正文区域。用 BeautifulSoup 可以快速完成。from bs4 import BeautifulSoup def extract_text(html: str, max_chars: int 3000) - str: soup BeautifulSoup(html, html.parser) for tag in soup([script, style, nav, footer, aside]): tag.decompose() text soup.get_text(separator\n, stripTrue) return text[:max_chars]截断这一步很重要。网页全文可能几万字塞进 LLM 会浪费 token还会稀释关键信息。先限制在 3000 字符以内后续如果发现漏信息再针对具体页面放大。5.4 LLM 结构化提取模块from openai import OpenAI import json client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL), ) def extract_with_llm(text: str, task_desc: str) - dict: prompt f 你是一个信息提取助手。请根据下面的任务描述提取关键信息。 任务描述{task_desc} 网页正文 {text} 要求输出 JSON字段包括 - title: 标题 - date: 日期 - is_relevant: 0 或 1是否与任务相关 - summary: 200 字以内的摘要 - risk_level: 高 / 中 / 低 / 无 只输出 JSON不要输出其他内容。 resp client.chat.completions.create( modelos.getenv(LLM_MODEL), messages[{role: user, content: prompt}], temperature0.1, response_format{type: json_object}, ) return json.loads(resp.choices[0].message.content)如果使用的模型服务不支持response_format参数就去掉这一行并在提示词里强调“只输出 JSON”。否则解析时容易因为模型输出了额外文字而报错。5.5 完整任务执行流程把搜索、提取、存储串起来def run_task(task: dict): keyword task[keywords][0] html asyncio.run(search_page(keyword, task[target_urls][0])) text extract_text(html) result extract_with_llm(text, task[name]) save_result(task[name], result)实际使用中一个关键词可能对应多个搜索结果页需要循环处理如果结果太多还要做去重。5.6 定时任务调度用 APScheduler 实现每日定时执行from apscheduler.schedulers.blocking import BlockingScheduler import yaml def load_tasks(): with open(config.yaml, r, encodingutf-8) as f: return yaml.safe_load(f) def scheduled_job(task): try: run_task(task) log(success, task[name]) except Exception as e: log(error, f{task[name]}: {e}) if __name__ __main__: config load_tasks() scheduler BlockingScheduler() for task in config[tasks]: scheduler.add_job(scheduled_job, cron, hour8, minute0, args[task]) scheduler.start()如果不依赖 Python 进程也可以直接用系统 cron# 每天早上 8 点执行 0 8 * * * cd /path/to/project .venv/bin/python scheduler.py data/logs/cron.log 216. 功能测试与效果验证系统跑起来之后不要直接放量监控先按下面的顺序做验证。6.1 单条抓取测试先用单任务、单关键词、单页面跑通最小链路python agent.py --task project_tender --keyword 智慧园区 招标预期结果终端能看到搜索页面被打开、正文被截断、LLM 返回 JSON、结果写入data/results。任何一步失败都会有明确报错。判断标准is_relevant字段基本准确summary能概括网页关键信息。6.2 结构化输出准确性测试准备 10 条人工标注过的网页样本让 LLM 提取对比字段准确率。重点看三个问题日期是否识别正确。无关信息是否被过滤is_relevant0。摘要是否出现事实性错误。如果准确率不理想优先调整提示词给模型更多字段示例不要一上来就换模型。6.3 定时任务测试把 cron 时间改成当前时间后 1 分钟观察任务是否能准时触发。确认跑通后再改回正式时间。6.4 失败恢复测试在抓取阶段故意传入一个不存在的 URL确认程序能捕获异常并记录日志而不是直接崩溃。这样可以确保以后某个目标网站改版时整个调度任务不会停摆。7. 接口 API 与批量任务扩展如果不想只在本机跑可以封装成 HTTP 接口让其他系统调用。7.1 FastAPI 服务封装# api_server.py from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class TaskRequest(BaseModel): task_name: str keywords: list[str] target_urls: list[str] app.post(/run_task) def create_task(req: TaskRequest): task { name: req.task_name, keywords: req.keywords, target_urls: req.target_urls, } run_task(task) return {status: ok, message: task finished}启动服务uvicorn api_server:app --host 127.0.0.1 --port 80007.2 curl 调用示例curl -X POST http://127.0.0.1:8000/run_task \ -H Content-Type: application/json \ -d { task_name: risk_monitor, keywords: [目标公司 经营异常], target_urls: [https://example.com/company] }7.3 Python 调用示例import requests url http://127.0.0.1:8000/run_task payload { task_name: project_tender, keywords: [智慧园区 招标, 数字化 政府采购], target_urls: [https://example.com/tender], } resp requests.post(url, jsonpayload, timeout300) print(resp.json())7.4 批量任务设计批量任务的核心不是加快抓取速度而是做好任务隔离。建议每个任务独立日志文件失败重试最多 3 次间隔递增import time def run_with_retry(task, max_retries3): for attempt in range(max_retries): try: run_task(task) return True except Exception as e: log(error, fattempt {attempt 1}: {e}) time.sleep(10 * (attempt 1)) return False并发控制也要注意。如果多个任务同时启动Playwright 会拉起多个浏览器进程内存压力会很大。更稳妥的方式是任务队列串行执行或者设置最多 2 个并发。8. 资源占用与性能观察这套方案的资源占用主要集中在采集层而不是模型推理层。云端 LLM API 方案本地不占用显存主要消耗 CPU、内存和网络带宽。每个 Playwright 浏览器进程大约占用 200-400MB 内存具体要看页面复杂度。本地 LLM 推理方案需要按模型规格确认显存要求。比如部分 7B 参数的量化模型需要 6GB 以上显存13B 以上模型需要更多。这一项必须以你实际部署的模型为准不要根据经验直接买卡。CPU 占用多数时间很低任务跑起来时浏览器渲染和页面解析会短时拉高 CPU。降低资源占用的三个方法使用无头模式并且每次用完立即关闭浏览器避免进程残留。减小正文截断长度比如 3000 字符改为 1500 字符能明显减少 LLM 调用时间和 token 消耗。控制调度频率。信息类站点没必要每小时抓一次早晚各一次通常足够。抓太频繁反而容易被限制。观察资源占用时可以盯三个指标任务执行耗时、LLM API 的 token 消耗、磁盘目录大小。这三个指标最能反映系统是否健康。9. 常见问题与排查方法问题现象可能原因排查方式解决方案启动后页面打不开端口冲突或 chromium 未安装查看终端报错执行playwright install chromium更换端口或重新安装浏览器内核搜索结果页返回 403目标站点有基础反爬检查是否触发频率限制换无头模式或加等待时间降低抓取频率必要时换数据源遇到登录验证码目标页面需要账号权限无法自动绕过记录日志并跳过该页面改用公开页面或由人工登录后执行LLM 返回内容无法解析成 JSON模型输出带额外文字或 response_format 不支持打印原始返回值去掉response_format在提示词中强调只输出 JSON定时任务不触发时区设置错误或进程未常驻查看data/logs/cron.log用crontab -l确认任务检查系统时区改用 APScheduler 并保持进程运行内存持续升高浏览器进程没关闭或有异步任务泄漏查看系统进程确认 chromium 残留在finally里关闭 browser限制并发数多个关键词重复结果同一信息在多个页面出现对比结果 title 和 URL按 titleURL 做本地去重摘要出现事实错误提示词约束不足或正文截断导致上下文缺失检查截断后的文本是否包含关键信息优化正文提取逻辑或调整截断位置10. 最佳实践与合规建议10.1 工程化建议第一次跑通后马上做三件事固定一套最小可运行配置备份requirements.txt和config.yaml以后环境再乱也能快速恢复。把抓取结果按日期建目录例如data/results/2025-01-01/避免历史结果被覆盖。在结果里记录抓取时间和来源 URL既方便回溯也方便日后排查信息准确性问题。10.2 提示词调优同样的模型提示词写得好不好效果差距很大。结构化提取任务的提示词应该包含任务背景、输入格式、输出字段、字段示例、禁止行为。例如面试官式的要求“只输出 JSON”一定要写否则模型很容易在 JSON 前后加说明文字。10.3 合规红线自动上网搜集公开信息本身是合法技术应用但不能越过几条红线不访问需要账号密码才能获取的数据不抓取个人隐私数据。不破解验证码、不绕过反爬机制、不影响目标站点正常服务。不把搜集到的信息用于投诉、骚扰、抹黑他人等不当用途。商业场景下对外发布或使用信息前确认版权和授权范围。10.4 人工复核机制每天生成的 AI 晨报建议留出 10 分钟人工过一遍。重点看摘要是否有歧义、风险等级是否合理、是否有明显误报。系统只是把信息从“散落各处”变成“集中一处”最终判断还是要靠人。11. 总结与下一步这套“AI 自动上网找项目、找钱、查风险”的方案最有价值的地方不是单个技术点而是把浏览器自动化、LLM 结构化提取、定时调度和消息通知组合成了一个可以长期跑的闭环。先做单任务验证跑通后再加关键词、加站点、加通知渠道是最稳的推进路径。最容易踩的坑有三个一是忽略正文截断token 消耗过大二是没做失败重试某个网站改版后整个任务停摆三是提示词没有约束输出格式解析代码频繁报错。这些都在前面的章节里给出了具体解决方式。如果你把自动上网跑顺之后想继续研究 AI Agent 的行为决策和多智能体协作可以关注 GitHub 上的开源项目https://github.com/mewamew/my_ai_town。它属于 AI 小镇类的 Agent 环境模拟项目适合用来观察多个智能体在环境里的自主行为和记忆机制对理解 Agent 长期任务执行和状态管理会有不少启发。建议先把今天的方案跑通输出第一份 AI 晨报再决定要不要往多 Agent 方向深挖。系统稳定运行后你会慢慢发现每天最耗时间的“开网页找信息”动作终于可以一键交给机器了。