
简介这是一套面向计算机专业本科生的Python爬虫实战项目专为课程设计、毕业设计及课设大作业打造聚焦闲鱼xianyu平台二手商品数据的自动化抓取与可视化分析。资源采用前后端分离架构后端基于FastAPI构建数据接口前端使用Vue实现交互式图表展示配套完整部署说明与运行指南兼顾教学性与工程规范性。压缩包共28个文件含11个核心Python脚本如saltyfish.py主爬虫、4个JSON配置与数据文件、3份Markdown文档含系统说明与README、2个JS前端逻辑文件以及exe可执行程序、图标与截图等辅助资源整体9.33MB结构清晰、开箱即用。已有215人学习下载提供高分毕设级方案——含稳定可运行代码、模块化目录结构、环境依赖清单requirements.txt及实测截图支持快速部署与二次开发答疑响应及时。1. 项目概述与核心价值最近在做一个市场调研项目需要分析闲鱼平台上特定品类的商品价格趋势和卖家分布。手动去翻效率太低数据也不全。用现成的数据工具要么功能不匹配要么价格不菲。所以我决定自己动手基于Python开发一个专门针对闲鱼平台的数据抓取工具也就是大家常说的“爬虫”。这个项目打包后我把它命名为“闲鱼商品爬虫-xianyu平台数据抓取-最新开发.zip”。这不仅仅是一个脚本集合它是我为了解决实际数据获取痛点从零开始搭建的一套包含反反爬策略、数据清洗和结构化存储的完整解决方案。简单来说这个工具能帮你自动化地、大批量地从闲鱼获取商品信息比如商品标题、价格、浏览量、想要数、卖家信息、地理位置、发布时间等。无论你是做竞品分析、价格监控、选品调研还是学术研究这套代码都能为你提供稳定、可靠的一手数据源。它特别适合有一定Python基础对数据抓取有实际需求但又不想从零开始研究闲鱼复杂页面结构和反爬机制的开发者或数据分析师。接下来我会把这套方案的完整设计思路、关键技术细节、踩过的坑以及优化心得毫无保留地分享出来。2. 整体架构设计与技术选型开发一个稳定可用的闲鱼爬虫远不止写几个requests.get那么简单。你需要面对动态加载、参数加密、请求频率限制等一系列挑战。我的整体架构设计遵循“模块化”和“稳健性”原则核心流程可以概括为模拟请求 - 解析数据 - 应对反爬 - 存储结果。2.1 核心模块分解整个项目主要分为五大模块请求管理模块负责构建符合闲鱼要求的HTTP请求包括Headers设置、Cookie管理、代理IP池的集成。这是与服务器对话的“外交官”。数据解析模块闲鱼页面数据是动态渲染的关键数据往往藏在JavaScript脚本或特定的JSON接口中。这个模块负责从混乱的响应体中精准提取出我们需要的结构化信息。反反爬虫策略模块这是项目的灵魂。闲鱼的反爬手段多样包括但不限于请求参数签名验证、用户行为检测如鼠标轨迹、IP频率限制。这个模块集成了多种策略来模拟真人操作。任务调度与并发模块为了高效抓取大量关键词或商品需要管理抓取队列并合理控制并发速度避免触发风控。数据存储与日志模块将抓取到的数据持久化我选择了MySQL作为主数据库同时将原始JSON响应备份到文件方便出错时回溯。日志系统则用于监控爬虫运行状态。2.2 关键技术选型与理由编程语言Python 3.8理由生态丰富是首要原因。requests,aiohttp,BeautifulSoup4,lxml,Selenium等库构成了爬虫的基石。其次Python在数据处理pandas和后续分析上具有天然优势。开发调试速度快能快速迭代反爬策略。HTTP客户端Requests Aiohttp理由Requests是同步请求的标杆语法简洁用于前期探索接口和编写核心逻辑。Aiohttp则用于实现异步并发在需要高速抓取且IP代理充足的情况下能极大提升效率。两者结合灵活应对不同场景。解析库BeautifulSoup4 与 正则表达式/json理由初期探索时BeautifulSoup4是解析HTML的瑞士军刀容错性好。但闲鱼的核心数据通常通过XHR接口返回JSON格式直接使用json.loads()解析效率最高。对于一些隐藏在脚本变量中的加密数据则需要结合正则表达式来提取原始字符串。浏览器自动化Selenium / Playwright理由当核心接口参数加密极其复杂或需要模拟完整登录、滑动验证等交互时无头浏览器是最后的“杀手锏”。Playwright相比Selenium更现代API更优雅启动速度也更快是我最终的选择。注意它通常作为备用方案因为资源消耗大、速度慢。数据存储MySQL 本地JSON文件理由MySQL用于存储结构化的最终数据便于SQL查询和分析。本地JSON文件则用于保存接口返回的原始响应这是一个非常重要的习惯。当数据结构发生变化或解析出错时你可以直接分析原始文件而无需重新抓取。代理IP服务付费动态代理IP池理由对于闲鱼这类大型平台使用固定IP高频请求会迅速被封。一个可靠的、高匿名的动态代理IP池是项目能长期稳定运行的基础。我选择了一家提供按量付费、支持HTTP/HTTPS协议的供应商并在代码中实现了IP自动切换和失效剔除逻辑。核心心得不要试图用一个技术栈解决所有问题。我的策略是“以轻量级接口请求为主浏览器自动化为辅”。95%的数据通过逆向分析接口用requests获取剩下5%的疑难杂症再用Playwright解决。这样在效率和稳定性之间取得了最佳平衡。3. 核心环节逆向分析与接口破解这是整个开发过程中最具挑战性也最体现技术含量的部分。闲鱼没有公开的API所有数据都需要通过分析其网页或App的通信过程来获取。3.1 寻找数据源头首先通过浏览器开发者工具F12的“网络”(Network)面板搜索商品列表页。打开闲鱼首页搜索一个关键词如“iPhone 13”。在Network面板中筛选XHR/Fetch请求。滚动页面加载更多商品观察新出现的请求。你会发现一个名为mtop.taobao.idle.avus.search或类似名称的请求其响应体是结构清晰的JSON包含了商品列表的所有信息。这就是我们的核心目标接口。3.2 解密请求参数找到接口后难点在于它的请求参数Query String或Payload是经过加密的。关键参数如data,api,v,sign等尤其是sign签名是服务器验证请求合法性的核心。追踪参数生成在开发者工具中找到这个请求查看其“标头”(Headers)和“负载”(Payload)。尝试在源代码中全局搜索关键参数名如sign。定位加密函数通常加密逻辑写在某个巨大的、被混淆过的JavaScript文件里。你可以通过“发起程序”(Initiator)标签页查看调用栈一步步回溯到生成参数的JavaScript函数。算法还原常见的算法是MD5、SHA1或AES也可能是一些自定义的哈希算法。你需要分析出参与签名的原始字符串通常包含接口名、固定令牌、时间戳、请求参数等以及签名的生成顺序。这个过程可能需要使用到“Hook”技术或调试工具逐步跟踪变量的值。一个简化版的签名思路仅为示例真实情况更复杂import hashlib import time def generate_sign(api, token, t, data_dict): # 1. 将参数按特定顺序拼接成字符串 param_str fapi{api}token{token}t{t}data{json.dumps(data_dict, separators(,, :), ensure_asciiFalse)} # 2. 加上一个固定的盐值salt salt 某段从JS中提取的固定字符串 sign_str param_str salt # 3. 进行MD5哈希 sign hashlib.md5(sign_str.encode(utf-8)).hexdigest() return sign # 使用 api “mtop.taobao.idle.avus.search” token “你的登录令牌需要获取” t str(int(time.time() * 1000)) # 时间戳 data {searchText: iPhone 13, page: 1, pageSize: 20} signature generate_sign(api, token, t, data)3.3 获取关键令牌如Cookie许多接口需要用户登录后的Cookie如_m_h5_tk,_m_h5_tk_enc才能访问。获取方式有两种手动登录后复制适用于个人小规模抓取。在浏览器登录闲鱼从开发者工具中复制完整的Cookie字符串到代码的请求头中。缺点是容易过期。模拟登录通过程序输入用户名密码或扫码完成登录流程获取并维护Cookie。这个过程非常复杂涉及滑块验证等通常建议使用无头浏览器方案Selenium/Playwright来绕过获取到Cookie后再用于接口请求。踩坑实录闲鱼的签名算法和令牌大约每2-3个月会有一次小更新。我的策略是将签名生成函数单独封装在一个模块里并定期例如每周用一组固定参数测试签名是否依然有效。一旦失效立即启动逆向分析流程。同时在代码中实现“降级机制”当接口请求连续失败时自动切换到备用方案如解析静态HTML虽然信息少或触发告警。4. 反反爬虫策略的实战部署破解接口只是第一步让爬虫长期、稳定、低调地工作才是真正的考验。4.1 请求头Headers的精细化伪装一个粗糙的请求头等于自报家门。必须让请求看起来完全来自真实的浏览器或App。headers { “User-Agent”: “Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 IdleFish/9.8.0 AliApp(AP/9.8.0.1000)”, # 使用移动端UA风控可能更低 “Accept”: “application/json”, “Accept-Language”: “zh-CN,zh;q0.9”, “Accept-Encoding”: “gzip, deflate, br”, “Content-Type”: “application/x-www-form-urlencoded;charsetUTF-8”, “Origin”: “https://market.m.taobao.com”, “Referer”: “https://market.m.taobao.com/”, # 正确且随页面变化的Referer至关重要 “x-requested-with”: “XMLHttpRequest”, # 必须包含从有效会话中获取的Cookie “Cookie”: “你的完整Cookie字符串” }关键点User-Agent,Referer,Cookie必须匹配且有效。可以准备一个UA池随机轮换。4.2 代理IP池的管理与调度单个IP的频繁请求是致命的。我构建了一个简单的代理IP池管理器获取与验证从付费API定时获取一批IP并立即用一个简单的测试请求如访问百度验证其连通性和匿名度。评分与存储将有效的IP存入数据库或Redis记录其响应速度、最近使用时间、失败次数。调度策略每次请求前从池中选取一个“最佳”IP如最近未使用、响应快的。请求成功后提高其评分失败如返回403/429状态码则降低评分失败次数过多则暂时剔除。异常处理当某个IP连续失败或收到特定风控响应时立即丢弃并更换IP同时将当前抓取任务暂停一小段时间。4.3 请求频率与人类行为模拟即使有代理IP过于规律的请求也会被识别。随机延时在请求间插入随机延时例如time.sleep(random.uniform(1.5, 4.0))模拟人类阅读和点击的间隔。流量整形为每个关键词或卖家设置一个全局的每日/每小时请求上限。会话管理模拟“浏览-点击-返回”的行为流而不是只疯狂抓取列表页。偶尔随机访问几个商品详情页并带上合理的页面停留时间。4.4 降级与熔断机制这是保证系统鲁棒性的关键。当检测到异常时自动执行降级策略IP失效切换代理IP。Cookie失效触发重新登录流程或告警人工处理。接口返回特定错误码如“访问太频繁”、“系统繁忙”。立即大幅延长等待时间如休眠5-10分钟并降低并发度。连续失败如果同一任务连续失败N次将其移入“失败队列”并记录日志稍后重试或人工检查。5. 数据解析与存储方案成功拿到数据只是半场高效、准确地解析和存储是下半场。5.1 结构化数据提取从接口返回的JSON中数据是嵌套的。我使用Python的字典和列表操作结合jsonpath或递归函数来提取字段。import json def parse_item(json_data): item_list json_data.get(“data”, {}).get(“mainInfos”, []) parsed_items [] for item in item_list: parsed { “item_id”: item.get(“itemId”), “title”: item.get(“title”), “price”: item.get(“price”), # 单位通常是分需转换 “price_float”: float(item.get(“price”, 0)) / 100.0, “view_count”: item.get(“view”), “want_count”: item.get(“favcount”), “seller_id”: item.get(“userId”), “seller_nick”: item.get(“nick”), “location”: item.get(“location”), “publish_time”: item.get(“publishTime”), # 可能是时间戳 “category”: item.get(“categoryName”), “url”: f“https://market.m.taobao.com/app/idleFish/xxx?id{item.get(‘itemId’)}” } # 清洗数据去除标题中的多余空格、换行符 parsed[“title”] ‘ ‘.join(parsed[“title”].split()) if parsed[“title”] else None parsed_items.append(parsed) return parsed_items5.2 数据库表设计在MySQL中我设计了至少两张核心表商品表 (items)字段名类型说明idBIGINT PRIMARY KEY AUTO_INCREMENT自增主键item_idVARCHAR(50) UNIQUE闲鱼商品ID唯一索引titleVARCHAR(255)商品标题price_fenINT价格分view_countINT浏览量want_countINT想要数seller_idVARCHAR(50)卖家IDseller_nickVARCHAR(100)卖家昵称location_cityVARCHAR(50)所在城市publish_timestampBIGINT发布时间戳categoryVARCHAR(100)商品类目detail_urlVARCHAR(500)商品详情页链接crawl_timeDATETIME DEFAULT CURRENT_TIMESTAMP抓取时间抓取任务表 (crawl_tasks)字段名类型说明idINT PRIMARY KEY AUTO_INCREMENT任务IDkeywordVARCHAR(100)搜索关键词statusENUM(‘pending’, ‘running’, ‘completed’, ‘failed’)任务状态current_pageINT当前抓取页码max_pagesINT计划抓取最大页数created_atDATETIME创建时间finished_atDATETIME完成时间这种设计便于追踪抓取进度、去重通过item_id以及后续基于时间维度的数据分析。5.3 数据去重与增量更新闲鱼商品列表是动态变化的。我的策略是插入时去重使用ON DUPLICATE KEY UPDATE语句当item_id冲突时更新价格、浏览量等可变字段而不是插入新记录。这样可以记录商品价格的历史变化。增量抓取对于监控类任务定期如每小时执行抓取只处理新出现的商品。可以通过记录上次抓取的最大publish_timestamp来实现。6. 工程化与部署实践要让这个爬虫7x24小时稳定运行需要一些工程化手段。6.1 项目目录结构一个清晰的结构有助于团队协作和维护。xianyu_crawler/ ├── config/ │ ├── settings.py # 配置文件数据库、代理API密钥、请求头等 │ └── logging.conf # 日志配置文件 ├── core/ │ ├── requester.py # 请求管理模块封装requests/aiohttp集成代理、重试 │ ├── parser.py # 数据解析模块 │ ├── anti_anti.py # 反反爬核心签名生成、Cookie管理 │ └── scheduler.py # 任务调度与并发控制 ├── utils/ │ ├── db_client.py # 数据库操作封装 │ ├── proxy_pool.py # 代理IP池管理 │ └── logger.py # 日志工具 ├── tasks/ │ ├── search_task.py # 关键词搜索任务 │ └── detail_task.py # 商品详情抓取任务 ├── storage/ │ ├── raw_json/ # 存储原始响应JSON按日期分目录 │ └── logs/ # 日志文件 ├── main.py # 主程序入口 └── requirements.txt # 项目依赖6.2 使用任务队列Celery Redis对于大规模、定时抓取我引入了Celery作为分布式任务队列。优势解耦将任务产生和任务执行分离。异步主程序发出抓取任务后立即返回由Worker异步执行。重试Celery自带任务重试机制可以配置重试次数和间隔。监控可以通过Flower等工具监控任务状态。配置示例# tasks/search_task.py from celery import Celery app Celery(‘xianyu’, broker‘redis://localhost:6379/0’, backend‘redis://localhost:6379/0’) app.task(bindTrue, max_retries3) def crawl_search_keyword(self, keyword, max_pages10): try: # 这里是具体的抓取逻辑 result do_crawl(keyword, max_pages) return result except Exception as exc: # 任务失败等待30秒后重试 raise self.retry(excexc, countdown30)然后通过crawl_search_keyword.delay(“iPhone 13”, 5)来异步发起任务。6.3 日志与监控完善的日志是排查问题的生命线。我采用分层日志记录DEBUG级记录详细的请求URL、参数、响应状态码。用于开发调试。INFO级记录任务开始、结束、抓取到的商品数量。WARNING级记录IP失效、Cookie过期、请求频率异常等。ERROR级记录解析失败、数据库连接错误、签名算法失效等严重问题。同时将关键指标如每日抓取量、成功率、IP消耗速度写入数据库或推送到监控系统如PrometheusGrafana便于可视化观察爬虫健康度。7. 常见问题排查与优化心得在实际运行中你会遇到各种各样的问题。这里记录了几个最典型的案例和解决思路。7.1 问题速查表问题现象可能原因排查步骤与解决方案返回空数据列表但状态码是2001. 请求参数签名错误。2. Cookie已过期失效。3. 请求头不完整缺少关键字段。1. 打印出生成的签名和请求参数与浏览器抓包对比。2. 手动在浏览器访问同一接口复制新Cookie替换。3. 使用抓包工具如Charles/Fiddler对比请求头差异补全Referer,x-requested-with等。频繁返回403 Forbidden或429 Too Many Requests1. 当前代理IP已被封。2. 请求频率过高触发风控。3. User-Agent被识别为爬虫。1. 立即切换代理IP并将该IP从池中剔除。2. 大幅增加请求间隔时间如休眠1分钟以上降低并发数。3. 更换为更真实、更随机的User-Agent池。抓取几页后后续页码返回相同内容或错误1. 分页参数逻辑有变。2. 服务器对深度分页做了限制。3. 会话Cookie在抓取过程中过期。1. 重新分析翻页时请求参数的变化规律特别是page、offset或feed相关的参数。2. 闲鱼可能只提供前50-100页数据这是平台限制无法绕过。3. 实现Cookie的定时刷新机制或在任务中检测到此类错误时自动重新登录。数据解析出错字段为None或结构不符1. 接口返回的数据结构已更新。2. 针对不同类目或筛选条件数据结构有差异。1.务必保存原始响应JSON对比新旧JSON文件找到字段路径的变化更新解析函数。2. 在解析代码中加入更严格的异常捕获和日志记录下解析失败的商品ID和原始数据片段。异步爬虫效率没有提升反而更慢1. 代理IP质量差响应慢。2. 目标服务器限制了单IP的并发连接数。3. 异步任务间存在资源竞争如数据库连接。1. 优化代理IP池筛选高速度、低延迟的IP。2. 为每个异步Worker设置并发限制asyncio.Semaphore。3. 使用数据库连接池或改为异步数据库驱动如aiomysql。7.2 性能优化心得连接复用使用requests.Session()或aiohttp.ClientSession来复用TCP连接能显著减少握手开销。异步与协程对于IO密集型的爬虫asyncioaiohttp是性能利器。但要注意控制并发量我一般设置在20-50之间根据代理IP数量和目标服务器响应情况调整。解析优化JSON解析用内置的json库。避免在循环内重复编译正则表达式应预编译pattern re.compile(…)。数据库批量写入不要抓取一条就插入一条。积累一定数量如100条后使用executemany()进行批量插入能减少数据库的I/O次数提升数倍性能。内存管理对于海量数据抓取注意及时释放已处理完的数据对象。使用生成器yield来逐条处理数据而不是一次性将所有数据加载到内存列表中。7.3 法律与道德边界最后也是最重要的一点必须清醒认识爬虫的边界。遵守robots.txt虽然技术上可以绕过但这是一个基本的行业规范。检查目标网站的robots.txt文件。控制抓取频率你的抓取行为不应影响目标网站的正常服务。这是避免法律风险和技术反制的最基本要求。尊重数据版权与用户隐私抓取的数据应用于个人学习、研究或合法的市场分析。绝对禁止用于大规模骚扰卖家或买家。未经授权地商业化复制闲鱼平台的全部或实质部分内容。获取并泄露用户的手机号、微信号等个人敏感信息这些信息通常也是加密的。数据用途明确你的数据用途最好停留在分析和洞察层面而非直接用于竞争或侵权。开发这个爬虫的过程是一个不断与平台风控系统“斗智斗勇”和“自我约束”的过程。技术是锋利的刀用它来解决问题、创造价值而不是制造麻烦。保持对技术的敬畏和对规则的尊重才能走得长远。这套方案目前运行稳定但互联网环境瞬息万变核心的逆向分析和策略调整能力才是你手中最可靠的武器。本文还有配套的精品资源点击获取