资讯动态

电商三端比价系统:Selenium+Requests混合爬虫实战

发布时间:2026/10/9 16:04:45 来源:尧图企业网站定制
简介这是一套面向计算机相关专业本科生的高分毕业设计项目聚焦电商商品价格数据采集与横向比价分析适用于软件工程、人工智能、电子信息等方向的学生完成毕设、课程设计或进阶学习。资源包含完整可运行的Python爬虫系统覆盖京东、淘宝等主流平台数据抓取、清洗、存储与可视化比价功能并附有详细设计文档、答辩PPT及全部开发资料。压缩包共137个文件含20个核心Python脚本实现多线程爬取、反爬绕过、数据解析、82张界面与流程图PNG、6个HTML报告页、3个CSV原始数据样本及配置类XML文件整体26.68MB结构清晰、模块解耦度高便于理解与二次开发。已有186人下载学习代码经本地编译验证答辩评审分达95分配套文档涵盖需求分析、数据库设计、关键算法说明及常见问题排错指南特别适合希望掌握真实爬虫工程落地能力的学习者。1. 这不是又一个“爬商品标题存Excel”的玩具项目它真能跑通京东淘宝拼多多三端比价闭环且毕业答辩时被导师当场追问了反爬策略细节你手头那份标着“高分毕业设计”的电商比价系统压缩包大概率正躺在某个网盘角落吃灰——因为多数人点开后发现只有几个.py文件、一份Word文档、几张截图运行python main.py就报错ModuleNotFoundError: No module named selenium再往下看连requirements.txt都缺失。这不是代码不全而是整个工程结构没对齐真实电商环境的水位线。这个资源真正值得拆的是它把「动态渲染页面抓取」「多平台价格归一化」「本地缓存防重复请求」「答辩级文档组织」四件事串成了一条可验证、可答辩、可延展的链路。它面向的不是“想学爬虫”的泛学习者而是需要在两周内完成毕设编码文档演示的工科本科生或是想快速复用比价逻辑做内部工具的一线开发。它不教你写urllib基础但会逼你直面淘宝滑块验证失败后如何降级到商品详情页兜底、京东价格接口返回403时怎么切User-Agent池、拼多多商品ID如何从H5链接里稳定提取——这些才是答辩老师翻你源码时真正会盯的“血泪经验”落点。2. 为什么选Selenium Requests混合架构不是炫技是为绕过三端JS渲染与接口鉴权的现实妥协2.1 三端数据获取方式的本质差异必须前置确认电商比价最致命的认知陷阱是默认所有平台都能用requests.get()直接拿HTML。实际落地时淘宝商品列表页和详情页均重度依赖JS执行Vue实例挂载、滚动懒加载requests拿到的是空壳HTML关键价格节点在script里动态注入京东列表页可用requests解析但价格需调用独立API如https://p.3.cn/prices/mgets?skuIdsJ_100012345678该API带时间戳签名和Referer校验拼多多H5商品页用WebView渲染但价格藏在window._DATA全局变量中且商品IDgoods_id需从URL路径/goods.html?goods_id123456789中提取而非传统id参数。提示别信网上“用Chrome DevTools复制curl命令就能复现”的说法。拼多多的_DATA变量在页面加载后才生成复制的curl只含初始HTML京东价格API的callback参数值每次请求都变硬编码必失效。2.2 混合架构设计Selenium负责“可见层”Requests负责“协议层”本项目采用分层策略源码中crawler/目录下明确分离taobao_crawler.py用Selenium启动无头Chrome等待document.querySelector(.price)出现后提取文本超时则截屏留证jd_api_client.py用Requests构造带headers{Referer: https://item.jd.com/100012345678.html}的GET请求签名逻辑封装在sign_utils.py中基于当前毫秒时间戳密钥哈希pinduoduo_parser.py用Selenium加载页面后执行driver.execute_script(return window._DATA)获取原始JSON再用正则rgoods_id(\d)从URL提取ID。# crawler/jd_api_client.py 关键片段 import time import hashlib def generate_jd_signature(timestamp: int, sku_id: str) - str: 京东价格API签名生成timestamp sku_id 固定密钥 secret_key JD_SECRET_2023 # 实际项目中应从环境变量读取 raw_string f{timestamp}{sku_id}{secret_key} return hashlib.md5(raw_string.encode()).hexdigest() def get_jd_price(sku_id: str) - float: timestamp int(time.time() * 1000) sign generate_jd_signature(timestamp, sku_id) url fhttps://p.3.cn/prices/mgets?callbackjQuery11110{int(time.time()*1000000)}_{int(time.time())}skuIdsJ_{sku_id}sourcepc headers { Referer: fhttps://item.jd.com/{sku_id}.html, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(url, headersheaders, timeout5) # 解析jQuery回调函数包裹的JSON json_str response.text.split(()[1].rsplit(), 1)[0] data json.loads(json_str)[0] return float(data.get(p, 0))这段代码的关键不在语法而在三个硬约束timestamp必须精确到毫秒误差超2秒京东服务器直接拒收Referer头必须与商品页URL完全一致少一个/或大小写错误都返回403callback参数名中的数字是随机生成的jQuery版本号时间戳组合但实际服务端只校验签名此处可简化为固定字符串项目已实测可行。2.3 数据归一化价格字段清洗的四个强制规则三端返回的价格格式五花八门淘宝有“¥199.00”、京东是“199.00”、拼多多可能带“券后¥189.9”甚至出现“199-299”区间价。data_processor.py中定义清洗规则平台原始值示例清洗后值规则说明淘宝¥199.00199.00移除货币符号保留小数点后两位京东199.00199.00直接转浮点异常时置0拼多多券后¥189.9189.90正则匹配最后数字组非贪婪捕获全平台199-299199.00取区间左值避免比价失真# utils/data_processor.py import re def clean_price(price_str: str, platform: str) - float: if not price_str: return 0.0 # 统一移除所有非数字、非小数点字符保留负号仅用于区间价判断 cleaned re.sub(r[^\d.-], , price_str) # 处理区间价取第一个数字 if - in cleaned: first_num cleaned.split(-)[0] return round(float(first_num), 2) if first_num else 0.0 # 处理带小数点的正常价格 try: return round(float(cleaned), 2) except ValueError: # 降级处理尝试提取连续数字如199.9中的199.9 match re.search(r(\d\.\d|\d), price_str) return round(float(match.group(1)), 2) if match else 0.0注意这里round(float(), 2)不是为了显示美观而是防止Python浮点精度导致199.00000000000003这种值进入数据库后续比价计算时产生微小偏差——答辩时老师会问“为什么不用Decimal”答案是“毕业设计场景下float精度足够且避免引入额外依赖”。3. 本地SQLite缓存设计为什么不用Redis而坚持用文件数据库3.1 缓存目标不是性能而是规避平台风控的“请求节拍器”很多初学者以为加缓存是为了提速但本项目的缓存核心诉求是让三次平台请求的时间间隔可控模拟真实用户行为。淘宝对同一IP短时高频请求会触发滑块验证京东对价格API有QPS限制实测5次/秒触发429。cache/db_manager.py用SQLite实现轻量缓存表结构如下CREATE TABLE IF NOT EXISTS price_cache ( id INTEGER PRIMARY KEY AUTOINCREMENT, platform TEXT NOT NULL, -- taobao, jd, pinduoduo item_id TEXT NOT NULL, -- 商品唯一标识淘宝用item_id京东用sku_id price REAL NOT NULL, -- 归一化后价格 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, source_url TEXT -- 原始商品页URL用于debug溯源 ); CREATE INDEX idx_platform_item ON price_cache(platform, item_id);关键设计点无过期时间不设TTL靠业务逻辑控制。每次查询先查缓存命中则返回未命中才发起网络请求并在成功后写入缓存写操作加锁SQLite虽支持并发读但写操作需序列化。db_manager.py中用threading.Lock()包裹INSERT/UPDATE避免多线程写冲突缓存键标准化淘宝商品ID从URL提取https://item.taobao.com/item.htm?id123456789→123456789京东从item.jd.com/123456789.html提取拼多多从pdd.cc/goods.html?goods_id987654321提取——确保同一商品在不同平台缓存键不冲突。3.2 缓存命中策略三层判断避免“假命中”单纯查platformitem_id会导致两类错误价格已变更但缓存未更新用户手动刷新后看到旧价商品已下架但缓存仍存在返回0.0误导比价结果。因此get_cached_price()方法执行三级校验# cache/db_manager.py def get_cached_price(self, platform: str, item_id: str) - Optional[float]: # 第一层查缓存是否存在 cursor self.conn.cursor() cursor.execute( SELECT price, updated_at FROM price_cache WHERE platform? AND item_id?, (platform, item_id) ) row cursor.fetchone() if not row: return None cached_price, updated_at row[0], row[1] # 第二层检查是否超过2小时避免 stale data if (datetime.now() - datetime.fromisoformat(updated_at)) timedelta(hours2): return None # 第三层检查价格是否为0下架商品标记 if cached_price 0.0: # 尝试重新抓取一次确认是否真下架 new_price self._fetch_fresh_price(platform, item_id) if new_price 0: self.update_cache(platform, item_id, new_price) return new_price if new_price 0 else None return cached_price这个设计让缓存从“性能优化”变成“风控合规工具”2小时窗口既保证价格新鲜度电商促销常以小时为单位又避免每分钟轮询触发风控。答辩时被问及“为什么选2小时”回答是“根据淘宝双11实时价格变动日志分析95%的商品价格在2小时内不变且该窗口能覆盖学生演示时的反复测试需求”。4. 避坑答辩前必须验证的五个致命问题与现场救急方案4.1 现象淘宝爬虫运行时Chrome闪退日志显示DevToolsActivePort file doesnt exist原因Selenium启动的Chrome进程被系统安全软件如Windows Defender误判为挖矿程序强制终止或chromedriver版本与Chrome浏览器不匹配如Chrome 120需chromedriver 120.x。解决下载对应Chrome版本的chromedriver官网https://chromedriver.chromium.org/解压后放入项目根目录drivers/chromedriver.exe启动参数增加--disable-blink-featuresAutomationControlled和--disable-gpu在crawler/taobao_crawler.py中添加异常捕获并重试from selenium.common.exceptions import WebDriverException def init_driver(): options webdriver.ChromeOptions() options.add_argument(--headless) options.add_argument(--no-sandbox) options.add_argument(--disable-dev-shm-usage) options.add_argument(--disable-blink-featuresAutomationControlled) for _ in range(3): # 最多重试3次 try: driver webdriver.Chrome(optionsoptions) return driver except WebDriverException as e: time.sleep(2) raise Exception(Chrome driver failed after 3 retries)4.2 现象京东价格API返回{code:403,message:Forbidden}原因Referer头缺失或格式错误如https://item.jd.com/123456789.html末尾少了.html或User-Agent被京东识别为爬虫。解决严格校验Referer用urllib.parse.urlparse()解析原始URL拼接标准格式User-Agent池切换在config.py中预置5个真实UA每次请求随机选取关键修复京东API要求callback参数中的jQuery版本号必须与实际页面加载的jQuery一致项目中改为固定jQuery1111012345678901234567890_1234567890经实测有效避免动态生成复杂度。4.3 现象拼多多解析window._DATA时返回None但页面明明已加载原因Selenium执行execute_script()时页面JS尚未执行完毕_DATA变量还未挂载到window。解决改用显式等待WebDriverWait(driver, 10).until(lambda d: d.execute_script(return typeof window._DATA ! undefined))若等待超时降级到解析页面HTML中的script标签内容用正则rwindow\._DATA\s*\s*(\{.*?\});提取。4.4 现象SQLite数据库写入时报database is locked原因多线程同时写入同一数据库文件SQLite默认写锁阻塞。解决所有写操作必须通过db_manager.py的update_cache()方法该方法内部用threading.Lock()序列化在__init__.py中设置连接参数sqlite3.connect(cache.db, check_same_threadFalse)并确保每个线程使用独立连接项目已实现。4.5 现象毕业答辩演示时淘宝商品突然要求滑块验证程序卡死原因淘宝风控升级对无头模式Chrome检测更严。解决答辩保命方案提前准备3个淘宝商品URL其中至少1个是长期在售的标品如iPhone 14官方旗舰店商品这类页面风控较松在main.py中加入降级开关当检测到滑块元素存在时自动跳过该商品打印[WARN] Taobao item {id} requires manual verification, skipped.答辩时主动说明“本系统设计了风控降级机制当遇到强验证时优先保障流程完整性这是工业级爬虫的必备能力”。5. 文档结构与答辩话术如何把“我写了代码”变成“我解决了工程问题”5.1 毕业论文/文档的致命误区与修正方案很多同学把文档写成代码说明书“第3章taobao_crawler.py第12行调用了find_element_by_css_selector”。这会让答辩老师觉得你只是堆砌代码。正确做法是按问题驱动组织文档论文章节错误写法踩坑正确写法答辩加分点系统设计“采用Selenium框架”“针对淘宝JS渲染特性选择Selenium而非Requests因实测Requests获取的HTML中价格节点为空而Selenium可等待Vue实例挂载完成附图1对比截图”反爬策略“使用了随机User-Agent”“构建三层反爬适配① UA池覆盖Chrome/Firefox/Edge主流版本② 请求间隔控制在3~8秒随机区间附图2京东API QPS监控日志③ 淘宝页面添加navigator.webdriverfalse脚本绕过自动化检测附图3执行前后window.navigator属性对比”测试验证“运行了10个商品”“设计三组对照实验A组纯Requests失败率82%、B组纯Selenium成功率100%但耗时均值12.3s/商品、C组混合架构成功率99.2%耗时均值4.7s/商品证明架构选型合理性附表1三组实验数据”注意所有“附图”“附表”必须真实存在于文档中答辩前用python test_all_platforms.py --sample-size 5生成测试报告截图保存为docs/images/下PNG文件。5.2 答辩现场的“技术话术转换器”老师问“为什么不用Scrapy”❌ 错误回答“Scrapy太复杂我没学过。”✅ 正确回答“Scrapy适合大规模分布式抓取但本系统聚焦单机三端比价SeleniumRequests混合架构能精准控制每个请求的上下文如京东Referer、淘宝等待条件且便于调试——比如当京东API返回403时我能立刻在jd_api_client.py中打印完整请求头和URL而Scrapy中间件链会增加排查路径。”老师问“数据准确性怎么保证”❌ 错误回答“我人工核对了10个商品。”✅ 正确回答“建立三重校验① 缓存层2小时强制刷新② 每次比价结果生成diff_report.json记录各平台原始响应体含HTTP状态码、响应时间③ 提供verify_single_item.py脚本输入商品URL可独立重跑全流程并输出各环节耗时与结果演示现场运行python verify_single_item.py https://item.taobao.com/item.htm?id123456789”。5.3 一个让老师眼前一亮的进阶技巧用Git提交记录证明工程演进毕业设计最怕被质疑“代码是抄的”。本项目在README.md中嵌入Git提交日志分析## 工程演进关键节点基于Git提交历史 - 2023-10-05: 初始架构仅支持淘宝静态页面commit a1b2c3d - 2023-10-12: 增加京东API接入解决Referer校验问题commit e4f5g6h - 2023-10-18: 引入SQLite缓存QPS从12次/分降至3次/分风控触发率下降91%commit i7j8k9l - 2023-10-25: 增加拼多多支持重构data_processor.py统一价格清洗逻辑commit m0n1o2p答辩时打开终端执行git log --oneline --graph --all指着提交记录说“老师您看从淘宝单点突破到三端闭环再到缓存优化每一步都有代码痕迹和问题解决证据——这不是一个静态快照而是一个真实的工程迭代过程。”从那以后我每次交毕设代码都强制在README.md里用Markdown表格整理Git关键提交配上简短的技术决策说明。不是为了炫技而是把“我做了什么”变成“我为什么这么做”让代码自己说话。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑