做工业数据采集这几年最头疼的事永远不是反爬是前端改版。很多站点反爬没把你搞死前端开发随手改个类名、调一下DOM层级、换个标签顺序你写的CSS选择器、XPath就全失效了数据抓空告警炸群。小改还好挨个修选择器要花大半天碰到全站重构等于爬虫重写一遍。去年我们团队维护的二十几个采集站点每月光花在修复选择器上的时间就有三四十个小时一半的运维精力都耗在这上面。后来尝试把LLM加进去做自愈选择器失效了自动识别新的路径不用人工介入。前后调了两个多月踩了幻觉、准确率、成本控制一堆坑最终普通改版的自愈成功率稳定在92%以上每月的人工运维时间降到了6小时以内效果比预期好很多。今天就把整套方案完整分享出来从设计思路、代码实现到踩坑优化全讲透看完就能嵌到自己的爬虫框架里。一、先想清楚传统的「耐造爬虫」方案差在哪在LLM之前大家也想了很多办法提升爬虫的鲁棒性也就是常说的Resilient Scraping但都有自己的天花板。绝对路径换相对路径不用层级过深的绝对XPath改用id、class、文本特征定位比绝对路径稳一点但类名一改还是直接挂。文本属性定位不靠DOM层级靠元素的文本、href、data-*属性定位稳定性更高但文本改了、属性删了照样失效。多规则兜底同一个元素写3-5个不同的选择器一个失效了试下一个。能应付小改动但改版幅度大一点还是全军覆没而且维护成本翻倍。这些方案本质都是「提前预判变化」靠人把可能的情况都想到。但前端改版是不可预测的你永远猜不到开发会改成什么样所以兜底规则再多也总有覆盖不到的情况。而LLM的思路完全不一样它不是靠预设规则是像人一样去「理解」页面结构根据旧元素的业务特征在新页面里找到对应的新元素。只要页面的业务逻辑没变哪怕DOM结构改得面目全非也能找对位置。二、LLM自愈爬虫的核心设计只做一件事修复选择器很多人做LLM爬虫一上来就让大模型写整个爬虫代码结果幻觉满天飞数据错了都不知道。我们的设计原则很明确LLM只负责选择器修复这一件事其余逻辑全靠原有爬虫框架。整个自愈流程触发时机非常明确当原有选择器匹配不到元素时才启动自愈流程正常情况下完全不调用LLM不增加额外成本。完整的执行链路是五步触发原有选择器匹配失败捕获异常进入自愈流程切片提取目标元素周边的DOM片段而不是整页HTML减少token消耗和干扰推理把旧选择器、旧元素特征、新页面DOM片段传给LLM生成新的选择器校验用新选择器去页面里匹配检查结果是否符合预期数量、文本、属性特征落库校验通过就更新选择器缓存下次直接用校验失败就触发人工告警核心是把LLM当成一个智能修复工具嵌在原有爬虫的异常处理链路里不侵入原有业务逻辑上线成本极低。三、手把手实现可直接落地的自愈模块接下来上完整代码基于Python实现兼容所有OpenAI协议的大模型本地部署的开源模型也能用。3.1 前置准备只需要两个基础依赖pipinstallbeautifulsoup4 openai用BeautifulSoup做DOM切片和结果校验openai库调用大模型接口通用度很高。3.2 第一步DOM切片别把整页HTML丢给LLM这是第一个大坑。一开始我直接把整页HTML传进去token又多、干扰又大LLM经常被无关元素带偏准确率很低。正确的做法是根据旧选择器的特征在新页面里定位大致的区域只截取目标周边的DOM片段再传给LLM。既省token又减少干扰准确率直接上一个台阶。frombs4importBeautifulSoupdefextract_related_dom(html,old_selector,context_range5):提取目标周边的DOM片段减少无关内容干扰soupBeautifulSoup(html,html.parser)# 尝试用旧选择器找近似区域找不到就取主体内容区targetsoup.select_one(old_selector)iftarget:# 向上找5层父元素作为上下文parenttargetfor_inrange(context_range):ifparent.parent:parentparent.parentelse:breakreturnstr(parent)# 旧选择器完全失效取页面主内容区兜底main_contentsoup.select_one(main, .content, #app)ifmain_content:returnstr(main_content)returnhtml[:5000]# 最后兜底只取前5000字符3.3 第二步核心Prompt设计精准控制LLM输出Prompt是自愈准确率的关键。要明确告诉LLM任务是什么、输入是什么、输出格式是什么、要遵守哪些规则绝对不能让它自由发挥。我们的Prompt经过十几轮优化核心包含四个部分角色定义、输入信息、输出要求、约束规则。defbuild_prompt(old_selector,element_desc,dom_snippet):returnf 你是专业的网页元素定位专家。请根据旧的选择器和元素描述在新的HTML片段中找到对应的目标元素生成新的CSS选择器。 【旧选择器】{old_selector}【元素业务含义】{element_desc}【新页面HTML片段】 html{dom_snippet}要求找到和旧元素业务含义一致的目标元素生成最稳定的CSS选择器优先使用id、data-*属性、文本特征、稳定的类名避免使用层级过深的绝对路径不要使用动态生成的随机类名优先选择语义化的、不随版本变化的特征严格按JSON格式输出不要额外解释格式如下{{“new_selector”: “新的CSS选择器”,“confidence”: 0.95,“reason”: “选择理由”}}置信度0-1越高表示越准确。如果完全找不到对应元素置信度填0。“”### 3.4 第三步调用LLM获取新选择器 用标准的OpenAI接口调用支持所有兼容协议的模型包括本地开源模型。 python from openai import OpenAI client OpenAI( api_key你的API_KEY, base_url你的接口地址 ) def llm_fix_selector(old_selector, element_desc, html): dom_snippet extract_related_dom(html, old_selector) prompt build_prompt(old_selector, element_desc, dom_snippet) try: resp client.chat.completions.create( modelqwen3-7b, # 轻量模型足够用成本极低 messages[{role: user, content: prompt}], temperature0.1, # 温度调低减少随机性 response_format{type: json_object} ) import json result json.loads(resp.choices[0].message.content) return result except Exception as e: print(fLLM调用失败: {e}) return {confidence: 0, new_selector: }实战建议用7B参数的轻量模型完全足够成本只有千亿大模型的几十分之一准确率也差不了多少。我们用本地部署的Qwen3-7B和千亿模型的准确率差不到3%单次调用成本可以忽略不计。3.5 第四步结果校验杜绝幻觉这是最重要的一步没有校验的自愈就是埋雷。LLM生成的选择器可能是错的直接用会导致脏数据入库比爬虫挂了更可怕。我们做了三层校验全部通过才认为修复成功defvalidate_selector(html,new_selector,old_features):三层校验确保新选择器正确soupBeautifulSoup(html,html.parser)elementssoup.select(new_selector)# 1. 数量校验匹配到的元素数量和预期是否一致iflen(elements)!old_features.get(expect_count,1):returnFalse# 2. 特征校验元素的文本、属性是否符合旧特征foreleinelements:# 检查文本是否包含预期关键词ifold_features.get(keywords):textele.get_text()ifnotany(kintextforkinold_features[keywords]):returnFalse# 检查关键属性是否存在ifold_features.get(required_attrs):forattrinold_features[required_attrs]:ifnotele.has_attr(attr):returnFalse# 3. 置信度校验LLM给出的置信度高于阈值才通过returnTrue只有三层校验都通过才更新选择器任何一层不通过都判定为自愈失败触发人工告警。四、嵌入现有爬虫零侵入式改造不用重写现有爬虫只要在元素匹配的异常捕获里加一行自愈逻辑就行。比如用DrissionPage的采集场景改造后是这样defsafe_get_element(page,selector,element_desc,old_features):带自愈能力的元素获取函数try:elepage.ele(selector,timeout2)returneleexceptException:# 匹配失败触发自愈流程htmlpage.html fix_resultllm_fix_selector(selector,element_desc,html)iffix_result[confidence]0.8andvalidate_selector(html,fix_result[new_selector],old_features):# 修复成功更新缓存print(f选择器自愈成功:{selector}-{fix_result[new_selector]})update_selector_cache(selector,fix_result[new_selector])returnpage.ele(fix_result[new_selector])else:# 修复失败触发告警send_alert(f选择器失效且自愈失败:{selector})raise原有业务代码完全不用改只是把原来的元素获取函数换成带自愈的版本半天就能完成全项目改造。五、踩了两个月的坑这些经验一定要避开坑1整页HTML丢给LLM费钱还不准整页HTML动辄几万字符token消耗大无关内容多LLM很容易被干扰找错元素。一定要做DOM切片只保留目标周边的上下文准确率能提升20%以上token消耗还能降到原来的十分之一。坑2温度太高结果五花八门温度参数一定要调低建议0.1以下。选择器修复是确定性任务不需要创意温度越低输出越稳定幻觉越少。一开始用默认0.7每次生成的选择器都不一样准确率忽高忽低调到0.1之后稳定多了。坑3不加校验直接用脏数据比挂了更可怕千万别相信LLM的输出一定要加多层校验。我们早期踩过这个坑LLM把别的元素当成了目标结果抓了一周的错误数据返工花了好几天。校验再严都不为过宁可自愈失败告警也不能让错误数据入库。坑4什么都让LLM做准确率反而低不要让LLM负责整个爬虫逻辑就聚焦在选择器修复这一件事上。任务越单一提示词越好写准确率越高越容易校验。贪多求全最后哪样都做不好。坑5用大模型跑成本太高完全没必要用千亿参数的大模型7B甚至3B的轻量模型就足够胜任这种结构化任务。本地部署开源模型的话成本几乎可以忽略比人工修划算太多。六、实测效果与适用边界我们在二十几个采集站点上跑了三个月核心数据非常直观普通小改版改类名、调层级自愈成功率92.6%基本不用人工介入中等改版模块重构、布局调整自愈成功率68.3%剩下的人工处理全站大重构成功率不到30%还是需要人工重写整体人工运维时间从每月30-40小时降到5-7小时下降80%以上不是万能的这些场景不适合页面完全重构业务逻辑都变了LLM也没法无中生有对准确率要求100%的场景还是人工审核更稳妥页面结构极其简单改版频率极低的站点没必要加LLM增加复杂度最适合的场景站点多、改版频繁人工维护成本高对可用性要求高不能动不动就挂数据允许少量容错有校验机制兜底总结LLM不是银弹不能解决爬虫的所有问题但在选择器自愈这件事上确实能大幅降低运维成本。它的价值从来不是100%替代人工而是把80%的简单、重复的修复工作自动化让人只去处理那20%的复杂改版。把工程师从重复的修选择器的体力活里解放出来去做更有价值的事。技术落地永远是这样不用追求高大上的方案找对具体的场景用合适的技术解决具体的痛点就是最好的方案。合规提示本文仅讨论爬虫技术的运维优化方案采集数据请严格遵守《网络安全法》及目标网站的robots协议不得用于非法用途。
企业数字化 ERP 产品动态
相关推荐
“软件已死”?独立开发大佬退订几乎所有工作软件:要啥让AI造 卖软件的人先不买软件了
一个做软件开发生意的人,开始大规模退订软件,还喊出了一句狠话:
软件已死。
10月11日,知名独立开发者Pieter Levels(levelsio)发文称,自己已经退掉了几乎所有工作用的… · 2026/11/3 18:13:35
OpenStack 存储管理实操:卷类型 QoS、卷全生命周期与 NFS 第二后端 卷建好只是开始——挂载、扩容、打快照、传成镜像、拿去发实例,每一步都有前置条件;删卷删不掉更是三条依赖链叠出来的经典现场。这篇按卷的一生走完 Dashboard 与 CLI 两套操作:卷类型与 QoS → 创建挂载 → 快照/镜像/扩容 → 基于卷发实例… · 2026/11/3 18:17:04
OpenStack 计算管理:实例锁定后被普通用户解锁了?避坑实操 给实例上了锁,转身普通用户登录就把锁解了、机删了——这不是 bug,是 policy.json 里 unlock 那条规则默认对 owner 开放。这篇把计算管理走一遍完整闭环:主机聚合与可用分区、规格的 Public/Private、密钥对与服务器组、发放实例,… · 2026/11/3 17:00:20
Redis SCAN命令原理与华为云优化实践 1. Redis SCAN命令基础解析Redis的SCAN命令是遍历大量键值对时的高效解决方案,它通过游标式迭代避免了KEYS命令可能引发的服务阻塞问题。在华为云Redis环境中,这个命令的工作机制与开源版本保持兼容,但在底层实现上针对云环境做了优化。1.1 S… · 2026/11/4 23:17:38
MySQL字符集与校对规则实战解析 1. MySQL字符集与校对规则深度解析最近在排查一个线上SQL报错时,遇到了Illegal mix of collations这个看似简单却隐藏着不少细节的问题。作为MySQL数据库中最基础却又最容易被忽视的配置项,字符集和校对规则的选择直接影响着数据存储、查询性能和多语言支… · 2026/11/4 23:17:38
OpenClaw自动化文档生成方案设计与实现 1. 项目背景与核心价值 最近在维护OpenClaw这个开源项目时,遇到一个典型的版本管理痛点:每次发布新版本后,配套的指令文档都需要手动同步更新。这不仅增加了维护成本,还容易因人为疏忽导致文档与代码实际功能脱节。经过两周的迭代… · 2026/11/4 23:17:38
Crowbar/Diksam解释器源码拆解:词法语法、GC与构建排错 简介:围绕自制编程语言主题的PDF资料,面向希望从语法设计、编译器实现到运行环境完整走通一遍的开发者与高年级学生,尤其适合已具备C语言基础、想理解解释器与编译器构造流程的读者。压缩包内共1个PDF文件,约2.38MB,以… · 2026/11/4 23:17:38
SeleniumBase与Cypress Real World App自动化测试实践 1. 项目概述:SeleniumBase与Cypress Real World App的自动化测试实践最近在尝试使用SeleniumBase框架对Cypress Real World App这个开源项目进行自动化测试时,遇到了几个典型的前后端交互问题。作为一款模拟真实金融场景的测试应用,Cypress R… · 2026/11/4 23:17:38
无头CMS架构设计与API-First开发实践 1. 项目背景与核心价值 在数字化转型浪潮中,内容管理系统(CMS)正在经历一场架构革命。传统CMS往往将内容创作、存储和展示强耦合在一起,导致系统灵活性差、迭代成本高。我们团队最近完成了一个API-First无头内容管理器的MVP研发&a… · 2026/11/4 23:16:36
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38