资讯动态

二手闲置平台商品数据抓取程序工程化实践:从字段设计到防封策略

发布时间:2026/10/20 5:58:47 来源:尧图企业网站定制
做二手生意的人或者搞市场调研的人多半都动过这样的念头把平台上在售的商品信息批量抓下来分析一下价格走势、上新节奏和热门品类。标题里的“咸鱼”按下不表先把它当成一个专做C2C交易的二手闲置平台全文统一叫它目标平台或二手闲置平台。这类程序的需求其实很清晰定时抓取商品标题、价格、成色、发布地区、发布时间存进自己的数据库再做筛选和报表。可标题里那句“100%成功”着实把人带偏了真实世界没有100%的成功率但我们可以通过一套设计把成功率从“碰运气”拉高到“工程化、可持续”。这篇文章就围绕一个目标平台的商品数据抓取程序把方案设计、字段规划、具体代码、踩坑排查和合规边界一次讲完适合刚接触爬虫的开发者也适合想把自己内部采集脚本工程化的朋友。1. 先把“100%成功”这个话掰开揉碎1.1 任何爬虫项目都没有“一次成功”这回事我见过不少项目需求开头动不动就写“全自动”“100%成功”“稳定不封”等到真跑起来才发现这些词只能当愿望不能当验收标准。商品数据抓取程序面对的是一个动态系统页面结构会改版、接口参数会加签名、风控策略会升级、商品本身会下架、价格会调整甚至用户所在地不同看到的商品列表都不一样。只要任何一个环节发生变化你昨天还跑得好好的脚本今天就可能全部扑空。所以我做的第一件事永远是转移预期不保证100%成功但保证每一类失败都有日志、有重试、有兜底。把“100%成功”翻译成工程语言其实是“足够高的成功率 失败自动恢复 长时间稳定运行”。这个标准反而更能落地。真正成熟的采集程序不是不出错而是出错之后能自己爬起来并且天亮之后你能从日志里定位到错在哪。1.2 先回答三个问题抓什么、干什么、怎么存很多新手上来就问“用什么框架”我反而会先问“你到底要分析什么”。同样是抓商品数据需求不同设计完全不同。比如有人想做选品分析那他需要商品ID、标题、价格、销量、成色、地区、上架时间还要保留历史价格有人只想做价格提醒那只需盯住少数几个商品ID定时拉取价格成本极低还有人想监控同行上新那就得高频扫描某个卖家的在售列表这和选品全库抓取是两种任务。我常建议用一个表格先把字段定下来。字段不是越多越好够用就行。一般来说商品数据抓取程序至少要包含这几类商品唯一标识ID、标题、当前价格、原价或参考价、运费、成色/使用程度、所在地、发布时间、商品状态在售/已下架、关键图片URL。如果要做卖家维度分析再加一个脱敏后的卖家标识但不要碰手机号、IM号、聊天内容这些个人隐私字段。采集边界一旦划清楚后面写解析代码、建表、清洗都会顺很多。1.3 动手前先做合规自查这里的合规不是套话是真的能帮你少惹麻烦。我自己接过一个模拟项目X需求是监控某二手平台某类目下的价格分布。第一版脚本写得很快但上线前我停下来查了三件事目标平台是不是有官方开放接口、网站robots协议怎么写的、公开的商品数据里有没有个人信息。结果发现平台有面向开发者的开放数据通道虽然接口覆盖的商品字段比页面少一些但胜在稳定合法。最终方案改成了“官方接口为主、页面采集为辅”既满足分析需要又避开了大部分风控风险。如果你确实只能做页面采集那就记住几个原则只采集公开可见的信息绝不绕过登录权限不批量下载图片不把采集频率压到影响平台正常服务的程度不把数据用于二次售卖或恶意营销。个人数据保护方面也要留个心眼涉及个人昵称、信用分等字段能不用就不用不得不用就做脱敏。合规不是项目的阻碍它其实是让项目能长期跑下去的护栏。2. 数据字段和链路设计别一上来就写爬虫2.1 商品数据字段怎么定我建议你动手敲代码之前先在纸上把字段清单画出来。下面是基于常见二手交易场景整理的一份字段参考表你可以按需增删。字段示例值用途注意事项商品ID6382...去重和关联详情要选稳定的唯一标识不要用标题做ID标题99新 大疆无人机品类判断、关键词搜索注意清洗换行和空格当前价格2599.00价格分析保留两位小数字符串转浮点数原价/参考价3999.00折扣分析没有时填NULL别强制填0运费0.00实际购买成本有的商品卖家包邮有的到付成色99新二手商品核心特征可能是枚举文本统一映射所在地广东 深圳地域分析可能需要从省市区字符串里拆分发布时间2026-01-18 14:30上新监测注意时区商品状态在售/已下架/已售出生命周期管理每次采集都更新图片URLhttps://...留存缩略图仅存URL不主动下载卖家标识masked_uid_123卖家维度分析必须脱敏不能是原始ID抓取时间2026-01-18 15:00历史版本比对每条记录都要有时间戳这个表不是为了好看而是为了告诉你每一份数据将来有什么用。比如“发布时间”这一项很多二手商品是短期发布的它能帮你看清楚平台每天真实上新在几点也能辅助判断一个卖家是不是在频繁刷屏。2.2 数据入口怎么选列表页、详情页还是接口目标平台给爬虫的信息入口通常有三个搜索结果页、类目列表页、商品详情页。列表页请求数量少一个页面能拿几十个商品的基础字段适合做全量扫描比如“这个平台现在一共有多少台某品牌的相机在卖”。详情页信息完整但一个页面只有一件商品适合对重点商品做精细追踪比如你要盯住某个卖家的某台机器什么时候降价。我自己的做法是分层采集第一层用列表页抓“候选商品”只拿商品ID、标题、价格、缩略图这几项第二层再根据商品ID进详情页补齐描述、成色、卖家信息。这样做的好处是列表页变动频率高但单次成本低即使列表页解析出错也不会丢掉已经抓到的商品详情。如果平台有移动端或H5的JSON接口数据质量普遍比解析HTML更稳定可以优先评估但要注意接口鉴权字段是否允许公开调用。总之一句话能用公开接口就别碰页面解析能用页面解析就别碰流量轰炸。2.3 全量采集和增量更新怎么搭一套商品数据抓取程序最忌每次都是全量重来。全量抓一遍可能要几万次请求既慢又容易被限流。更好的做法是把任务拆成“首轮全量 每日增量 定时详情刷新”。首轮全量用于把数据库从零填起来之后每天的增量任务只抓“新发布的商品”而已经入库的商品按各自生命周期单独调度。增量更新的核心是“上次抓取时间”和“商品状态”两个字段。比如凌晨2点定时跑增量只抓发布时间在24小时内的商品而那些在售中的老商品每6小时做一次价格刷新就行。这个设计能把请求量降一个数量级也让数据可靠性大幅提高。我曾经把一个每天请求几十万次的脚本改成这种分层调度后日请求量降到三万以内数据完整度反而提升了因为没那么容易被频控了。3. 实操从请求到入库的完整过程3.1 请求层的基本代码不管用什么框架请求层都要具备四样东西超时设置、重试机制、退避策略、请求头管理。下面这段示例用的是Python的requests库逻辑很简单但已经能扛住大多数日常场景。import time import requests HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36 } def fetch_html(url, max_retry3): for attempt in range(max_retry): try: resp requests.get(url, headersHEADERS, timeout8) if resp.status_code 200: return resp.text if resp.status_code in {403, 429}: # 遇到风控先停下来降低频率 wait_time 5 * (attempt 1) time.sleep(wait_time) continue except requests.RequestException: time.sleep(2) return None这套代码看起来普通但有两个容易被忽略的点。第一个是timeout必须设置不设置的话一个卡死的连接可能拖垮整个调度任务。第二个是403、429不能立即重试要按指数退避等待等待时间可以加上随机抖动比如1.5s、3s、6s避免所有请求整齐划一地同时重试反而触发更大规模的封禁。3.2 页面解析和字段提取请求拿到HTML之后解析层最常用的还是CSS选择器或XPath。我习惯用parsel库因为它的语法和Scrapy同源将来迁移到异步爬虫时改动很小。from parsel import Selector def parse_list_page(html): sel Selector(texthtml) items [] for card in sel.css(div.item-card): item_id card.xpath(data-id).get() title card.css(a.title::text).get() price card.css(span.price::text).get() location card.css(span.location::text).get() items.append({ item_id: item_id, title: title.strip() if title else , price: parse_price(price), location: location.strip() if location else }) return items这里我强调一个坑不要直接用text()裸提取因为前端模板改版后原来的span.price可能变成div.price你应该把“CSS选择器”和“字段名”做成一张配置表存起来页面改版时只改配置不改代码。另外价格字段常常会同“¥”或“包邮”混在一起直接转float会报错得先做一层清洗比如把非数字字符去掉再转。3.3 去重和入库入库环节我推荐先建好数据库表再把唯一索引加上去。商品ID就是天然的去重键如果同一ID重复抓取应该用INSERT ON CONFLICT或UPDATE而不是插入新行。CREATE TABLE product_snapshot ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_id TEXT NOT NULL UNIQUE, title TEXT, price REAL, location TEXT, status TEXT DEFAULT on_sale, first_seen_at DATETIME, last_seen_at DATETIME, UNIQUE(item_id, status) );去重不要只用item_id还要加上状态维度。同一件商品今天在售明天可能已售出后天价格又变了。如果只留一条最新快照历史变化就全丢了如果每抓一次都插一条新纪录数据表会膨胀得非常快。折中的方案是维护两张表一张是“商品主表”记录商品当前状态一张是“价格历史表”记录每次抓取时的价格和状态变化。分析价格走势时查历史表做实时监控时查主表。3.4 并发、限速和可观测性很多人一提到提高效率就上多线程这其实是把双刃剑。并发能提高抓取速度但对目标平台来说你就是一堆来自同一IP的密集请求很容易触发风控。我在实际项目中会先用单线程跑一遍计算出单次请求的耗时和成功率再决定开多少并发。一般单IP下每秒2到5个请求已经算比较克制了。如果你要抓的数据量大可以在代码里加一个简单的限流器比如信号量加Interval控制。更重要的是一定要有日志和统计面板每完成100个请求就打印一次成功率、平均耗时、失败状态码分布。没有这些指标你会连“100%成功”到底怎么定义都说不清楚。我自己踩过最深的坑就是日志太糙半夜程序挂了第二天看日志只看到一堆空白只能从头排查。4. 常见问题和排查实录4.1 403、429、连接超时怎么处理这是我被问最多的一类问题。“昨天还能跑今天全403”是常态。403通常是风控识别到了异常请求429是明确的限流信号连接超时可能是网络波动也可能是程序并发开太大。我的处理套路是先停掉所有任务手动用浏览器访问一次目标页面如果浏览器正常说明对方没有封IP问题出在请求头上如果浏览器也访问不了说明当前网络环境已受限需要等一段时间再继续。请求头那里User-Agent是最基础的一层别用默认的Python-requests但也别完全伪造一个假的浏览器UA就万事大吉。有些平台会校验TLS指纹和浏览器行为这类反爬手段不是改UA能解决的。我的建议很实际遇到这种情况不要硬刚降低频率、错峰采集、优先使用官方数据通道比研究绕过方案稳妥得多也安全得多。4.2 商品数据是动态加载的怎么办很多现代页面商品列表不是写在HTML里的而是浏览器先加载JS再通过接口渲染。你用requests直接拿HTML拿到的基本就是个空壳。这时候有两个思路一是找到页面背后的JSON接口直接请求接口处理速度比解析HTML快得多二是用无头浏览器自动化工具模拟浏览器渲染。我优先推荐找JSON接口虽然有时会遇到加密参数但别去搞逆向破解那属于高风险操作。更好的办法是看看接口是否包含公开的appkey或签名逻辑如果没有公开权限就踏踏实实用浏览器自动化。无头浏览器效率低也有被识别出来的风险但处理少量重点商品没问题。另外要强调一点如果页面出现验证码立刻停止程序。验证码是平台保护自己的一种方式绕过它既不明智也有法律风险换一个时间段再跑往往就恢复了。4.3 价格、库存、状态数据对不齐二手商品数据最有意思的就是它的不稳定性。同一件商品早上和晚上价格可能不一样你上午抓到“在售”下午可能已经卖掉了。如果程序只看当前页面很容易把“已售出”误判成“抓取失败”。我遇到的典型场景是商品详情页里已经没有价格了但JSON接口里还会返回一个历史价格这时候如果不做判断就可能把一条失效数据当正常数据入库。解决方法是在字段里增加status和captured_at两个字段每次抓取都更新。对于状态异常的商品不直接删除而是标记为removed。这样你在做价格趋势分析时可以按时间范围过滤“状态在售”的数据在做商品热度分析时则可以统计哪些商品在上架后几小时内就变成了removed。数据不一致不是bug它是商品真实生命周期的体现用模型去承接它就好。4.4 解析出来的字段乱码或缺失字段缺失是家常便饭。有的卖家不填成色有的商品没有原价有的标题里全是表情符号和特殊字符。解析时最常见的报错是编码问题和类型转换问题。页面声明是UTF-8但部分数据里混入了GBK编码可能导致标题乱码。统一在解析后做一层清洗先按文本规范化为UTF-8再去除控制字符和多余的空白。至于缺失字段我建议给每个字段都设计一个“不可用”的默认值比如空字符串、NULL或者-1。这样后续做统计时可以用IS NOT NULL过滤掉缺失项。千万不要在清洗时把空值填成0否则价格分析时会多出一堆“0元商品”的假数据这个坑我见过不止一次。5. 合规边界和后续玩法5.1 优先找官方口子说句实在话现在做正规的数据分析第一选择绝对不是爬页面而是检查目标平台有没有开放API、开放数据或官方合作渠道。以某二手平台为例曾经开放过面向垂直行业的数据服务比如废旧电子产品回收估价、二手行情指数这些官方数据比你去抓几万条页面再自己算准确得多。即便是为了学习也可以先把爬虫跑通在本地小规模环境里只抓少量公开数据不用于任何商业场景。合规不是一句空泛的口号而是每个实际决策里的成本计算。官方接口可能字段不够全但有授权、稳定、不被封页面采集看着自由但你需要持续维护还要承担风控和法律风险。小项目可以图省事涉及商业决策的项目我强烈建议先做合规评估。5.2 数据落地之后怎么用抓数据只是开始真正有价值的是数据应用。这里举几个我见过的落地场景。第一个是二手商品价格带分析把某类目的商品按价格区间分组算出分布比例你能看出哪个价位段竞争最激烈。第二个是地域供给分析观察哪些城市的货源多、价格低对做闲置回收的团队有直接参考价值。第三个是“秒下架”监控很多热销商品上架后几小时就没了这类商品往往代表真实需求很强监控它们的标题和关键词可以做选品参考。这些应用都不需要特别复杂的算法关键是要有持续稳定的数据源。程序能不能跑一个月不断档比它单次跑得多快更重要。所以我在设计时会把数据库表结构、字段含义、采集日志全部写成文档这样三个月以后回来看代码还能知道每个字段是怎么来的。5.3 我的两个小建议第一先小规模跑通再上量。我第一次做类似项目时直接写了个50线程的并发脚本跑完十分钟发现数据库里一半数据是重复的浪费了大量带宽。正确做法是先抓100条数据写出完整链路确认解析、清洗、入库都没问题再把任务挂到定时调度上。第二做好失败留痕。每次请求的URL、状态码、报错信息都要记录下来这不仅是排查问题的依据也是你评估“成功率”的唯一可信来源。最后再分享一个技巧给程序加一个“熔断开关”当连续失败超过50条时自动暂停一小时并且发一条通知到手机。这个开关拯救过我很多次半夜的睡眠。商品数据抓取程序说到底不是靠蛮力而是靠对失败的管理。你把失败管理好了成功率自然就会稳定在那种让人看了想说“100%”的水平。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑