惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
Scott Helme
Scott Helme
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
P
Privacy & Cybersecurity Law Blog
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
Martin Fowler
Martin Fowler
Cisco Talos Blog
Cisco Talos Blog
罗磊的独立博客
MyScale Blog
MyScale Blog
博客园 - 【当耐特】
L
LangChain Blog
AWS News Blog
AWS News Blog
Security Latest
Security Latest
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Proofpoint News Feed
T
True Tiger Recordings
aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享
月光博客
月光博客
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
The GitHub Blog
The GitHub Blog
Stack Overflow Blog
Stack Overflow Blog
S
SegmentFault 最新的问题
Recorded Future
Recorded Future
S
Security Archives - TechRepublic
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
Y
Y Combinator Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
博客园 - 聂微东
GbyAI
GbyAI
N
News and Events Feed by Topic
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
Last Week in AI
Last Week in AI
博客园 - 三生石上(FineUI控件)
G
Google Developers Blog
A
About on SuperTechFans
K
Kaspersky official blog
NISL@THU
NISL@THU
S
Securelist
Microsoft Azure Blog
Microsoft Azure Blog
V
V2EX - 技术

V2EX

[问与答] token 用量究竟是怎么算的? 香港众安银行开户返 300HKD+50USD 英伟达股票兑换券 活动时间 5.28 日至 7.1 日截止。 vibe coding 了个辅助颈腰椎病康复的体态相机小工具 有在用免费 VPS 的吗?可以当梯子用吗? 这个 sechub 网站搬运了很多 V 站的内容,站方能管到它吗 我的 AI(LLM) 和 vibe coding 使用技巧已经落伍了吗 我做了一个 Agent Team 协作平台——Rudder:让 Agent Team 在实践中成长 react 这个技术栈到底是如何做到每天都有新发现的? 我终于找到了 24 小时进行 coding 的终极方法,你可以在帖子当中看到最佳的 Vibe coding 助手 我不想看你的产出 Anker 已经不是原来的 Anker 了,从苹果生态到饭圈生意,一路从龙头企业做到现在韭菜头子。 [产品发布] [产品自荐] 业余两周做了个 AI Visual Agent,自动选模型、写 prompt、调参数,想请 V 友帮忙看看 [深圳] 居家办公距离南山科兴地铁 50 分钟有推荐的小区吗 [推广] 📊 [抽奖+1] 多券商开户福利(万 0.854/两融低至 3.x),回帖抽 coding plan 欢迎各位分子 AirPods4 降噪版在地铁上的表现实在糟糕,关门声差点我把送走 [酷工作] 远程 AI 前端招聘 30-50K 活过来了,继续推广一下我的 codex 中转站,依旧免费送 30 刀 复杂内网里的 WebRTC + gRPC 音视频通话方案:信令、媒体链路与自恢复 寻找 App 平台规则与技术合规咨询顾问 / 团队 做了个宠物拍立得风格照片生成器,给你的猫狗来张照片吧 [问与答] 国内网盘,大家都试过有哪些好用的原生支持 webdav 的网盘? [酷工作] [Golang] 兼职/全职大量招聘|团队扩招—跨境电商 AI+SaaS 用多模态大模型来做语音输入,效果碾压 typeless [推广] [FK Claude] 满血 Claude 折扣中转站 最近 claude code 频繁卡死有碰到同样问题的吗 [问与答] 香港金管局:就内地投资者开户核查倒查至 2023 年 1 月。啥意思? 各位小微企业创业的大佬,欢迎联系我购买财务软件 麻将洗牌 40 张牌跟踪, YOLO+ByteTrack 累积 1942 ID, SAM 2 / Cutie / CoTracker3 哪个能救? [Claude] 跪求 Claude 使用高手 [分享发现] 小米开发者计划送了 820 亿 token + 240 亿 credits,有人用得完吗? 有需要的可以用我的 前几天看到有坛友有 NAS 托管需求 ,刚好我们这边可以放这个 和大家讨论讨论可行性 [OpenAI] 高考期间国产 AI 工具部分功能或将禁用 哪些兄弟有 token 渠道,采购需求! [酷工作] 阿里国际急招 Agent 开发,流程快,最核心的交易业务,速来 网站公安备案,安全评估大家是怎么处理的 vibe 了一个可视化 sing-box 配置编辑器 寻找视觉处理大佬,多目标 mask 跟踪, SAM2, CoTracker3 / TAPIR (点跟踪)等 香港那边是不是开不了投资账户了 伪装成技术博客的本地 TXT 小说阅读器,让你在办公室光明正大地摸鱼 [问与答] 选择还房贷还是选择理财冲掉房贷利息? 中转站 token 掺水检查 关于懒猫微服,你需要一场面对面的交流,直播预告 [分享发现] 果然便宜没好货,用 Deepseek v4pro 写出来的程序 用 opus 4.7 审计出来了 500 多个 bug,笑死 去那种不大的咖啡店里学习简直是种折磨。 [深圳] 暑假想让老婆孩子来深圳,短租 2 个月,求推荐靠谱的找房方式 codex 中转站 0.05x 倍率 高并发 0.03x [分享发现] 知乎这文章,乱写毒人的吧? 想学习 AI 应用开发练手,用哪家的什么套餐比较好啊 claude code 日更两次,现在启动上下文足够长的窗口也比以前快了 第一版很粗糙,欢迎体验面向全球用户的校友社区 - AlumniCircle(校友圈) 今天 Codex 经常在思考中卡死了 [分享发现] 新开了一个英国银行账户 [程序员] 我又来了,给大家分享一下这几天积累的几个 skills [分享创造] Vibe 了一个机器人工具 33 岁阿里 5 年,平薪去长沙 vs 继续卷杭州,怎么选? [VPS] 收购一台 VPS, colocrossing 家的 [NAS] 利用本地 NAS 解决商业/公益 Emby 服务器无法转码的问题 入手了 一加 15T,说说感受 Apple Store ChatGPT 土耳其区可以年付吗? 『记个到』v1.6 更新:任务分享、统一管理、统计信息和反馈记录 Next2V:原生鸿蒙 V2EX 社区客户端已上架市场 最近接 AI Agent / AI 工作流 / 企业内部自动化相关的远程项目。 国际阿里云/腾讯云|AWS/谷歌云 sm 账号 7 折充值! 看看大家的 AGENTS.md/claude.md 里面都有什么好东西 [深圳] CWILL 招聘内推:产品经理 / Golang / 运维 / AI 解决方案 PM 打 BOSS 技术能聊吗? 之前站内看到的汽水音乐的谷歌搜索结果中有危险网址的问题还在 [AI Agent 智能体] 为什么国内的大模型很少能支持 openAi responses api 的 [推广] [打工人药丸] 瞒着老板,偷偷送 5 个海外住宅 IP 兑换码(全球 195+ 国家选),新用户速来! [分享发现] 今天刷抖音发现有一个在线摸鱼表格莫名其妙的火了 [编程] codex 任何地区都登录不上了 域名注册哪家便宜 [程序员] 聊一聊各位大佬们在 Vibe coding 环境下用的技术栈? 隔壁 L 站小作文好难啊 内核(驱动)内存泄露 [问与答] 你们用 opus 和 gpt 的时候 effort 开的是 medium 还是 extra high [问与答] 可以大陆直连,支持 openai image2 的中转站有吗? [生活] 想买个桨板配套的救生衣,有推荐的吗?帮忙给个链接 [职场话题] 想知道你们曾经离职的主要核心原因都是什么? 讲讲我的中转站建站历程,大家似乎都不太关注中转站实际使用的模型,最近我的 gpt-oss-120b(别名成 GPT-5.5)蜜罐被盗刷炸了 [程序员] codex app 一定要开 tun 模式才能用吗? [问与答] 写了一个免费的 LLM4Rec(大模型推荐系统)的课程,不确定 0 基础能看懂吗? [生活] 中排量摩托车求推荐! 本地大模型最佳 Mac 配置选择 不主动不拒绝不表态的女生,还有必要继续吗? [首发/急招] 搞定万卡调度后,我们决定去 Web3 用 Go + Agent 掀翻天花板! 微软 Azure 的 openai 服务有需要组队的么? 从产品初始化到迭代,总抓不准真实用户需求?我做了一个让用户反馈驱动产品决策的工具 Feedalyze 现在还有哪些值得推荐的机场 每天 6 毛钱的 AI 日报系统 —— AI Daily 又进化了 [程序员] 小米 token plan 明天到期,只用了 1%,搞了什么好呢 怎么优化重构 AI 生成的代码方便后面维护? 求助 GPT 的升级规则 game sinnermaker 最近沉迷低价 plus,推广区的赛博鸡蛋都有点懒得领了,分享一下我的使用方案 [电动汽车] 从没体验过智能电车,要实现这些需求得什么价位? 可靠的小道消息, minimax3 真的要来了(附 minimax 邀请链接) qoder 偷偷在干啥? [程序员] 求推荐一些 ubuntu 好用的 http 抓包工具 [程序员] 有没有推荐的 codex 中转?能包月最好能开票
想把我最近做的一个分布式网络爬虫系统开源,不知道有人有兴趣不
guoguobaba · 2025-11-07 · via V2EX

WebRPA: 分布式网络爬虫

前言

webrpa 是一个分布式的网络爬虫系统,基于 fastapi+fastadmin 开发,通过 web api 接口发起网络爬虫服务,实现流程自动化或数据自动抓取。它包含两部分:

  • manager: 用于提供 web 服务,实现了 web server 和 websocket server 。用户通过 web api 发送请求,manager 会将查询请求通过 websocket 转发给对应的 worker ,由 worker 执行查询操作。
  • worker: 通过 websocket 和 manager 连接,用于执行网络爬虫任务,接收 manager 的 websocket 请求,并执行查询操作。worker 可以跨网络分布式部署。
graph LR
client-->manager-->worker1
manager-->worker2
manager-->workers[worker...]

主要实现的功能包括:

  • 爬虫流程自定义:通过 json 指定访问网页的各种操作,实现流程自动化,并支持通过 markdown flowchart 语法定义流程,实现在不同条件下的跳转
  • 数据自动抓取:支持通过 js 对网页数据进行处理,获取结构化的数据以及对页面某个区域进行自动截图
  • 跨网络分布式部署:worker 可以跨网络分布式部署,实现负载均衡,并可以根据查询类型不同指定专用的 worker 。
  • 代理池支持:支持自定义代理池
  • undetected chromedriver:支持无头浏览器以及绕开网站的反扒检测。支持通过 selenium 和 requests 组合查询
  • 自定义 captcha 引擎:支持对图形验证码或者其他验证码的自动识别和点击操作等操作。并增加随机扰动,避免 antibot 检测。
  • 缓存和自动重试:支持缓存和自动重试,查询失败的请求会自动在闲时重试。
  • 自动扩容:支持 k8s 部署,一键扩容。
  • 权限和审计:支持数据源权限模型,不同的用户对不同的数据源具备不同的权限,并提供审计数据。

TODO

引入 browser use ,通过 LLM 自动创建数据爬虫服务。

一个示例,爬取某网站

{
  "name": "szreorc",
  "desc": "深圳不动产查询",
  "driver": "firefox",
  "url": "",
  "debug": true,
  "window_size": "1920x1080",
  "action_timeout": 5,
  "wait_redirect": true,
  "wait_redirect_interval": 2,
  "identifier": "{username}-{BuildingName}-{UNIT_NO}",
  "credential": "{username}",
  "actions": {
    "1": {
      "desc": "确认登录",
      "action": "check_variable",
      "options": {"script": "return window.location.href;",
        "target": "^https://pnr.sz.gov.cn/d-ghrer/reroosp/ytcf"
      }
    },
    "10": {
      "desc" : "用户名密码登录",
      "action": "click",
      "timeout": 2,
      "target": ["xpath", "//a[contains(@class, 'login-tab') and normalize-space(text())='账号密码']"]
    },
    "11": {
      "desc" : "输入用户名",
      "action": "input_text",
      "target": ["xpath", "//input[@type='text' and @placeholder='请输入账号']"],
      "param": "username"
    },
    "12": {
      "desc": "增加计数",
      "action": "variable",
      "options": {"variable":"counter1","operator": "+"}
    },
    "13": {
      "desc": "检测计数",
      "action": "variable",
      "stop_on_fail": true,
      "options": {"variable":"counter1","operator": "<", "target": 2, "sleep": 2000}
    },
    "14": {
      "desc" : "输入密码",
      "action": "input_text",
      "target": ["xpath", "//input[@type='password' and @placeholder='请输入密码']"],
      "param": "password"
    },
    "15": {
      "desc": "识别 captcha",
      "action": "decode_captcha_code",
      "target": ["xpath","//div[contains(@class, 'captcha-body') and @title='点击刷新']"],
      "options": {"code_type": 11}
    },
    "16": {
      "desc": "输入 captcha",
      "action": "input_text",
      "target": ["xpath","//div[contains(@class, 'account_verifying')] //input[@type='text']"]
    },
    "17": {
      "desc": "点击登录",
      "action": "click",
      "target": ["xpath", "//button[contains(@class, 'gd-btn-primary') and contains(@class, 'gd-btn') and @type='button']//span[starts-with(text(), '登录 ')]"]
    },
    "18": {
      "desc": "继续登录",
      "action": "click",
      "target": ["xpath", "//button[.//span[contains(text(), '继续登录')]]"]
    },
    "20": {
      "desc": "确认选择",
      "action": "click",
      "timeout": 10,
      "stop_on_fail": true,
      "fail_message": "login failed",
      "options": {"set_credential": true},
      "target": ["class name", "jinruxuzhi-checkbox"]
    },
    "21": {
      "desc": "确认选择下一步",
      "action": "click",
      "target": ["class name", "jinruxuzhi-buttonOk"]
    },
    "30": {
      "desc": "展开查询类型",
      "action": "click",
      "options": {"sleep": 2},
      "target": ["xpath", "//input[@type='text' and @placeholder='请选择']"]
    },
    "31": {
      "desc": "等待下拉菜单",
      "action": "wait_element",
      "options": {"visible":  true},
      "target": ["css selector", "div.el-select-dropdown.el-popper"]
    },
    "32": {
      "desc": "选择查询类型",
      "action": "click",
      "target": ["xpath", "//li[contains(@class, 'el-select-dropdown__item') and span[text()='楼名及栋名']]"]
    },
    "33": {
      "desc" : "输入查询内容",
      "action": "input_text",
      "target": ["xpath", "//input[@type='text' and @placeholder='请输入内容']"],
      "param": "BuildingName"
    },
    "34": {
      "desc": "点击查询",
      "action": "click",
      "target": ["class name", "el-icon-search"]
    },
    "35": {
      "desc": "点击截图对象",
      "action": "click",
      "timeout": 20,
      "stop_on_fail": true,
      "fail_message":  "search failed",
      "target": ["xpath", "//div[contains(@class, 'el-dialog__wrapper')]//div[contains(@class, 'el-tabs__item') and normalize-space(text())='楼宇']"]
    },

    "40": {
      "desc": "获取数据",
      "action": "get_data",
      "options": {"script": "var table = document.querySelector(\"#pane-1 table.is-bordered.el-descriptions--mini\");\nvar fields = [\"土地坐落\", \"楼名及栋名\", \"房屋类型\", \"房屋性质\", \"房屋用途\"];\nvar result = {};\nif (table) {\n    var rows = table.querySelectorAll(\"tr.el-descriptions-row\");\n    rows.forEach(function(row) {\n        var label = row.querySelector(\"th.el-descriptions-item__label\").innerText.trim();\n        var content = row.querySelector(\"td.el-descriptions-item__content\").innerText.trim();\n        if (fields.includes(label)) {\n            result[label] = content;\n        }\n    });\n    console.log(JSON.stringify(result));\n} else {\n    console.log(\"Table not found.\");\n};\nreturn result;\n"}
    },
    "41": {
      "desc": "点击截图对象",
      "action": "click",
      "target": ["xpath", "//div[contains(@class, 'el-dialog__wrapper')]//div[contains(@class, 'el-tabs__item') and normalize-space(text())='房屋']"]
    },
    "42": {
      "desc": "下拉房屋查询",
      "action": "click",
      "target": ["css selector", "#pane-2 input.el-input__inner"]
    },
    "43": {
      "desc": "点击房屋查询",
      "action": "click",
      "target": ["xpath", "//li[contains(@class, 'el-select-dropdown__item')]//span[text()='{UNIT_NO}']"],
      "param": "UNIT_NO"
    },
    "44": {
      "desc": "截图",
      "action": "screenshot",
      "target": ["class name", "el-dialog__wrapper"],
      "options": {"visible": true}
    },
    "45": {
      "desc": "获取数据",
      "action": "get_data",
      "options": {"script": "var table = document.querySelector(\"#pane-2 table.is-bordered.el-descriptions--mini\");\nvar fields = [\"房号\", \"所在楼层\", \"建筑面积\", \"使用年限\", \"存在抵押\", \"存在查封\", \"存在异议\", \"存在居住权\"];\nvar result = {};\nif (table) {\n    var rows = table.querySelectorAll(\"tr.el-descriptions-row\");\n    rows.forEach(function(row) {\n        var label = row.querySelector(\"th.el-descriptions-item__label\").innerText.trim();\n        var content = row.querySelector(\"td.el-descriptions-item__content\").innerText.trim();\n        if (fields.includes(label)) {\n            result[label] = content;\n        }\n    });\n    console.log(JSON.stringify(result));\n} else {\n    console.log(\"Table not found.\");\n};\nreturn result;\n"}
    }
  },
  "processes": "start->1\n1(no)->10->11\n11(no)->12->13\n13(yes)->10\n11(yes)->14->15->16->17->18->20->21->30->31->32->33->34->35->40->41->42->43->44->45->end\n1(yes)->20",
  "result":["screenshot", "data"]
}