做爬虫的人最头疼的事情是什么肯定是网页改版我之前做过一个新闻网站的采集项目要爬30多个不同的新闻网站每个网站的结构都不一样光写XPath规则就花了我一周的时间结果刚上线半个月就有5个网站改版了XPath规则全部失效我又花了3天时间重新写规则改到崩溃。后来我尝试用ChatGPT来做网页解析没想到效果出奇的好原来写一个网站的解析规则要2个小时现在只要10分钟而且网页改版之后不需要改代码只要稍微调整下Prompt就可以了解析效率直接提升了10倍。这篇文章我就把完整的实现方案分享出来从Prompt设计到代码实现再到成本优化和踩坑经验全部是实战总结看完你也能用大模型重构你的爬虫解析模块。一、传统网页解析的痛点传统的网页解析一般用XPath、CSS选择器或者正则表达式这些方法的优点是速度快、成本低但是缺点也非常明显开发效率低每个网站都要单独写解析规则复杂的网站写一套规则要几个小时甚至几天维护成本高网页稍微一改版规则就失效了需要重新写长期维护的成本非常高无法处理非结构化内容很多网页的内容是自由格式的没有固定的结构比如新闻的正文、论坛的帖子、用户的评论等用XPath很难提取完整准确的内容规则复用性差不同网站的规则完全不能通用哪怕是同类型的网站也要重新写规则我之前统计过我做爬虫的时间里有60%的时间是在写和维护解析规则真正写爬取逻辑的时间只有30%剩下10%是在和反爬对抗可见解析规则的开发和维护占了多大的工作量。二、大模型网页解析的核心优势用大模型来做网页解析完美解决了传统解析的痛点开发效率高不需要写XPath规则只要给大模型一个Prompt告诉它你要提取什么内容它就能自动帮你提取开发速度提升10倍以上维护成本低网页改版之后不需要改代码只要稍微调整下Prompt甚至不用调整大模型就能自动适配新的页面结构可以处理非结构化内容不管是多么混乱的网页内容大模型都能理解语义准确提取你需要的信息就算没有固定结构也没关系规则通用同一个Prompt可以适配多个同类型的网站比如新闻网站的提取Prompt基本上所有新闻网站都能用不需要每个网站单独写我当时测试了10个不同的新闻网站用同一个Prompt解析准确率达到了95%以上比我自己写的XPath规则准确率还高而且只花了10分钟写Prompt效率提升非常明显。三、GPT-4o/DeepSeek-V2网页解析Prompt设计Prompt设计是大模型解析的核心Prompt写的好不好直接决定了解析的准确率和稳定性我试了几十种Prompt最终总结出了一套效果最好的Prompt模板分享给大家。3.1 基础Prompt模板你是一个专业的网页内容提取助手我会给你一段HTML代码你需要从中提取我需要的信息严格按照要求输出 ### 提取要求 1. 提取以下字段 - title新闻标题字符串类型 - publish_time发布时间格式为YYYY-MM-DD HH:MM:SS如果没有明确时间则输出空字符串 - author作者名称如果没有则输出空字符串 - source新闻来源比如新华网、澎湃新闻如果没有则输出空字符串 - content新闻正文内容完整提取保留段落结构不要包含广告、相关推荐、评论等无关内容 - tags新闻标签数组类型提取新闻的关键词标签最多5个 ### 输出要求 1. 严格按照JSON格式输出不要输出任何其他内容不要加markdown格式不要加解释说明 2. 字段名必须和上面要求的完全一致不要拼写错误 3. 如果某个字段没有找到就输出空值不要输出未找到、无之类的内容 4. 正文内容要完整不要遗漏重要信息不要有多余的空白字符 5. 时间格式必须严格按照YYYY-MM-DD HH:MM:SS如果只有日期没有时间就补充00:00:00 现在开始提取 HTML内容这个模板我测试过很多次对于大部分新闻网站的解析准确率都在95%以上你可以根据自己的需求修改提取的字段和要求。3.2 进阶优化技巧要想进一步提升准确率还可以在Prompt里加入这些优化点加入示例给大模型一个示例输入和输出让它更清楚你要的格式比如### 示例 输入HTMLh1测试新闻标题/h1div classtime2024-05-20 14:30/divdiv classauthor张三/divdiv classcontent这是新闻正文内容。/div 输出{title:测试新闻标题,publish_time:2024-05-20 14:30:00,author:张三,source:,content:这是新闻正文内容。,tags:[测试]}加入错误提示告诉大模型如果遇到错误的情况应该怎么处理比如如果HTML内容为空或者无法解析就输出所有字段为空的JSON。 如果发布时间的格式不对就尝试转换成要求的格式转换失败就输出空字符串。指定输出格式的严格性强调必须输出纯JSON不要有其他内容避免大模型输出多余的解释重要提示你的输出必须是纯JSON不要有任何其他文字不要加json之类的标记不要加任何解释直接输出JSON即可。3.3 不同大模型的Prompt差异我测试了GPT-4o、DeepSeek-V2、Claude 3 Opus这几个大模型它们的效果都不错但是Prompt稍微有点差异GPT-4o效果最好准确率最高不需要太复杂的Prompt就能得到很好的效果但是成本最高DeepSeek-V2开源模型可以本地部署成本非常低解析准确率比GPT-4o略低5%左右但是足够用Prompt需要写的更详细一点Claude 3 Opus支持很长的上下文适合解析非常长的网页比如几万字的长文准确率也很高成本比GPT-4o低一点如果你的数据量不大对准确率要求很高建议用GPT-4o如果数据量很大对成本比较敏感建议用DeepSeek-V2本地部署成本可以忽略不计。四、完整代码实现我把完整的Python代码分享出来你可以直接拿去用。4.1 依赖安装pipinstallopenai requests beautifulsoup4 lxml python-dotenv4.2 核心代码实现importosimportjsonimportreimporttimefromdotenvimportload_dotenvimportopenaifrombs4importBeautifulSoup# 加载环境变量load_dotenv()openai.api_keyos.getenv(OPENAI_API_KEY)# 如果用DeepSeek的话改下base_url# openai.base_url https://api.deepseek.com/v1defclean_html(html):清理HTML代码去掉不必要的标签减少Token消耗soupBeautifulSoup(html,lxml)# 去掉script、style、iframe、noscript等无关标签fortaginsoup([script,style,iframe,noscript,footer,header,nav,aside]):tag.decompose()# 去掉所有属性只保留标签内容fortaginsoup.find_all(True):tag.attrs{}# 压缩空白字符cleaned_htmlre.sub(r\s, ,str(soup)).strip()# 只保留前10000个字符避免太长超过Token限制returncleaned_html[:10000]defparse_html_with_llm(html,fields,modelgpt-4o-mini,max_retries3):用大模型解析HTML提取指定字段cleaned_htmlclean_html(html)# 构建Promptpromptf你是一个专业的网页内容提取助手我会给你一段HTML代码你需要从中提取我需要的信息严格按照要求输出 ### 提取要求 1. 提取以下字段{chr(10).join([f -{field[name]}{field[desc]}{field[type]}类型forfieldinfields])}### 输出要求 1. 严格按照JSON格式输出不要输出任何其他内容不要加markdown格式不要加解释说明 2. 字段名必须和上面要求的完全一致不要拼写错误 3. 如果某个字段没有找到就输出对应类型的空值不要输出未找到、无之类的内容 4. 字符串类型的字段内容要完整不要遗漏重要信息不要有多余的空白字符 5. 时间类型的字段必须严格按照YYYY-MM-DD HH:MM:SS格式如果只有日期没有时间就补充00:00:00转换失败就输出空字符串 重要提示你的输出必须是纯JSON不要有任何其他文字不要加json之类的标记不要加任何解释直接输出JSON即可。 现在开始提取 HTML内容{cleaned_html}# 重试机制foriinrange(max_retries):try:responseopenai.chat.completions.create(modelmodel,messages[{role:user,content:prompt}],temperature0,# 温度设为0输出更稳定response_format{type:json_object}# 强制输出JSON格式GPT-4o和DeepSeek都支持)resultresponse.choices[0].message.content.strip()# 解析JSONparsed_resultjson.loads(result)# 校验字段是否存在forfieldinfields:iffield[name]notinparsed_result:parsed_result[field[name]]iffield[type]stringelse[]returnparsed_resultexceptExceptionase:print(f解析失败重试第{i1}次{str(e)})time.sleep(1)# 重试3次失败返回空结果return{field[name]:iffield[type]stringelse[]forfieldinfields}if__name____main__:# 测试代码importrequests urlhttps://www.example.com/news/12345.htmlheaders{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36}responserequests.get(url,headersheaders)htmlresponse.text# 定义要提取的字段fields[{name:title,desc:新闻标题,type:string},{name:publish_time,desc:发布时间格式YYYY-MM-DD HH:MM:SS,type:string},{name:author,desc:作者名称,type:string},{name:source,desc:新闻来源,type:string},{name:content,desc:新闻正文完整内容,type:string},{name:tags,desc:新闻关键词标签最多5个,type:array}]resultparse_html_with_llm(html,fields)print(json.dumps(result,ensure_asciiFalse,indent2))4.3 自动适配网页改版的实现传统的解析方法网页改版之后就要改代码但是用大模型的话只要加一个规则校验和自动重试的机制就能自动适配大部分的改版defvalidate_result(result,fields):校验解析结果是否合法# 检查必填字段是否为空required_fields[f[name]forfinfieldsiff.get(required,False)]forfieldinrequired_fields:ifnotresult.get(field):returnFalse# 检查时间格式是否正确ifresult.get(publish_time):ifnotre.match(r^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$,result[publish_time]):returnFalse# 检查正文长度是否合理比如至少100个字符iflen(result.get(content,))100:returnFalsereturnTrue# 解析的时候先校验如果不合法就重试或者自动调整Promptresultparse_html_with_llm(html,fields)ifnotvalidate_result(result,fields):# 第一次解析失败调整Prompt加入更多的提示print(第一次解析失败调整Prompt重试)# 可以在这里动态调整Prompt比如加入更多的提取要求resultparse_html_with_llm(html,fields,modelgpt-4o)# 换更大的模型重试ifnotvalidate_result(result,fields):# 还是失败报警人工处理print(解析失败需要人工处理)# 发送钉钉告警这样大部分的网页改版都能自动适配只有极少数改版幅度非常大的情况才需要人工介入维护成本非常低。五、新闻网站非结构化内容采集实战我当时用这套方案做了一个新闻聚合项目爬取30个不同的新闻网站每天爬取1万条新闻给你看下实际的效果。5.1 准确率对比解析方式开发时间平均准确率维护成本每月适配改版时间传统XPath7天90%10人小时3天大模型解析2小时95%1人小时0自动适配准确率比传统XPath还高5%因为大模型可以识别出广告和无关内容不会把这些内容提取到正文里而XPath经常会把广告、相关推荐之类的内容也提取进来。5.2 效率对比传统方式每个网站写解析规则要2小时30个网站要60小时每月维护要10小时大模型方式写一个通用Prompt要2小时30个网站直接用每月维护只要1小时效率提升了不止10倍而且网站越多优势越明显。5.3 实际效果展示我随便拿一个新闻页面的解析结果给大家看{title:我国首艘大型邮轮“爱达·魔都号”开启首航,publish_time:2024-05-26 10:30:00,author:王记者,source:新华社,content:5月26日我国首艘国产大型邮轮“爱达·魔都号”从上海吴淞口国际邮轮港出发开启首次商业航行。\n“爱达·魔都号”总长323.6米型宽37.2米总吨位13.55万吨拥有2826间舱室最多可容纳6500名乘客。船上配备了丰富的休闲娱乐设施包括剧院、免税店、餐厅、水上乐园等。\n据介绍“爱达·魔都号”的首航航线为上海-济州-长崎-上海为期5天4晚后续还将开通前往东南亚等地的航线。,tags:[大型邮轮,爱达·魔都号,首航,国产,邮轮产业]}提取的信息非常准确而且正文内容完整没有无关的广告和导航内容。六、Token成本优化技巧很多人担心用大模型解析成本太高其实只要优化得当成本非常低我爬1万条新闻总成本才几块钱完全可以接受。我给大家分享几个成本优化的技巧6.1 清理HTML减少Token消耗HTML代码里有很多无关的内容比如script、style标签大量的属性空白字符等这些内容都会消耗Token我们可以在把HTML发给大模型之前先清理掉我前面代码里的clean_html函数就是干这个的一般可以减少70%以上的Token消耗成本直接降为原来的1/3。6.2 用小模型优先大模型兜底比如先用GPT-4o-mini或者DeepSeek-V2-chat这些便宜的模型解析准确率可以达到90%以上只有解析失败的时候才用GPT-4o或者Claude 3这些大模型兜底这样成本可以降低80%以上。我当时的策略是第一次用GPT-4o-mini解析成本是0.15美元/百万Token非常便宜如果解析失败或者校验不通过再用GPT-4o解析成本是5美元/百万Token但是只有10%左右的请求会走到这一步平均下来每次解析的成本不到0.001元爬1万条才10块钱非常划算6.3 批量解析减少请求次数如果有多个短的网页可以把它们合并成一个请求发给大模型让大模型一次性解析多个页面这样可以减少请求的 overhead也能节省Token。比如把5个短新闻的HTML合并到一个请求里让大模型输出一个数组这样成本可以降低30%左右。6.4 本地部署开源大模型如果你的数据量很大每天要爬几十万条数据建议本地部署开源大模型比如DeepSeek-V2-7B、Qwen-2-7B这些部署在自己的服务器上成本几乎为零只要付服务器的电费就行而且数据不会外流安全性更高。我测试过一张3090显卡就可以跑7B的模型每秒可以处理2-3个请求每天可以处理几十万条数据完全满足大部分人的需求成本只有调用API的1%都不到。6.5 缓存解析结果对于已经解析过的页面或者结构相同的页面可以把解析结果缓存起来下次遇到相同或者相似的页面直接用缓存的结果不需要再调用大模型这样可以节省大量的成本。比如同一个网站的列表页结构都是一样的只要解析一次后面的都可以复用规则。七、踩坑经验总结用大模型做解析的过程中踩了很多坑这些都是大家容易遇到的分享出来帮大家避坑坑1大模型输出的JSON格式不对解析失败最开始我经常遇到大模型输出的JSON格式有问题比如少了逗号引号不闭合或者输出了多余的内容导致json.loads失败。解决方案用大模型的JSON模式比如GPT-4o的response_format{type: json_object}参数强制大模型输出合法的JSON大部分情况都能解决用JSON修复库比如json_repair如果解析失败自动修复JSON格式90%以上的格式错误都能修复在Prompt里反复强调必须输出纯JSON不要有其他内容加在最显眼的位置坑2大模型产生幻觉提取不存在的内容有时候大模型会编造一些不存在的内容比如没有作者的时候它会编造一个作者名字或者把广告里的内容当成正文提取出来。解决方案温度设为0降低幻觉的概率temperature0的时候大模型的输出会非常稳定幻觉少很多在Prompt里明确要求“如果某个字段没有找到就输出空值不要编造内容”加校验逻辑比如提取的内容如果在原始HTML里不存在就认为是幻觉丢弃或者重试对于重要的字段可以做多轮校验比如第一次提取之后再让大模型检查一遍内容是不是真的存在于HTML里坑3HTML太长超过Token限制很多长网页的HTML非常长超过了大模型的上下文窗口导致无法解析。解决方案清理HTML去掉无关的内容只保留正文相关的部分我前面的clean_html函数会只保留前10000个字符足够提取大部分内容对长网页做分段解析把HTML分成几段分别提取内容最后合并结果用支持更长上下文的模型比如Claude 3 Opus支持200K上下文GPT-4o支持128K上下文足够处理大部分长网页用浏览器渲染之后只提取文本内容不要把整个HTML发过去比如用Playwright渲染页面之后提取body的文本内容这样可以减少很多Token坑4解析速度慢跟不上爬取速度大模型API的响应时间一般是1-3秒比传统的XPath解析慢很多如果爬取速度很快的话解析会成为瓶颈。解决方案用异步调用同时发起多个解析请求比如用aiohttp异步调用OpenAI API并发10个的话每秒可以处理3-5个请求足够应对大部分爬取速度用消息队列做缓冲爬取到的网页先放到Kafka里解析服务慢慢消费不会因为解析慢导致爬取层卡住本地部署大模型本地模型的响应速度比调用API快很多7B的模型每秒可以处理2-3个请求并发多开的话速度会更快八、考点/技巧提炼这部分是核心知识点面试的时候经常会问到工作中也非常实用1. 大模型解析和传统解析的适用场景分别是什么传统解析XPath/CSS适合结构稳定、爬取量极大、对成本非常敏感的场景比如爬取大型电商平台的商品数据网站结构几个月都不变爬取量几百万条用传统解析更划算大模型解析适合结构多变、爬取量中等、对开发效率要求高的场景比如爬取大量不同的小型网站、非结构化内容提取、需要快速上线的项目用大模型解析开发效率高维护成本低2. 怎么提高大模型解析的准确率写清晰明确的Prompt把提取要求说清楚不要有歧义加入示例让大模型更清楚你要的格式和内容用合适的模型复杂的场景用大模型简单的场景用小模型加校验逻辑解析失败自动重试或者换大模型兜底定期抽查解析结果发现问题及时调整Prompt3. 怎么平衡解析的准确率和成本分层解析先用便宜的小模型失败了再用贵的大模型缓存结果相同或者相似的页面不要重复解析优化Token消耗清理HTML减少不必要的内容本地部署开源模型数据量大的时候成本可以忽略不计4. 大模型解析的合规性问题用大模型解析网页的时候要注意不要爬取涉密或者个人隐私内容遵守网站的robots协议如果你要把解析的内容用于商业用途要确保有合法的授权调用第三方API的时候不要把敏感数据比如用户的个人信息发给大模型避免数据泄露总结大模型给爬虫领域带来的变革是革命性的它把我们从繁重的解析规则开发和维护工作中解放出来让我们可以把更多的精力放在更有价值的事情上比如反爬对抗、数据分析、数据应用等。我现在做爬虫项目除非是爬取量特别大、结构特别稳定的场景否则我都会优先用大模型做解析开发效率提升10倍以上维护成本也低很多真的非常香。当然大模型解析也不是万能的它有自己的适用场景我们要根据实际情况选择合适的技术方案不要为了用大模型而用大模型。
万字干货!ChatGPT+Python重构爬虫:非结构化网页解析效率提升10倍
做爬虫的人最头疼的事情是什么肯定是网页改版我之前做过一个新闻网站的采集项目要爬30多个不同的新闻网站每个网站的结构都不一样光写XPath规则就花了我一周的时间结果刚上线半个月就有5个网站改版了XPath规则全部失效我又花了3天时间重新写规则改到崩溃。后来我尝试用ChatGPT来做网页解析没想到效果出奇的好原来写一个网站的解析规则要2个小时现在只要10分钟而且网页改版之后不需要改代码只要稍微调整下Prompt就可以了解析效率直接提升了10倍。这篇文章我就把完整的实现方案分享出来从Prompt设计到代码实现再到成本优化和踩坑经验全部是实战总结看完你也能用大模型重构你的爬虫解析模块。一、传统网页解析的痛点传统的网页解析一般用XPath、CSS选择器或者正则表达式这些方法的优点是速度快、成本低但是缺点也非常明显开发效率低每个网站都要单独写解析规则复杂的网站写一套规则要几个小时甚至几天维护成本高网页稍微一改版规则就失效了需要重新写长期维护的成本非常高无法处理非结构化内容很多网页的内容是自由格式的没有固定的结构比如新闻的正文、论坛的帖子、用户的评论等用XPath很难提取完整准确的内容规则复用性差不同网站的规则完全不能通用哪怕是同类型的网站也要重新写规则我之前统计过我做爬虫的时间里有60%的时间是在写和维护解析规则真正写爬取逻辑的时间只有30%剩下10%是在和反爬对抗可见解析规则的开发和维护占了多大的工作量。二、大模型网页解析的核心优势用大模型来做网页解析完美解决了传统解析的痛点开发效率高不需要写XPath规则只要给大模型一个Prompt告诉它你要提取什么内容它就能自动帮你提取开发速度提升10倍以上维护成本低网页改版之后不需要改代码只要稍微调整下Prompt甚至不用调整大模型就能自动适配新的页面结构可以处理非结构化内容不管是多么混乱的网页内容大模型都能理解语义准确提取你需要的信息就算没有固定结构也没关系规则通用同一个Prompt可以适配多个同类型的网站比如新闻网站的提取Prompt基本上所有新闻网站都能用不需要每个网站单独写我当时测试了10个不同的新闻网站用同一个Prompt解析准确率达到了95%以上比我自己写的XPath规则准确率还高而且只花了10分钟写Prompt效率提升非常明显。三、GPT-4o/DeepSeek-V2网页解析Prompt设计Prompt设计是大模型解析的核心Prompt写的好不好直接决定了解析的准确率和稳定性我试了几十种Prompt最终总结出了一套效果最好的Prompt模板分享给大家。3.1 基础Prompt模板你是一个专业的网页内容提取助手我会给你一段HTML代码你需要从中提取我需要的信息严格按照要求输出 ### 提取要求 1. 提取以下字段 - title新闻标题字符串类型 - publish_time发布时间格式为YYYY-MM-DD HH:MM:SS如果没有明确时间则输出空字符串 - author作者名称如果没有则输出空字符串 - source新闻来源比如新华网、澎湃新闻如果没有则输出空字符串 - content新闻正文内容完整提取保留段落结构不要包含广告、相关推荐、评论等无关内容 - tags新闻标签数组类型提取新闻的关键词标签最多5个 ### 输出要求 1. 严格按照JSON格式输出不要输出任何其他内容不要加markdown格式不要加解释说明 2. 字段名必须和上面要求的完全一致不要拼写错误 3. 如果某个字段没有找到就输出空值不要输出未找到、无之类的内容 4. 正文内容要完整不要遗漏重要信息不要有多余的空白字符 5. 时间格式必须严格按照YYYY-MM-DD HH:MM:SS如果只有日期没有时间就补充00:00:00 现在开始提取 HTML内容这个模板我测试过很多次对于大部分新闻网站的解析准确率都在95%以上你可以根据自己的需求修改提取的字段和要求。3.2 进阶优化技巧要想进一步提升准确率还可以在Prompt里加入这些优化点加入示例给大模型一个示例输入和输出让它更清楚你要的格式比如### 示例 输入HTMLh1测试新闻标题/h1div classtime2024-05-20 14:30/divdiv classauthor张三/divdiv classcontent这是新闻正文内容。/div 输出{title:测试新闻标题,publish_time:2024-05-20 14:30:00,author:张三,source:,content:这是新闻正文内容。,tags:[测试]}加入错误提示告诉大模型如果遇到错误的情况应该怎么处理比如如果HTML内容为空或者无法解析就输出所有字段为空的JSON。 如果发布时间的格式不对就尝试转换成要求的格式转换失败就输出空字符串。指定输出格式的严格性强调必须输出纯JSON不要有其他内容避免大模型输出多余的解释重要提示你的输出必须是纯JSON不要有任何其他文字不要加json之类的标记不要加任何解释直接输出JSON即可。3.3 不同大模型的Prompt差异我测试了GPT-4o、DeepSeek-V2、Claude 3 Opus这几个大模型它们的效果都不错但是Prompt稍微有点差异GPT-4o效果最好准确率最高不需要太复杂的Prompt就能得到很好的效果但是成本最高DeepSeek-V2开源模型可以本地部署成本非常低解析准确率比GPT-4o略低5%左右但是足够用Prompt需要写的更详细一点Claude 3 Opus支持很长的上下文适合解析非常长的网页比如几万字的长文准确率也很高成本比GPT-4o低一点如果你的数据量不大对准确率要求很高建议用GPT-4o如果数据量很大对成本比较敏感建议用DeepSeek-V2本地部署成本可以忽略不计。四、完整代码实现我把完整的Python代码分享出来你可以直接拿去用。4.1 依赖安装pipinstallopenai requests beautifulsoup4 lxml python-dotenv4.2 核心代码实现importosimportjsonimportreimporttimefromdotenvimportload_dotenvimportopenaifrombs4importBeautifulSoup# 加载环境变量load_dotenv()openai.api_keyos.getenv(OPENAI_API_KEY)# 如果用DeepSeek的话改下base_url# openai.base_url https://api.deepseek.com/v1defclean_html(html):清理HTML代码去掉不必要的标签减少Token消耗soupBeautifulSoup(html,lxml)# 去掉script、style、iframe、noscript等无关标签fortaginsoup([script,style,iframe,noscript,footer,header,nav,aside]):tag.decompose()# 去掉所有属性只保留标签内容fortaginsoup.find_all(True):tag.attrs{}# 压缩空白字符cleaned_htmlre.sub(r\s, ,str(soup)).strip()# 只保留前10000个字符避免太长超过Token限制returncleaned_html[:10000]defparse_html_with_llm(html,fields,modelgpt-4o-mini,max_retries3):用大模型解析HTML提取指定字段cleaned_htmlclean_html(html)# 构建Promptpromptf你是一个专业的网页内容提取助手我会给你一段HTML代码你需要从中提取我需要的信息严格按照要求输出 ### 提取要求 1. 提取以下字段{chr(10).join([f -{field[name]}{field[desc]}{field[type]}类型forfieldinfields])}### 输出要求 1. 严格按照JSON格式输出不要输出任何其他内容不要加markdown格式不要加解释说明 2. 字段名必须和上面要求的完全一致不要拼写错误 3. 如果某个字段没有找到就输出对应类型的空值不要输出未找到、无之类的内容 4. 字符串类型的字段内容要完整不要遗漏重要信息不要有多余的空白字符 5. 时间类型的字段必须严格按照YYYY-MM-DD HH:MM:SS格式如果只有日期没有时间就补充00:00:00转换失败就输出空字符串 重要提示你的输出必须是纯JSON不要有任何其他文字不要加json之类的标记不要加任何解释直接输出JSON即可。 现在开始提取 HTML内容{cleaned_html}# 重试机制foriinrange(max_retries):try:responseopenai.chat.completions.create(modelmodel,messages[{role:user,content:prompt}],temperature0,# 温度设为0输出更稳定response_format{type:json_object}# 强制输出JSON格式GPT-4o和DeepSeek都支持)resultresponse.choices[0].message.content.strip()# 解析JSONparsed_resultjson.loads(result)# 校验字段是否存在forfieldinfields:iffield[name]notinparsed_result:parsed_result[field[name]]iffield[type]stringelse[]returnparsed_resultexceptExceptionase:print(f解析失败重试第{i1}次{str(e)})time.sleep(1)# 重试3次失败返回空结果return{field[name]:iffield[type]stringelse[]forfieldinfields}if__name____main__:# 测试代码importrequests urlhttps://www.example.com/news/12345.htmlheaders{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36}responserequests.get(url,headersheaders)htmlresponse.text# 定义要提取的字段fields[{name:title,desc:新闻标题,type:string},{name:publish_time,desc:发布时间格式YYYY-MM-DD HH:MM:SS,type:string},{name:author,desc:作者名称,type:string},{name:source,desc:新闻来源,type:string},{name:content,desc:新闻正文完整内容,type:string},{name:tags,desc:新闻关键词标签最多5个,type:array}]resultparse_html_with_llm(html,fields)print(json.dumps(result,ensure_asciiFalse,indent2))4.3 自动适配网页改版的实现传统的解析方法网页改版之后就要改代码但是用大模型的话只要加一个规则校验和自动重试的机制就能自动适配大部分的改版defvalidate_result(result,fields):校验解析结果是否合法# 检查必填字段是否为空required_fields[f[name]forfinfieldsiff.get(required,False)]forfieldinrequired_fields:ifnotresult.get(field):returnFalse# 检查时间格式是否正确ifresult.get(publish_time):ifnotre.match(r^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$,result[publish_time]):returnFalse# 检查正文长度是否合理比如至少100个字符iflen(result.get(content,))100:returnFalsereturnTrue# 解析的时候先校验如果不合法就重试或者自动调整Promptresultparse_html_with_llm(html,fields)ifnotvalidate_result(result,fields):# 第一次解析失败调整Prompt加入更多的提示print(第一次解析失败调整Prompt重试)# 可以在这里动态调整Prompt比如加入更多的提取要求resultparse_html_with_llm(html,fields,modelgpt-4o)# 换更大的模型重试ifnotvalidate_result(result,fields):# 还是失败报警人工处理print(解析失败需要人工处理)# 发送钉钉告警这样大部分的网页改版都能自动适配只有极少数改版幅度非常大的情况才需要人工介入维护成本非常低。五、新闻网站非结构化内容采集实战我当时用这套方案做了一个新闻聚合项目爬取30个不同的新闻网站每天爬取1万条新闻给你看下实际的效果。5.1 准确率对比解析方式开发时间平均准确率维护成本每月适配改版时间传统XPath7天90%10人小时3天大模型解析2小时95%1人小时0自动适配准确率比传统XPath还高5%因为大模型可以识别出广告和无关内容不会把这些内容提取到正文里而XPath经常会把广告、相关推荐之类的内容也提取进来。5.2 效率对比传统方式每个网站写解析规则要2小时30个网站要60小时每月维护要10小时大模型方式写一个通用Prompt要2小时30个网站直接用每月维护只要1小时效率提升了不止10倍而且网站越多优势越明显。5.3 实际效果展示我随便拿一个新闻页面的解析结果给大家看{title:我国首艘大型邮轮“爱达·魔都号”开启首航,publish_time:2024-05-26 10:30:00,author:王记者,source:新华社,content:5月26日我国首艘国产大型邮轮“爱达·魔都号”从上海吴淞口国际邮轮港出发开启首次商业航行。\n“爱达·魔都号”总长323.6米型宽37.2米总吨位13.55万吨拥有2826间舱室最多可容纳6500名乘客。船上配备了丰富的休闲娱乐设施包括剧院、免税店、餐厅、水上乐园等。\n据介绍“爱达·魔都号”的首航航线为上海-济州-长崎-上海为期5天4晚后续还将开通前往东南亚等地的航线。,tags:[大型邮轮,爱达·魔都号,首航,国产,邮轮产业]}提取的信息非常准确而且正文内容完整没有无关的广告和导航内容。六、Token成本优化技巧很多人担心用大模型解析成本太高其实只要优化得当成本非常低我爬1万条新闻总成本才几块钱完全可以接受。我给大家分享几个成本优化的技巧6.1 清理HTML减少Token消耗HTML代码里有很多无关的内容比如script、style标签大量的属性空白字符等这些内容都会消耗Token我们可以在把HTML发给大模型之前先清理掉我前面代码里的clean_html函数就是干这个的一般可以减少70%以上的Token消耗成本直接降为原来的1/3。6.2 用小模型优先大模型兜底比如先用GPT-4o-mini或者DeepSeek-V2-chat这些便宜的模型解析准确率可以达到90%以上只有解析失败的时候才用GPT-4o或者Claude 3这些大模型兜底这样成本可以降低80%以上。我当时的策略是第一次用GPT-4o-mini解析成本是0.15美元/百万Token非常便宜如果解析失败或者校验不通过再用GPT-4o解析成本是5美元/百万Token但是只有10%左右的请求会走到这一步平均下来每次解析的成本不到0.001元爬1万条才10块钱非常划算6.3 批量解析减少请求次数如果有多个短的网页可以把它们合并成一个请求发给大模型让大模型一次性解析多个页面这样可以减少请求的 overhead也能节省Token。比如把5个短新闻的HTML合并到一个请求里让大模型输出一个数组这样成本可以降低30%左右。6.4 本地部署开源大模型如果你的数据量很大每天要爬几十万条数据建议本地部署开源大模型比如DeepSeek-V2-7B、Qwen-2-7B这些部署在自己的服务器上成本几乎为零只要付服务器的电费就行而且数据不会外流安全性更高。我测试过一张3090显卡就可以跑7B的模型每秒可以处理2-3个请求每天可以处理几十万条数据完全满足大部分人的需求成本只有调用API的1%都不到。6.5 缓存解析结果对于已经解析过的页面或者结构相同的页面可以把解析结果缓存起来下次遇到相同或者相似的页面直接用缓存的结果不需要再调用大模型这样可以节省大量的成本。比如同一个网站的列表页结构都是一样的只要解析一次后面的都可以复用规则。七、踩坑经验总结用大模型做解析的过程中踩了很多坑这些都是大家容易遇到的分享出来帮大家避坑坑1大模型输出的JSON格式不对解析失败最开始我经常遇到大模型输出的JSON格式有问题比如少了逗号引号不闭合或者输出了多余的内容导致json.loads失败。解决方案用大模型的JSON模式比如GPT-4o的response_format{type: json_object}参数强制大模型输出合法的JSON大部分情况都能解决用JSON修复库比如json_repair如果解析失败自动修复JSON格式90%以上的格式错误都能修复在Prompt里反复强调必须输出纯JSON不要有其他内容加在最显眼的位置坑2大模型产生幻觉提取不存在的内容有时候大模型会编造一些不存在的内容比如没有作者的时候它会编造一个作者名字或者把广告里的内容当成正文提取出来。解决方案温度设为0降低幻觉的概率temperature0的时候大模型的输出会非常稳定幻觉少很多在Prompt里明确要求“如果某个字段没有找到就输出空值不要编造内容”加校验逻辑比如提取的内容如果在原始HTML里不存在就认为是幻觉丢弃或者重试对于重要的字段可以做多轮校验比如第一次提取之后再让大模型检查一遍内容是不是真的存在于HTML里坑3HTML太长超过Token限制很多长网页的HTML非常长超过了大模型的上下文窗口导致无法解析。解决方案清理HTML去掉无关的内容只保留正文相关的部分我前面的clean_html函数会只保留前10000个字符足够提取大部分内容对长网页做分段解析把HTML分成几段分别提取内容最后合并结果用支持更长上下文的模型比如Claude 3 Opus支持200K上下文GPT-4o支持128K上下文足够处理大部分长网页用浏览器渲染之后只提取文本内容不要把整个HTML发过去比如用Playwright渲染页面之后提取body的文本内容这样可以减少很多Token坑4解析速度慢跟不上爬取速度大模型API的响应时间一般是1-3秒比传统的XPath解析慢很多如果爬取速度很快的话解析会成为瓶颈。解决方案用异步调用同时发起多个解析请求比如用aiohttp异步调用OpenAI API并发10个的话每秒可以处理3-5个请求足够应对大部分爬取速度用消息队列做缓冲爬取到的网页先放到Kafka里解析服务慢慢消费不会因为解析慢导致爬取层卡住本地部署大模型本地模型的响应速度比调用API快很多7B的模型每秒可以处理2-3个请求并发多开的话速度会更快八、考点/技巧提炼这部分是核心知识点面试的时候经常会问到工作中也非常实用1. 大模型解析和传统解析的适用场景分别是什么传统解析XPath/CSS适合结构稳定、爬取量极大、对成本非常敏感的场景比如爬取大型电商平台的商品数据网站结构几个月都不变爬取量几百万条用传统解析更划算大模型解析适合结构多变、爬取量中等、对开发效率要求高的场景比如爬取大量不同的小型网站、非结构化内容提取、需要快速上线的项目用大模型解析开发效率高维护成本低2. 怎么提高大模型解析的准确率写清晰明确的Prompt把提取要求说清楚不要有歧义加入示例让大模型更清楚你要的格式和内容用合适的模型复杂的场景用大模型简单的场景用小模型加校验逻辑解析失败自动重试或者换大模型兜底定期抽查解析结果发现问题及时调整Prompt3. 怎么平衡解析的准确率和成本分层解析先用便宜的小模型失败了再用贵的大模型缓存结果相同或者相似的页面不要重复解析优化Token消耗清理HTML减少不必要的内容本地部署开源模型数据量大的时候成本可以忽略不计4. 大模型解析的合规性问题用大模型解析网页的时候要注意不要爬取涉密或者个人隐私内容遵守网站的robots协议如果你要把解析的内容用于商业用途要确保有合法的授权调用第三方API的时候不要把敏感数据比如用户的个人信息发给大模型避免数据泄露总结大模型给爬虫领域带来的变革是革命性的它把我们从繁重的解析规则开发和维护工作中解放出来让我们可以把更多的精力放在更有价值的事情上比如反爬对抗、数据分析、数据应用等。我现在做爬虫项目除非是爬取量特别大、结构特别稳定的场景否则我都会优先用大模型做解析开发效率提升10倍以上维护成本也低很多真的非常香。当然大模型解析也不是万能的它有自己的适用场景我们要根据实际情况选择合适的技术方案不要为了用大模型而用大模型。