ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

电商数据采集系统实战:从爬虫到稳定数据管道

电商数据采集系统实战:从爬虫到稳定数据管道 近两年我一直在一家做电商数据服务的团队里写采集程序每天打交道最多的就是商品页、价格页、评价页这些看起来简单、实际处处是坑的数据源。团队内部从零到一沉淀了一套叫xxxwww的采集方案核心目标就是解决电商场景下高频、多站点、字段不稳定这三件事。这篇文章说的“实战案例”就是这套方案从最初几十行的实验原型逐步变成每天承载几百万商品数据采集任务的完整过程。如果你是刚接触爬虫的可以重点看第二、三节能理解电商爬虫到底在解决什么问题、一个能上生产的采集系统要具备哪些模块。如果已经在用Scrapy或者其他框架做过采集第四节和第五节关于调度、稳定性、字段兜底的内容应该是你最容易有共鸣的部分。我会尽量把参数、配置、踩坑过程都摆出来而不是只讲概念。1. 项目背景电商数据采集的现状与难点1.1 电商爬虫到底在爬什么很多人以为电商爬虫就是“把商品标题和价格抓下来”真做了才知道这只是冰山一角。我在实际项目中接触到的需求通常包括几类价格监控需要在固定时间粒度内记录商品价格变化用于比价或者活动效果分析选品调研要采集某个类目下的商品列表、销售数量、评价数、上架时间辅助判断市场容量评论分析把用户评价抓下来做情感分析或者卖点挖掘这个对数据量和清洗要求都很高还有供应链侧的库存跟踪监控SKU的上下架状态、规格变化、地区库存差异。单看任何一个需求都不难但把它们组合起来就麻烦了。同一个商品可能同时需要价格、评论、库存、规格四类数据更新频率还不一样价格可能要每小时抓一次评论可能一天一次就够规格变化则可以一周同步一次。如果都用一套任务去跑要么降低效率要么把对方平台的压力放大最终的结果就是封IP、封账号数据断供。所以电商爬虫的第一课其实是“分清你要什么别什么都抓”。1.2 为什么需要xxxwww这样的专门方案市面上不缺少爬虫框架Scrapy、Colly、还有各种可视化采集工具能力都不差。我用Scrapy做了两年多项目说实话它确实稳定生态也丰富但在电商场景里我自己会遇到几个绕不开的痛点。第一个痛点是调度和状态管理。电商爬虫很少是单机任务尤其是价格监控这种高频任务一台机器跑一个平台可能没问题但要同时跑二十个平台、几十个任务就需要一个统一调度的东西。Scrapy的调度是单机内存层面的跨机器协调基本要靠自己搭。第二个痛点是解析规则和字段的频繁变动。电商页面改版是家常便饭今天选择器还能选到价格明天可能就要换一个路径。如果把解析代码写在蜘蛛文件里每次改完都要重新发布、重启任务这在生产环境里非常低效。第三个痛点是抓取质量和数据校验。电商数据字段之间有关联关系比如SKU缺失时价格其实没意义评论内容为空时评分可能异常。通用爬虫框架很少关心这些事情而数据服务团队最怕的就是数据错误比数据缺失更麻烦。这几个问题反复出现之后我们内部开始积累一套自己的工具和规范也就是后来的xxxwww。它不是要替代Scrapy而是把采集任务用一种更接近“数据工程”的方式组织起来任务可配置、规则可热更新、节点可以横向扩展同时把数据校验从抓取流程里独立出来。这样一来团队里负责写爬虫的同学不用再关心分布式调度负责数据治理的同学也不用去读爬虫代码职责边界清楚了很多。2. xxxwww的核心设计与技术选型2.1 架构分层调度中心、采集节点、解析引擎、存储层xxxwww的整体设计其实不复杂核心思路是把一次完整的采集任务拆成四个层面。调度中心负责任务拆分、队列管理、失败重试。所有采集任务在这里定义成JSON格式的配置包括目标站点、采集频次、字段映射、关联代理策略。这个配置是一个任务的核心资产直接存在Redis或者数据库中不跟代码绑定。采集节点是无状态的Worker只负责一件事从队列里拿任务按照配置去请求页面把抓到的HTML或者JSON原文暂存到本地或者消息队列里。节点不关心数据最终去哪也不负责解析这样设计的好处是节点可以随时加机器也可以随时下线不会影响其他模块。解析引擎是独立于采集过程运行的它读取暂存的页面内容根据任务配置里的解析规则抽取出结构化字段。这部分设计解释一下很多爬虫方案把解析写在抓取之后马上做这样看起来实时性高但一旦页面改版解析规则报错整条链路就断了。xxxwww把解析从抓取中解耦即使解析失败原始页面还在修复规则后可以重新解析不需要再次请求目标站点。存储层是数据出口支持写入MySQL、ClickHouse、Elasticsearch或者简单的JSON文件。实际项目中我们主力用的ClickHouse因为商品价格和评论数据量大分析查询多ClickHouse的列式存储非常合适。小规模场景下直接用MySQL也能跑得很稳。2.2 为什么选择这样设计先说调度中心从代码中分离这件事。电商平台的采集任务数量是动态变化的比如双十一前商品数量会突然增加如果任务定义写死在代码里每次调整都要走发布流程等到审批完再上线数据窗口早就过了。用配置化任务的好处是运营同学自己都能在后台调整采集频率和商品范围不需要经过开发。采集节点无状态这个是核心它让整个系统获得了很好的弹性。遇到对方平台页面结构大改、需要加班重写解析规则的时期节点数量都是往下降的因为不需要抓新的数据反而要把队列里积压的存量数据处理完。当解析修复后要追历史数据的时候节点数量可以随时往上加加机器不需要改任何配置只要启动新的Worker实例即可。解析引擎独立这块可能有人会觉得多此一举徒增中间环节。但我实际操作下来这个设计让系统的可用性提升很多。以前用Scrapy直接抓完就解析一旦页面微调整个任务就会报错积压的请求全部白费。现在抓取和解析分离即使解析挂了原始数据还在本地文件或者消息队列里随时可以重新跑给运维留出了缓冲时间。存储层之所以没有绑定具体数据库是因为电商数据有几个不同的去向。价格数据进入分析库做趋势计算评论数据进入搜索引擎做关键词聚合商品快照数据进文件系统备份。直接绑定某一种存储会把系统做窄也增加了后续替换的改造成本。2.3 与其他方案的对照维度Scrapy方案xxxwww方案分布式能力需要额外搭配scrapy-redis等组件调度中心原生支持节点无状态解析规则更新改代码重新发布改配置下一轮自动生效抓取与解析紧耦合解耦原始数据先落盘数据校验需要自己写pipeline独立的校验步骤规则可配置适合场景中小规模、页面稳定多平台高频、字段变化频繁这个对照不是要踩Scrapy它依然是很好的框架。我只是想说当你的采集规模到了几十个站点、几百个任务、每天千万级请求的时候调度、配置、校验这些问题会超过“写爬虫”本身变成数据工程问题需要从系统层面去解决。3. 实操过程在电商场景中落地xxxwww3.1 初始化项目和采集目标梳理拿我们做过的某个美妆电商平台项目举例。这个项目的要求不算特别复杂每天同步一次全站商品信息包括商品标题、价格、销量、评价数、规格、上下架状态大概六万多个SKU。听起来量不大但页面接口有反爬策略普通请求频率一高就会被限流。落地第一步是梳理采集目标。我们把字段拆成两个表商品基础信息表和价格历史表。基础信息表每天全量更新价格历史表每次抓到价格变化就插入一条记录。这样设计的目的很明确基础信息表反映当前状态价格历史表反映时间序列后续做价格走势分析可以直接查询不用再对全量表做按日分区。字段定好之后在xxxwww里建立采集任务配置。配置的核心字段有几个任务名称、入口URL模板、分页参数、采集深度、字段映射表、更新频率。入口URL模板需要支持占位符因为商品详情页的URL通常是固定的格式比如商品ID要通过列表页拿到然后再拼成详情页地址。3.2 商品列表页与详情页的抓取配置采集过程分为两步第一步抓列表页第二步抓详情页。列表页用来获取商品ID和基础摘要信息详情页用来获取完整字段。列表页的配置重点是分页逻辑和翻页频率。xxxwww里可以设置每页条数和最大翻页数还需要设置随机延时区间避免请求间隔太规律被识别。以这个美妆平台为例列表页每页60条商品六万多个SKU大概要翻一千页。我们设置的是每页抓取后随机等待0.5到1.5秒单机跑完列表页需要十五到二十分钟时间在凌晨执行完全可以接受。详情页的字段比较多需要配置解析规则。xxxwww的解析引擎支持CSS选择器和XPath两种方式。我个人的经验是优先用CSS选择器因为它简洁、易读改起来不容易出错遇到需要根据标签层级关系判断的情况再用XPath。比如商品标题多数平台会放在h1或者特定的meta标签里CSS选择器直接选就行但是规格参数这种通常在一个表格里不同商品的表格结构可能不一样需要写相对复杂的XPath表达式。这个项目的详情页有个麻烦点商品价格在不同状态下显示的节点不一样有正常价格、促销价格、会员价格甚至部分地区缺货时不显示价格。如果只写一条选择器很容易抓到空值。xxxwww的解析配置里支持多选择器回退也就是说可以按顺序配置多个选择器第一个取不到就尝试第二个全部取不到就标记为异常字段。这个功能在电商场景里太常用了。3.3 数据清洗与落库抓取完成只是开始清洗是决定数据质量的关键环节也是容易被新手忽略的部分。原始抓下来的字段里什么都有价格可能是“¥99.00”这样的字符串销量可能是“1.2万”这种带单位的表达评论数可能是“好评率98%”这种混杂文本。这些都要转成可以分析的结构化数据。xxxwww里每个字段映射可以配置多个清洗函数按顺序执行。比如价格字段先做正则提取数字部分再去掉小数点后多余的零最后转成Decimal类型。销量字段“1.2万”要特殊处理先判断是否包含“万”包含就乘以10000再去掉“”号。这类规则不复杂但是必须针对每个平台单独配因为每个平台的文本格式都不同。清洗完之后进入校验步骤。我们配了三个规则价格不能为0且不能超过十万销量不能小于0关键字段不能为空。任何一条校验不通过的数据会进入异常队列而不是直接丢弃或者写入脏数据。异常队列里的数据可以人工查看也可以等解析规则更新后重新跑。这里多说一句校验规则宁严勿松因为下游分析的同学默认数据是可信的脏数据只要漏进去一条就可能影响整个报表结论。最后落库到ClickHouse基础信息表用商品ID做分区键价格历史表用日期做分区键。这样每天凌晨跑完增量任务后分析团队可以直接按日期查询不用再做复杂的预处理。4. 核心环节拆解稳定性与反爬应对4.1 请求频率控制与代理池策略电商平台的反爬策略这两年升级速度很快已经不满足于简单的请求频率限制还会检测请求头的一致性、访问路径的行为模式、账号的登录状态。xxxwww在请求控制这一层的设计我拆分一下各个部分的作用。请求头配置不是随便填个UA就行要做到“整站一致”。什么意思如果浏览器环境是Chrome在Windows上访问那么UA、Accept、Accept-Language、Sec-Fetch这些头要保持一个组合不要混搭。很多新手会抓取的时候用了一个定制UAAccept-Language却是英文或者缺失这在服务端看来就是异常信号。xxxwww允许为每个站点配置一组独立的请求头模板采集节点发送请求时直接套用不用在代码里硬编码。请求频率控制用的是令牌桶算法。每个站点有独立的并发上限和每秒请求数上限比如这个美妆平台我们设的是并发2、每秒最多3个请求。刚开始的时候这个数值还要更保守一些跑一段时间观察有没有被限流再逐步调高。不要一上来就希望最大并发那样大概率第一天就把任务跑挂了。代理池配置是专门为稳定性准备的。我们的代理池分为三层免费代理、付费短效代理、长驻住宅代理。日常采集用付费短效代理就够了成本低稳定性尚可遇到平台风控严格或者需要长期跟踪的账户数据才切到住宅代理。xxxwww支持给不同任务指定不同的代理组任务代理失效时自动重试每次重试会换一个新的代理。这里有个实际经验代理重试的上限不要设太高三次足够了超过三次说明当前代理池整体质量有问题继续重试只会浪费时间应该触发告警让人来检查。4.2 解析规则维护与异常兜底页面改版永远是电商爬虫的第一大杀手。我经历的电商项目里没有哪一个平台的页面能半年不变。解析规则的维护实际上占了整个项目维护工作量的六成以上。xxxwww在设计解析模块时想到的最关键一点是“规则可热更新”。解析配置文件存在管理后台或者独立的配置中心里Worker在每次解析前会检查配置版本号如果版本号变了就重新读取。这意味着规则改动之后不需要重启任何进程下一批任务进来就会使用新规则。这个能力在应对紧急页面改版时非常有用深夜发现解析报错我只需要在后台把规则调整好系统会自动恢复不用连夜赶回公司改代码重新发布。当然规则热更新不是银弹有些页面改版是结构性的比如整个商品详情页从服务端渲染改成了前后端分离HTML里根本没有商品数据了这种情况光改选择器没用需要重写整个解析模板。所以xxxwww也支持针对某个任务配置“自定义解析脚本”用Python写一段完整的解析逻辑放在配置中心里Worker动态加载执行。这个能力要谨慎使用因为脚本带来的灵活性和隐患是对等的用多了系统会变得难以维护。异常兜底是解析模块的另一块重要设计。每个字段除了配置主选择器和回退选择器还可以配置一个默认值。比如评论数抓不到的时候填0上下架状态抓不到的时候填“未知”。这个设计不是为了制造假数据而是让数据管道不断流。一条数据的字段缺失不会影响整批数据的写入。标记为异常的字段会单独记录等规则修复后可以用另一个重跑任务把历史异常数据再拉出来重新解析。4.3 分布式节点的调度与扩容当任务数量和站点数量上来了单机Worker必然遇到瓶颈。xxxwww的分布式调度逻辑用了Redis作为消息队列任务状态存在Redis的Hash结构里每个站点一个队列。Worker启动后从Redis拉取任务处理完把状态更新回Redis进度信息通过心跳上报。这里有一个容易被忽略的问题任务队列的消费速度不均衡。不同平台的响应速度差异很大有的平台接口200毫秒就返回有的要3秒。如果所有任务都塞进同一个队列慢任务会拖累快任务的进度。我们最初就吃过这个亏后来调整为每个站点建一个队列Worker订阅多个主题快的站点任务不会被慢的阻塞。这个改动本身不难但对整体任务耗时的影响非常明显。扩容节点也很有意思。因为Worker是无状态的扩容不需要做任何数据迁移。新启动的Worker会自动从Redis队列里拉取任务不需要Leader节点分配。当一个Worker异常退出它正在处理的任务会在超时后重新进入待处理队列被其他Worker捡走。这里要注意任务超时时间要设置合理太短会导致慢请求的任务被重复消费太长则会影响故障恢复速度。我们线上设置的是5分钟基本能覆盖绝大多数慢请求场景。5. 常见问题与排查技巧实录5.1 商品字段频繁变动怎么排查字段变动是所有电商爬虫日常都要面对的事情。我总结的排查路径分三步。第一步看监控报表。xxxwww会为每个任务记录“字段解析成功率”如果某个字段的解析成功率往下跌说明这个字段对应的选择器可能失效了。打开任务详情页能看到每个字段最近24小时的成功率趋势以及最近失败的具体样本。第二步核对页面结构。找到一条失败样本对应的原始HTML用浏览器的开发者工具重新检查字段所在位置确认选择器是否需要更新。这里有个小技巧别直接在控制台里用document.querySelector验证就完了要注意这个选择器是否匹配多个节点电商页面经常有隐藏的重复节点选择器和你在控制台里看到的返回结果要一致才行。第三步更新规则并触发重跑。如果只是选择器问题直接在配置中心修好保存后等下一轮任务自动使用新规则即可。如果想马上把失败的历史数据处理掉可以手动触发一次“仅重解析”任务它能从暂存区读取历史原始HTML用新规则重新抽取字段整个过程不需要重新请求目标网站。5.2 采集任务队列积压怎么处理队列积压通常发生在两种情况一种是平台响应变慢任务处理平均耗时长了一倍另一种是解析模块故障导致Worker卡在某个环节无法继续。排查队列积压时第一步先看监控面板里吞吐量的趋势确认是吞吐下降还是任务新增激增。如果是平台响应变慢可以在短时间内增加流量控制防止继续发送大量请求把平台逼到主动封禁。同时增加Worker节点来提升整体吞吐。要注意增加节点不是无限制的因为目标平台的服务端是单方瓶颈请求总量达到一定水平后响应时间还会进一步恶化。所以更稳妥的做法是重新评估任务优先级把低频任务暂停集中资源处理高频的核心任务。如果是解析模块故障导致积压要快速定位到具体任务、找到异常原因。xxxwww的Worker日志此时就派上用场了它会记录每条任务的处理耗时和各阶段的状态变化。找到故障点之后先暂停对应任务让其他任务继续跑再修复解析规则。不要试图在Worker运行中去改解析脚本还是那句话灵活性大的代价是可控性差。5.3 价格和库存数据对不上怎么办电商爬虫最怕的事情是数据对不上。比如价格表里记录了一个价格但用户实际下单页面显示的是另一个价格。这个问题排查起来很麻烦因为可能是抓取时页面渲染没完成抓到的还是缓存数据也可能是存在地区差异或者登录态差异导致不同请求看到的同一商品价格不一样。这类问题的根治思路是在源头做约束。在配置任务时尽量保持同一商品的价格请求来自同一个地区和同一种登录状态。比如这个美妆平台匿名状态下看到的价格和登录后的会员价不一样我们就统一用匿名状态抓取并且明确字段名称为“公共价”而不是“成交价”避免下游误解。另一个常见原因是页面中存在动态加载。很多电商平台的商品价格不是直接写在HTML里的而是先加载页面骨架再通过接口异步获取价格数据更新到页面节点上。如果Worker获取HTML的时机太早抓到的是初始状态价格节点为空或者为占位符就会被漏掉或误判。解决方案是在抓取配置里启用“等待页面加载完成”的机制xxxwww支持设置最长等待时间和等待条件条件可以是一个DOM节点出现或者消失。5.4 常见问题速查表问题现象可能原因处理办法字段解析成功率突然下降平台页面改版选择器失效查看失败样本更新选择器单任务耗时突然增长代理质量变差或平台响应变慢检查代理池健康度调整并发与限速大量请求返回403请求头组合异常或IP被限核对请求头一致性切换代理组队列积压但节点繁忙解析脚本效率低或卡在IO查看日志定位耗时环节优化脚本数据出现重复重试机制超时设置不合理调大任务超时时间增加任务幂等键6. 一点个人体会电商爬虫做了这么久我一直觉得真正难的从来不是“写爬虫”而是让一个爬虫系统长期稳定地跑下去。前端框架换了一轮又一轮平台的反爬策略也跟着变如果整个系统的架构没有为变化留好余地每次页面改动都要伤筋动骨那这个项目很快就会被维护成本拖垮。xxxwww这套方案能坚持用下来靠的不是某个单项技术有多强而是它在“快速修改”和“稳定运行”之间找了一个平衡点。最后再分享一个我自己很在意的细节监控是爬虫系统里投入产出比最高的部分没有之一。很多团队重视开发轻视监控结果线上出了问题只能靠用户反馈才发现数据已经断了好几个小时。我建议任何做爬虫的团队都要先配置好一套包含“任务成功率”“节点存活状态”“队列积压量”三个核心指标的监控看板宁可没有花哨的报表也要把这三个盯住。数据采集团队能不能睡得着觉全看它们。
返回列表