
简介本资源是一套面向本科毕业设计与数据采集实践的Scrapy爬虫项目聚焦闲鱼平台二手商品信息的结构化抓取适用于计算机专业学生开展课程设计、毕设开发或Web数据采集入门学习。压缩包共11个文件含7个核心Python模块spiders定义爬取逻辑、items声明数据结构、pipelines实现清洗与存储、middlewares处理反爬、settings配置运行参数等辅以README.md说明文档、LICENSE授权文件、.gitignore版本控制配置及scrapy.cfg工程配置文件整体仅8KB轻量易部署。已有145人下载学习项目目录结构规范完整呈现Scrapy标准工程组织方式提供可直接运行的爬虫骨架、字段映射逻辑与基础去重策略便于读者理解动态页面解析、请求头模拟、数据管道流转等关键环节并可基于此快速扩展至其他垂直电商网站。 很多玩爬虫的朋友第一次拿到闲鱼这类项目都会下意识觉得“这不就是个普通电商网站嘛Scrapy直接怼上去就行”。真跑起来才发现返回的HTML全是空的页面渲染全靠JS执行商品数据躲在几十个异步接口里外加各种参数校验和滑块验证纯Scrapy根本玩不转。我这次基于Python-Scrapy框架做了一个闲鱼二手商品数据爬取项目把“接口直连抓JSON 动态渲染兜底 反爬对抗”这套完整方案跑通了。这个项目适合三类人看一是刚学完Scrapy基础、想找个实战项目练手的人二是需要采集二手商品价格、销量数据做市场分析或比价系统的开发者三是对反爬和风控对抗感兴趣、想了解真实平台防护策略的技术爱好者。下面把整个项目的设计思路、核心细节、实操过程和踩坑经验完整拆出来全部基于我实测能跑通的方案。1. 项目整体设计与思路拆解1.1 闲鱼页面的技术特征与爬取难点闲鱼和淘宝、天猫同属阿里系前端技术栈高度统一整个页面是典型的SPA单页应用。页面加载时服务器只返回一个空壳HTML和一堆JS文件所有商品数据全部由浏览器执行JS后通过XHR异步请求从接口拉取再渲染到DOM上。这意味着用常规的scrapy.Request去请求商品列表页URL拿回来的HTML里根本找不到商品标题、价格、销量这些字段只能在JS代码里看到一堆混乱的变量。很多新手在这一步就卡住了以为是代码写错了其实是爬取策略从根上就错了。闲鱼商品数据爬取的难点主要集中在这几个方面页面属于动态渲染静态请求拿不到有效数据数据接口有严格的请求头校验缺字段直接拒绝用户ID和商品ID经过编码从页面上无法直接对应高频请求会触发阿里系的滑块验证和IP风控部分接口需要登录态Cookie匿名访问只能拿到部分数据这个项目的核心思路就是转变策略不去渲染页面而是直接抓取浏览器后台的数据接口。用抓包工具定位到返回商品JSON数据的XHR请求然后在Scrapy里模拟这个请求直接拿到结构化数据效率和成功率都比渲染方案高得多。1.2 为什么选Scrapy而不是Requests或Selenium在技术选型阶段其实有三个备选方案Requests BeautifulSoup、Selenium/Playwright全家桶、Scrapy框架。最终选了Scrapy不是因为它最流行而是因为这个场景下它的收益最合适。先说Requests方案。它写起来最简单几行代码就能发起请求但问题在于它只是一个HTTP请求库没有调度器、没有去重机制、没有并发管理、没有中间件体系。爬取几百个页面够用一旦扩大到上万条商品数据请求调度、失败重试、并发控制全得自己手写工程量不亚于重写一个微型框架。再说Selenium方案。它确实能完美渲染动态页面什么数据都能拿到但代价是大量资源的消耗。一个浏览器实例至少占几百MB内存并发开5个实例之后服务器基本就卡死了。而且浏览器渲染速度比直接请求接口慢几十倍爬1万条数据要跑十几个小时。更麻烦的是Selenium模拟的浏览器操作特征太明显在阿里系风控系统面前几乎是一抓一个准。Scrapy方案的优势在于它天生就是一个完整的爬虫工程框架自带调度器管理请求队列自带去重过滤器基于Twisted异步网络库实现高并发请求中间件机制可以灵活插入代理、UA轮换、Cookie管理Pipeline管道可以优雅地处理数据清洗、去重和存储。请求和解析天然分离代码结构清晰可维护。最重要的一点Scrapy的并发是IO级别而不是浏览器级别的并发16个请求占用的内存几乎可以忽略不计爬取1万条数据的耗时大概只有Selenium方案的几十分之一。1.3 整体爬取方案选型整个项目的架构设计采用了分层结构第一层是调度层由Scrapy引擎和调度器负责维护请求队列实现去重、优先级控制和爬取顺序管理。第二层是下载层由Downloader Middleware负责请求转发、Cookie注入、UA轮换、代理切换、重试机制。第三层是解析层由爬虫主逻辑负责解析接口返回的JSON数据提取商品ID、标题、价格、成交信息、地理位置等核心字段。第四层是存储层由Item Pipeline负责数据清洗、去重、格式化和落库支持CSV文件、MySQL数据库和Redis多种存储方式。数据采集链路分为两条支线主动接口链路定位到闲鱼的异步数据接口构造请求参数直接爬取结构化JSON数据。这是主力方案覆盖90%以上的数据量。动态渲染兜底链路对于接口无法覆盖的数据比如部分需要特定环境参数的数据用Scrapy-Selenium或Scrapy-Playwright配合真实浏览器渲染页面弥补接口方案的盲区。为什么优先走接口方案因为效率和稳定性都比渲染方案高一个量级。接口返回的就是纯JSON解析成本极低也不受页面结构变动影响而渲染方案每次请求都要拉起浏览器、加载所有JS、等待网络请求完成中间任何一个环节慢都会拖累整体爬取速度。1.4 存储方案与去重策略的考虑数据存储用了双通道方案热数据存MySQL用于日常查询和分析全量原始数据存CSV用于备份和批量处理。这里有个容易被忽视的点就是Scrapy的去重机制默认只针对URL但闲鱼的商品ID才是真正唯一的业务标识。同一个商品可能出现在多个搜索结果里对应的URL也可能不同这时候必须自定义基于商品ID的去重过滤器否则数据会出现大量冗余。去重策略采用了双写模式Spider层用Python的set集合做第一层去重Pipeline层再用redis set做第二层全局去重。第一层是防止单个Spider实例内重复解析第二层是防止多个Spider实例或多次运行之间产生重复数据。2. 核心细节解析与实操要点2.1 环境准备与依赖安装这个项目推荐使用Python 3.8以上版本我用的是Python 3.10。创建虚拟环境后依次安装依赖# 创建并激活虚拟环境 python -m venv xianyu_env source xianyu_env/bin/activate # Windows下用 xianyu_env\Scripts\activate # 安装Scrapy核心框架 pip install scrapy # 安装动态渲染支持的Selenium相关库 pip install scrapy-selenium pip install selenium # 安装可选的反爬对抗和数据处理库 pip install fake-useragent pip install redis pip install pymysql安装完成后用scrapy startproject xianyu_spider创建项目骨架然后在spiders目录下新建爬虫文件。Scrapy会自动生成settings.py、items.py、middlewares.py、pipelines.py这些核心模块。这里有一个我自己踩过的坑fake-useragent这个库会在运行时从外部服务器拉取最新的UA列表如果网络环境受限会导致UA初始化超时。建议提前生成好UA列表保存到本地文件然后自己写一个轮换逻辑避免运行时依赖外部请求。2.2 抓包分析定位闲鱼数据接口这是整个项目最关键的一步目标就是找到那个返回商品列表JSON数据的接口。我用Chrome浏览器打开闲鱼网页版按F12打开开发者工具切换到Network面板。然后在页面上随便搜索一个关键词注意观察Network面板里新增的XHR请求。闲鱼的接口大多数都带有特定的特征比如请求路径中含有异步网关相关的关键参数。在Network面板的筛选栏输入XHR然后逐一查看返回的JSON数据找返回包里包含商品标题、价格、想要人数等数据的接口。定位到核心接口后查看它的详情信息完整URL包含所有查询参数请求方法GET还是POST请求头User-Agent、Referer、Cookie、token等返回格式JSON还是JSONP把这些信息完整记录下来这是后面在Scrapy里构造请求的直接依据。一个很重要的细节闲鱼接口返回的数据里商品ID和用户ID都是经过编码处理的不是明文数字。抓包时不要把明文数字ID当成商品ID来用后续拼接商品详情页链接时要用接口返回的编码ID。2.3 动态渲染页面的三种处理方案接口方案虽然高效但不可能覆盖所有场景。比如当Cookie过期、风控策略升级、接口参数校验加强时就需要页面渲染方案兜底。总结下来处理闲鱼这类动态页面有三种方案方案一纯接口直连直接构造和浏览器一致的请求头带上有效的Cookie和必要参数请求异步数据接口解析返回的JSON。优点是速度快、资源消耗低。缺点是依赖接口参数和Cookie接口一旦升级或Cookie过期就会失效。方案二Scrapy-Selenium中间件通过Selenium启动真实浏览器让浏览器自动完成JS渲染然后通过中间件把渲染后的页面返回给Scrapy解析。优点是兼容性最好能实现所见即所得。缺点是速度慢、耗资源、代码耦合度高而且浏览器自动化特征明显容易被风控识别。方案三Scrapy-Playwright异步渲染基于Playwright的异步API把浏览器渲染能力嵌入Scrapy的异步流程中。比Selenium方案性能好很多API设计也更加现代。适合对渲染速度有一定要求、又不想完全脱离接口方案的场景。我的建议是优先使用方案一它最简单高效。当接口方案失效时临时切换到方案二或方案三作为应急手段。三个方案在项目里都有代码实现按注释切换即可。2.4 Scrapy核心组件配置Scrapy框架的配置集中在settings.py文件中。针对闲鱼这个目标关键的配置项如下# 请求并发数闲鱼风控较严建议控制在16以内 CONCURRENT_REQUESTS 8 # 下载延迟建议设置1-2秒 DOWNLOAD_DELAY 1.5 # 是否遵循robots协议本项目仅用于学习研究保持False便于测试 ROBOTSTXT_OBEY False # 默认请求头 DEFAULT_REQUEST_HEADERS { Accept: application/json, text/plain, */*, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://www.goofish.com/, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, } # 启用中间件注意数字越小优先级越高 DOWNLOADER_MIDDLEWARES { xianyu_spider.middlewares.CookieMiddleware: 100, xianyu_spider.middlewares.ProxyMiddleware: 200, xianyu_spider.middlewares.RandomUserAgentMiddleware: 300, } # 启用Pipeline数字越小优先级越高 ITEM_PIPELINES { xianyu_spider.pipelines.CsvPipeline: 300, xianyu_spider.pipelines.MySQLPipeline: 400, }Downloader Middleware是配置的核心优先级数字越小越早执行。Cookie注入必须在最前面因为后续所有的代理、UA切换都需要在Cookie有效的请求头基础上进行。RandomUserAgentMiddleware放在后面是为了确保每次请求发出时UA是随机切换的。2.5 登录态Cookie的管理闲鱼大多数数据接口允许匿名访问但部分高价值数据需要登录Cookie。Cookie管理是整个项目中最容易出问题的环节。我采用的方案是手动获取Cookie模拟登录后从浏览器开发者工具中复制Cookie字符串然后保存在本地配置文件中。Spider启动时读取Cookie并注入到请求头中。Cookie过期是不可避免的所以还需要写一个Cookie状态检测逻辑。如果连续多个请求都返回登录失效的错误状态码就停止爬取并提醒手动更新Cookie。这个逻辑要放在中间件层面避免错误的请求继续消耗配额。有一个细节要注意请求头里的Cookie字段是整个字符串但实际有些参数比如特定token是独立的请求头字段不能只复制Cookie就万事大吉。抓包时要仔细比对浏览器发出的所有请求头字段缺了任何一个都可能导致请求失败。3. 实操过程与核心环节实现3.1 模型的建立Item定义在items.py中定义需要采集的字段这是数据流的起点。闲鱼二手商品的核心字段包括import scrapy class XianyuItem(scrapy.Item): # 商品ID用于去重和详情页拼接 item_id scrapy.Field() # 商品标题 title scrapy.Field() # 商品价格统一转换为浮点数 price scrapy.Field() # 原价方便计算折扣率 original_price scrapy.Field() # 想要的人数 want_count scrapy.Field() # 浏览人数 view_count scrapy.Field() # 所在城市 city scrapy.Field() # 卖家昵称 seller_name scrapy.Field() # 卖家ID seller_id scrapy.Field() # 商品图片链接 image_url scrapy.Field() # 商品详情链接 item_url scrapy.Field() # 商品描述 description scrapy.Field() # 发布时间 publish_time scrapy.Field() # 抓取时间 crawl_time scrapy.Field()Item定义的原则是“宁多勿缺”宁可多定义几个暂时用不到的字段也不要等需要的时候再去重新爬一遍数据重新爬取的代价远高于前期多花一点时间。3.2 Spider主体代码实现下面是我实际跑通的Spider核心代码去掉了业务相关的敏感参数保留整体逻辑import json import time import scrapy from scrapy import Request from xianyu_spider.items import XianyuItem class GoofishSpider(scrapy.Spider): name goofish allowed_domains [goofish.com] def __init__(self, keyword手机, *args, **kwargs): super().__init__(*args, **kwargs) self.keyword keyword # 从本地配置读取Cookie和基础参数 self.cookie self._load_cookie() self.base_params self._load_base_params() def start_requests(self): # 构造第一页请求 url self._build_search_url(self.keyword, page1) yield Request( urlurl, callbackself.parse_list, headers{ Cookie: self.cookie, User-Agent: self._random_ua(), }, meta{page: 1} ) def parse_list(self, response): # 接口返回的是JSON数据 data json.loads(response.text) # 解析商品列表 items data.get(data, {}).get(items, []) for item_data in items: item XianyuItem() item[item_id] item_data.get(id) item[title] self._clean_title(item_data.get(title)) item[price] self._parse_price(item_data.get(price)) item[want_count] item_data.get(wantCount) item[view_count] item_data.get(viewCount) item[city] item_data.get(city) item[seller_name] item_data.get(sellerNick) item[seller_id] item_data.get(sellerId) item[item_url] fhttps://www.goofish.com/item?id{item_data.get(id)} item[crawl_time] time.strftime(%Y-%m-%d %H:%M:%S) yield item # 翻页逻辑 page response.meta[page] total_page data.get(data, {}).get(totalPage, 1) if page total_page: next_url self._build_search_url(self.keyword, pagepage 1) yield Request( urlnext_url, callbackself.parse_list, headers{ Cookie: self.cookie, User-Agent: self._random_ua(), }, meta{page: page 1} ) def _build_search_url(self, keyword, page): # 拼接搜索接口URL # 注意URL中的参数必须和抓包时完全一致 pass def _load_cookie(self): # 从本地配置文件读取Cookie pass def _random_ua(self): # 从预置UA列表随机选择一个 pass def _clean_title(self, title): # 清洗标题去除HTML标签和特殊字符 pass def _parse_price(self, price): # 价格统一转成浮点数部分字段可能带单位 pass这个Spider的请求流程是构造搜索接口URL请求返回JSON数据解析商品列表提取字段包装成Item翻页继续请求直到所有页抓完。这里要特别说明一个细节为什么用json.loads而不是Scrapy自带的response.json()因为闲鱼接口有时会返回带BOM头的JSON数据以及某些字段可能是字符串形式的数字用response.json()直接解析容易遇到编码问题。先手动json.loads可以更灵活地做容错处理。3.3 请求头与签名参数处理闲鱼的接口请求头包含几个关键字段缺一个都可能被拒绝User-Agent必须和浏览器保持一致不能太老也不能太过新Referer必须指向闲鱼页面否则会被拒绝Cookie包含登录态和基本身份信息token类参数某些接口需要独立的token请求头这些参数直接从抓包工具里复制不用自己伪造。伪造的难度很大阿里系的token生成算法经过混淆短时间内逆向成本远高于收益。有一种情况需要注意接口URL里可能带有时间戳或者sign签名参数这类参数有一定时效性。如果发现请求返回的签名过期错误需要更新这些参数。我采用的是定时重新抓包更新的方案配合代码中的动态参数读取机制。3.4 Pipeline数据清洗与存储Pipeline是Scrapy中处理Item的管道组件每个Pipeline类负责一个独立的处理环节。我实现了两个Pipeline一个负责数据清洗和去重一个负责存储。数据清洗Pipeline的代码如下import re import redis class DataCleanPipeline: def __init__(self): # 连接Redis用于去重 self.redis_client redis.Redis(hostlocalhost, port6379, db0) def process_item(self, item, spider): # 商品ID去重 item_id item.get(item_id) if not item_id: raise DropItem(fMissing item_id: {item}) # 使用Redis的set做全局去重 if self.redis_client.sismember(xianyu:item_ids, item_id): raise DropItem(fDuplicate item: {item_id}) # 清洗标题去除HTML标签、多余空格 title item.get(title, ) title re.sub(r[^], , title) title re.sub(r\s, , title).strip() item[title] title # 价格格式化统一为两位小数浮点 price item.get(price) if isinstance(price, str): price price.replace(元, ).replace(,, ).strip() try: item[price] float(price) except (ValueError, TypeError): item[price] 0.0 # 商品链接拼接 item[item_url] fhttps://www.goofish.com/item?id{item_id} # 写入去重集合 self.redis_client.sadd(xianyu:item_ids, item_id) return item存储Pipeline负责把清洗后的Item写入存储介质import csv import os class CsvPipeline: def __init__(self): # 生成带时间戳的文件名 timestamp time.strftime(%Y%m%d_%H%M%S) self.file_path fxianyu_data_{timestamp}.csv self.csv_file open(self.file_path, w, newline, encodingutf-8-sig) self.writer csv.writer(self.csv_file) def process_item(self, item, spider): # 如果是第一次写入先写入表头 if not hasattr(self, written_header): self.writer.writerow(item.keys()) setattr(self, written_header, True) # 写入数据行 self.writer.writerow([item.get(key) for key in item.keys()]) return item def close_spider(self, spider): self.csv_file.close()这里有一个经验之谈CSV文件的编码必须用utf-8-sig而不是utf-8。因为Excel直接打开utf-8编码的CSV文件时会出现中文乱码而utf-8-sig会在文件头部加上BOM标记Excel可以正确识别这个坑我蹲过很多次。3.5 增量爬取与定时调度增量爬取是实际项目中最重要的环节一次性爬完数据就结束的爬虫在实际场景中意义不大。闲鱼数据是实时变动的需要对目标关键词做持续监控。增量的实现思路是只爬取发布时间在最近N天内的商品或者只处理商品ID不在已抓取集合中的新商品。判断依据是商品的发布时间字段和商品ID。定时调度的实现非常灵活在Linux服务器上用Crontab在Windows上用计划任务。我的经验是直接在Spider内部做一个死循环加随机延迟的调度这样不需要依赖外部任务系统while True: # 执行爬取任务 self.crawl_once(keyword_list) # 随机等待时间避免固定间隔被识别 sleep_time random.randint(1800, 3600) time.sleep(sleep_time)每次执行完一轮爬取后要把已经成功处理的商品ID记录到本地文件或数据库中下一轮开始时加载去重。3.6 分布式扩展Scrapy-Redis如果单机爬虫满足不了数据量需求可以无缝扩展到分布式。Scrapy-Redis是Scrapy的分布式扩展方案核心是把调度器的请求队列和去重集合从内存搬到Redis中实现多个Spider实例共享任务队列和去重集合。需要改动的配置只有几行# settings.py中添加 SCHEDULER scrapy_redis.scheduler.Scheduler DUPEFILTER_CLASS scrapy_redis.dupefilter.RFPDupeFilter REDIS_URL redis://localhost:6379改完之后多台机器上的Spider实例启动后会从Redis队列中领取任务去重也在Redis中全局生效天然就是分布式的。不过对于闲鱼这类有严格风控的目标分布式并不意味着能更快更高效反而更容易触发反爬。所以这个扩展更像是锦上添花的功能等数据量确实大到单机处理不了时再启用。4. 常见问题与排查技巧实录4.1 高频问题速查表这个项目从开发到跑稳定总共遇到过七八类问题。下面整理成速查表遇到问题直接对着排查问题现象可能原因解决方案返回内容是一堆JS代码而不是JSONCookie过期或请求参数缺失接口没被正确调用重新抓包更新Cookie和所有请求头字段核对URL参数请求能到但返回空列表当前IP被识别接口返回了风控空数据更换IP降低请求频率使用代理请求频繁出现滑块验证爬取频率过高或UA指纹太单一增加下载延迟轮换UA减少并发数数据字段全部为None接口字段名变更解析逻辑失效打印原始JSON重新核对字段名更新解析逻辑CSV文件中文乱码编码使用了utf-8Excel不识别改用utf-8-sig编码写文件数据库连接中断MySQL连接超时Pipeline中加try-except断线重连机制爬取中途内存暴涨请求队列积压过多URL降低并发数启用自动限速扩展商品链接打开后显示已删除商品被下架或ID过期存储商品ID和管理员定期清理失效数据4.2 反爬与风控对抗的个人经验在闲鱼爬虫上踩过最深的坑就是低估了阿里系的风控系统。这套风控不是简单的IP限制和User-Agent检查而是一个多维度的用户行为分析系统它会综合判断请求频率、操作规律、浏览器指纹、网络环境等多维度信息。我实际测试下来有几个能明显降低风控触发概率的配置组合并发数控制在8以内不要贪多下载延迟设置在1.5秒以上让请求间隔不那么规律同一个IP每小时的请求次数控制在300次以下每次运行的爬取时长控制在1小时内结束后换IPUA列表准备20个以上随机轮换不要固定另外一个很多人忽略的点是请求时间的分布。如果每一秒都精确地发出一个请求风控很容易识别出这是机器行为。我采用了随机延迟策略基础延迟1.5秒再加上0到1秒的随机偏移。这样请求时间分布更接近真实用户行为。4.3 验证码和滑块的处理就算做得再好闲鱼的滑块验证还是可能会弹出来。滑块验证本质上是一个图像识别和轨迹模拟问题处理方案有两种。第一种是保守方案检测到滑块验证后立即停止爬取等待一段时间或者更换IP后重新开始。这种方式实现简单缺点是会中断任务。第二种是主动方案用图像识别算法定位滑块缺口位置然后用带加速度轨迹模拟的方式拖动滑块。这个方案技术上可行但需要大量调试而且闲鱼的滑块验证码也在不断升级模拟轨迹的特征很容易被识别为机器行为。我实际采用的是第一种方案在中间件里检测响应中是否有滑块验证的特征标识有就直接抛异常同时记录触发次数。连续触发超过阈值就触发全局暂停机制冷却10分钟后继续。4.4 一个很重要的合规提醒虽然代码能跑通但爬虫是一把双刃剑。写这个项目的初衷是学习Scrapy框架和应对动态页面的技术方案不是鼓励大家去大规模采集闲鱼的数据。在实操时有几点需要特别注意控制爬取频率不要给目标服务器造成不必要的压力只采集公开可看的数据不要尝试绕过登录验证和获取非公开信息爬取到的数据只用于个人学习研究不要用于商业用途或公开传播遵守平台的服务条款尊重平台的合法权益我用这个项目做的主要是价格趋势分析和二手市场行情调研数据量控制在合理范围内。如果你是在公司环境做类似项目建议先咨询法务意见确保数据来源合规。5. 项目扩展与后续优化建议5.1 从搜索爬虫扩展到详情爬虫搜索列表页拿到的只是商品摘要字段更完整的描述、多图信息、卖家详情都在详情页接口里。可以把搜索爬虫和详情爬虫串联起来搜索爬虫产出商品ID列表详情爬虫根据ID列表请求详情接口补全数据字段。伪代码逻辑如下def parse_list(self, response): # 解析出商品ID列表 for item_id in item_id_list: # 构造详情请求回调到详情解析 yield Request( urlself.build_detail_url(item_id), callbackself.parse_detail, headers{...}, meta{item_id: item_id} ) def parse_detail(self, response): # 解析详情字段和搜索列表数据合并 detail_data json.loads(response.text) ...这里要注意的是详情接口的请求频率要控制得更低因为详情接口的风控更严格。5.2 价格走势监控与数据可视化爬虫是手段数据分析才是目的。对爬下来的数据做进一步的分析和处理能产生更大的价值。可以做的分析方向包括相同商品的二手价格走势曲线不同品牌、不同品类的溢价率对比闲置商品的流动性指标想买人数/浏览人数不同城市的二手商品供需热度数据可视化可以用matplotlib生成图表或者用Tableau做交互式看板。我目前已经实现了基础的报表自动生成功能每周跑一次数据汇总生成一份价格趋势报告。5.3 代码结构维护与异常监控爬虫项目最大的特点就是容易随着平台改版而“死掉”。一口吃不成胖子代码写完之后要建立完善的维护机制日志系统用Python的logging模块记录每个关键的节点状态方便回溯异常报警Webhook通知到手机或邮箱爬虫挂了能及时知道监控面板如果数据量到一定规模可以考虑接一个Grafana显示抓取数据量和成功率我自己维护这个项目时把所有的配置项都集中到了一个conf.py文件中包括URL模板、请求头、Cookie、数据库连接信息等。平台改版时只需要改配置文件不用翻整个代码库。最后再分享一个实用小技巧刚开始写爬虫时千万不要一上来就怼全量数据。先做好单页的抓取、解析、存储闭环确认整条链路没问题后再放开翻页和并发。我见过太多人一上来就开16个并发跑全站结果第二天还被风控封了IP连基本的调试都没法做了。稳扎稳打数据自然就来了。本文还有配套的精品资源点击获取