Python 2.7+Scrapy 1.4电商爬虫实战:京东淘宝天猫反爬适配指南
简介这是一套面向数据采集工程师、电商研究者及Python初学者的实战型爬虫工具包旨在解决京东、淘宝、天猫三大平台商品信息高效抓取难题尤其适用于市场分析、竞品监控与价格趋势研究等场景。资源共20个文件含12个核心Python脚本如spiders、pipelines、middlewares等模块、2个Shell启动脚本init.sh/run.sh、1个JSON配置文件setting.json用于管理cookie与参数、1个CFG配置模板、1个README.md说明文档及1个附赠Word使用指南整体仅49KB轻量易部署。已有90人学习下载体现其在中小规模数据采集任务中的实用价值。用户可直接复用完整Scrapy项目结构通过修改关键词与cookie配置快速适配不同搜索需求代码模块职责清晰涵盖请求调度、反爬绕过、CSV/MongoDB双通道存储及基础数据清洗逻辑具备良好的可读性与二次开发基础。1. 这不是“一键爬全网”的玩具一个真实跑在 Python 2.7 Scrapy 1.4 上、能过京东滑块加密、淘宝 Cookie 校验、天猫 Referer 拦截的生产级电商爬虫工具你手头这份e-commerce-spider-master.zip不是 GitHub 上那种「能跑 demo 就算成功」的玩具项目。它是一套在 2018–2020 年间被实际用于竞品价格监控、SKU 全量建档、电商舆情初筛的落地工具——核心逻辑跑在Python 2.7.18非 3.x和Scrapy 1.4.0非 2.x上所有中间件、Pipeline、Spider 都针对三大平台反爬机制做了硬编码适配京东用的是带jd_login模块的 Cookie 注入UA 轮换请求间隔抖动淘宝走的是taobao_logincookie_format.py解析.txt格式 Cookie 字符串并注入requests.Session天猫则依赖RefererUser-AgentX-Requested-With三重伪造绕过其 JS 渲染拦截。它不依赖 Playwright 或 Selenium纯 Scrapy 异步调度单机日均稳定抓取 12–18 万 SKU含详情页评论页但前提是——你得先让它的init.sh正确加载setting.json里的user_cookie和search_keywords且不能漏掉dbs.py里 MongoDB 的authSource配置。适合需要长期跑批、对数据字段完整性要求高商品标题/价格/月销量/好评率/店铺名/SPU 编码/主图 URL/详情页 HTML 原始快照、且能接受 Python 2.7 技术栈约束的中小团队数据工程师、市场分析岗或独立开发者。别指望它开箱即用但只要调通它比绝大多数 Python 3.x 爬虫更稳——因为它的对抗逻辑是用真实电商运营场景反复锤出来的。2. 为什么必须是 Python 2.7 Scrapy 1.4这不是技术债而是反爬兼容性选择2.1 京东滑块加密与 Python 2.7 的 OpenSSL 兼容性真相京东在 2019 年底升级滑块验证后其callback参数生成依赖Crypto.Cipher.AES的 ECB 模式 base64.b64encode而 Scrapy 1.4 默认使用的pyOpenSSL 16.2.0在 Python 2.7 下能正确解析京东返回的Set-Cookie中带Path/; Domain.jd.com; HttpOnly的复合 Cookie 字段。换成 Python 3.6 后http.cookies.SimpleCookie对HttpOnly属性的解析会丢弃关键pt_key和pt_pin导致后续请求直接 302 跳登录页。本项目cookie_format.py第 47 行明确写死# cookie_format.py def parse_jd_cookie(raw_cookie): # Python 2.7 str is bytes, no decode needed # Python 3.x would require .encode(latin-1) then .decode(utf-8) —— but breaks jds base64 padding cookies {} for item in raw_cookie.split(; ): if in item: k, v item.split(, 1) cookies[k.strip()] v.strip() return cookies这段代码在 Python 3 下会因v.strip()返回str而k.strip()是bytes导致KeyError。这不是 bug是刻意为之——因为京东当时返回的 Cookie 值含\x00字节Python 2.7 的str可原生承载Python 3 的str会报UnicodeDecodeError。所以强行升 Python 版本放弃京东支持。2.2 Scrapy 1.4 的 Downloader Middleware 执行顺序不可替代淘宝搜索页的反爬核心是anti_content字段校验其生成依赖window.performance.timing.navigationStart时间戳 document.referrernavigator.userAgent拼接后 MD5。Scrapy 1.4 的DownloaderMiddleware执行链中process_request在spider.parse之前触发且request.meta[proxy]可被middlewares.py中的RandomUserAgentMiddleware动态注入。而 Scrapy 2.0 改为process_request→process_response→process_exception三级回调request.meta在中间被清空导致taobao_login.py里self.session.get(url, headersself.headers)无法复用已注入的 UA 和 Referer。本项目middlewares.py第 89 行# middlewares.py class TaobaoRefererMiddleware(object): def process_request(self, request, spider): if taobao in request.url: # Scrapy 1.4 guarantee: request.meta is persistent across middleware stack if not request.meta.get(taobao_referer): request.headers[Referer] https://www.taobao.com/ request.meta[taobao_referer] True这个request.meta标记在 Scrapy 1.4 下全程存活在 2.0 下第二层 middleware 就丢失。这就是为什么pipelines_csv.py能拿到完整 Referer 日志而新版 Scrapy 用户常抱怨「Referer 总是空」。2.3 天猫的X-Requested-With伪造必须绑定 Scrapy 1.4 的 Request 构造逻辑天猫商品列表页如https://list.tmall.com/search_product.htm?q手机会校验X-Requested-With: XMLHttpRequest但仅此不够——它还检查Accept是否为application/json, text/javascript, */*; q0.01。Scrapy 1.4 的Request类允许在__init__中直接传入headers字典且该字典在scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware前生效。本项目spiders/tmall_spider.py第 62 行# tmall_spider.py yield scrapy.Request( urlurl, headers{ X-Requested-With: XMLHttpRequest, Accept: application/json, text/javascript, */*; q0.01, User-Agent: self.ua.random }, callbackself.parse_list, meta{dont_redirect: True} )Scrapy 2.0 要求通过scrapy.http.headers.Headers类构造且HttpCompressionMiddleware会覆盖Accept为text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8导致天猫直接返回 403。这不是配置问题是框架底层行为变更。提示不要尝试用pip install scrapy2.6.1 --force-reinstall覆盖本项目依赖。settings.py第 12 行BOT_NAME e_commerce_spider和第 34 行SPIDER_MODULES [e_commerce_spider.spiders]已深度耦合 Scrapy 1.4 的模块加载器。强行升级会导致ImportError: No module named core.downloader.handlers.http11。3. 从解压到首条数据入库五步走通全流程3.1 环境初始化Python 2.7.18 Scrapy 1.4.0 的最小可信安装先确认系统已装gcc、openssl-develCentOS或libssl-devUbuntu。不要用pyenv或conda它们默认创建隔离环境而本项目init.sh依赖全局pip。执行# CentOS 7 / Ubuntu 16.04 LTS wget https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz tar -xzf Python-2.7.18.tgz cd Python-2.7.18 ./configure --enable-optimizations make -j$(nproc) sudo make altinstall sudo /usr/local/bin/python2.7 -m pip install --upgrade pip sudo /usr/local/bin/python2.7 -m pip install scrapy1.4.0 pymongo3.7.2 requests2.20.0注意pymongo3.7.2是关键——它支持MongoClient(host, port, authSourceadmin)而 4.x 版本强制要求authMechanismSCRAM-SHA-1但本项目dbs.py第 22 行写死authSourceadmin无authMechanism参数。若装错版本scrapy crawl tmall会卡在pymongo.errors.OperationFailure: Authentication failed.。3.2 配置文件注入setting.json的四个必填字段与三个隐藏约束解压后进入e-commerce-spider-master目录编辑setting.json{ mongodb: { host: 127.0.0.1, port: 27017, db_name: ecommerce, collection_name: products, username: spider_user, password: your_strong_password, authSource: admin }, cookies: { jd: pt_keyxxx; pt_pinyyy; ..., taobao: txxx; cookie2yyy; ..., tmall: cnaxxx; _tb_token_yyy; ... }, keywords: [手机, 笔记本电脑, 蓝牙耳机], concurrent_requests: 8 }⚠️ 三个隐藏约束cookies.jd必须包含pt_key和pt_pin缺一则京东登录态失效spiders/jd_spider.py第 156 行if pt_key not in cookie_dict:会跳过请求cookies.taobao中的cookie2值必须以cookie2开头否则cookie_format.py第 112 行正则rcookie2([^;])匹配失败返回空字典keywords数组长度不能超过 5否则spiders/taobao_spider.py第 88 行for kw in keywords[:5]:截断后run.sh启动时scrapy crawl taobao -a keyword手机会忽略后续关键词。3.3 Cookie 提取实操从浏览器导出到setting.json的三步清洗法以 Chrome 为例Firefox 同理登录京东 → F12 → Application → Cookies → 右键https://www.jd.com→ Save as →jd_cookies.txt打开文件删除第一行# Netscape HTTP Cookie File和所有#HttpOnly_开头的行用 Python 2.7 脚本清洗# clean_cookie.py with open(jd_cookies.txt) as f: lines f.readlines() cleaned [] for line in lines: if not line.startswith(#) and \t in line: parts line.strip().split(\t) if len(parts) 7: # domain, flag, path, secure, expires, name, value cleaned.append(%s%s % (parts[5], parts[6])) print(; .join(cleaned))运行python2.7 clean_cookie.py输出结果复制到setting.json的cookies.jd字段。血泪经验淘宝 Cookie 必须从「我的淘宝」页面抓不能从搜索页抓——后者缺少cookie2和_tb_token_天猫 Cookie 必须带cna字段否则spiders/tmall_spider.py第 203 行if cna not in cookie_dict:会拒绝请求。3.4 启动爬虫run.sh的真实作用与手动调试入口run.sh内容极简#!/bin/bash scrapy crawl jd -a keyword手机 scrapy crawl taobao -a keyword笔记本电脑 scrapy crawl tmall -a keyword蓝牙耳机 wait但它隐含两个关键动作启动后台进程避免单个 Spider 失败阻塞全部wait确保三个进程全部结束才退出方便cron定时调用。调试时不要直接跑run.sh而是用scrapy crawl jd -a keyword手机 -s LOG_LEVELDEBUG -s CLOSESPIDER_ITEMCOUNT50-s CLOSESPIDER_ITEMCOUNT50限制只抓 50 条避免首次调试时触发平台风控-s LOG_LEVELDEBUG输出middlewares.py中process_request的每一步 header 注入日志确认X-Requested-With是否生效。3.5 数据落库验证MongoDB 中products集合的字段完整性检查成功运行后进 MongoDB 执行use ecommerce db.products.find({platform: jd}, {title: 1, price: 1, shop_name: 1, sku_id: 1, _id: 0}).limit(3)应返回类似{ title : Apple iPhone 14 Pro Max 256GB 深空黑色 支持移动联通电信5G双卡双待, price : 8999.00, shop_name : Apple官方旗舰店, sku_id : 100038913221 }若price为空检查pipelines_mongodb.py第 68 行item.get(price) or item.get(sale_price)——京东有时返回sale_price若shop_name为空说明jd_spider.py第 221 行response.css(.p-shop a::text).extract_first()未匹配到需检查是否被京东改版此时要更新 CSS 选择器为response.xpath(//div[classp-shop]/span/a/text()).extract_first()。4. 避坑这六个翻车点90% 的人第一次跑就栽在第三步4.1 现象scrapy crawl jd启动后立即报ImportError: No module named Crypto.Cipher原因pip install scrapy1.4.0不自动安装pycrypto而jd_login.py第 12 行from Crypto.Cipher import AES依赖它。且pycrypto在 Python 2.7 下必须用gcc编译pip install pycrypto会因缺少python2.7-dev头文件失败。解决sudo yum install python27-devel gcc-c # CentOS # 或 sudo apt-get install python2.7-dev build-essential # Ubuntu sudo /usr/local/bin/python2.7 -m pip install pycrypto2.6.14.2 现象淘宝爬虫跑出 0 条数据日志显示Filtered duplicate request原因taobao_spider.py第 45 行start_urls [https://s.taobao.com/search?q{}.format(keyword)]生成的 URL 被 Scrapy 的dupefilter当作重复请求过滤。因为keyword是中文URL 中q手机未 urlencodeScrapy 1.4 的RFPDupeFilter默认对原始 URL 字符串哈希而q%E6%89%8B%E6%9C%BA和q手机哈希值不同但scrapy.dupefilters.RFPDupeFilter在request_fingerprint中会对urlparse.urlparse(request.url).path做标准化导致中文关键词被误判为重复。解决在settings.py末尾添加# settings.py DUPEFILTER_CLASS scrapy.dupefilters.BaseDupeFilter并修改taobao_spider.py第 45 行import urllib start_urls [https://s.taobao.com/search?q{}.format(urllib.quote(keyword.encode(utf-8)))]4.3 现象天猫爬虫返回403 Forbidden但curl -H X-Requested-With: XMLHttpRequest却能成功原因tmall_spider.py第 188 行yield scrapy.Request(url, headersheaders, ...)中headers字典被HttpCompressionMiddleware覆盖Accept变成text/html。但curl手动指定时不会经过中间件。解决禁用压缩中间件在settings.py中# settings.py HTTPCOMPRESS_ENABLED False或更精准地在tmall_spider.py的start_requests方法中def start_requests(self): for url in self.start_urls: yield scrapy.Request( urlurl, headersself.headers, dont_filterTrue, meta{handle_httpstatus_list: [403]} )4.4 现象MongoDB 存入数据后price字段全是None但日志显示Extracted price: ¥5999原因pipelines_mongodb.py第 72 行item[price] float(item.get(price, ).replace(¥, ).strip())中replace(¥, )在 Python 2.7 下对 Unicode 字符串无效。京东返回的price是u¥5999.00replace不处理 Unicode导致float(¥5999.00)报ValueErrorexcept块设为None。解决在pipelines_mongodb.py第 71 行前加# pipelines_mongodb.py if isinstance(item.get(price), unicode): item[price] item[price].encode(utf-8)4.5 现象run.sh启动后三个进程都显示Finished但 MongoDB 里一条数据都没有原因setting.json中mongodb.authSource写成admin但实际用户是在ecommerce库下创建的。dbs.py第 22 行MongoClient(host, port, usernameusername, passwordpassword, authSourceauth_source)会去admin库查用户找不到就静默失败。解决要么在 MongoDB 创建用户时指定authSourceuse admin db.createUser({user: spider_user, pwd: your_strong_password, roles: [{role: readWrite, db: ecommerce}]})要么把setting.json中authSource改为ecommerce。5. 进阶技巧用EvaluateCrawl模块做反爬强度压测与成功率基线校准5.1EvaluateCrawl是什么它不是测试脚本而是反爬韧性仪表盘e-commerce-spider-master/EvaluateCrawl/目录下有三个文件test_jd.py模拟 100 次京东搜索请求记录200/302/403/503状态码分布test_taobao.py用requests.Session复现taobao_login.py流程统计cookie2有效期衰减曲线report.py聚合三平台 24 小时成功率生成 CSV 报表。它存在的意义是帮你回答一个关键问题你的 Cookie 还剩多少小时有效当前并发数下京东每分钟最多扛住多少请求而不触发滑块这不是理论值是实测基线。5.2 执行test_jd.py获取京东滑块触发阈值的黄金参数进入EvaluateCrawl目录编辑test_jd.py# test_jd.py import time import requests from cookie_format import parse_jd_cookie # 从 setting.json 读取 jd cookie with open(../setting.json) as f: config json.load(f) cookie_dict parse_jd_cookie(config[cookies][jd]) headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Cookie: config[cookies][jd] } success_count 0 block_count 0 for i in range(100): url https://search.jd.com/Search?keyword%E6%89%8B%E6%9C%BAencutf-8 try: r requests.get(url, headersheaders, timeout10) if r.status_code 200 and 滑块 not in r.text: success_count 1 elif r.status_code 302 or captcha in r.url: block_count 1 time.sleep(1.2) # 京东要求最小间隔 1.2s except Exception as e: pass print(Success: {}, Block: {}.format(success_count, block_count))运行python2.7 test_jd.py若Block超过 15%说明Cookie 已过期需重新登录提取或当前 IP 被限频需切换代理本项目不内置代理但middlewares.py第 33 行预留了ProxyMiddleware接口可自行注入proxies{http: http://user:passip:port}。5.3 用report.py建立每日巡检 SOP三平台成功率基线表report.py会连接 MongoDB统计过去 24 小时各平台status字段由pipelines_mongodb.py第 95 行写入PlatformTotal RequestsSuccess (%)Block (%)Parse Error (%)JD124,89298.2%1.3%0.5%Taobao187,30595.7%3.1%1.2%Tmall92,41697.4%2.0%0.6%当某平台Block (%)连续 2 小时 5%SOP 触发自动运行test_jd.py或对应平台脚本若Block 20%发邮件告警并暂停该平台爬虫人工介入用浏览器登录平台导出新 Cookie更新setting.json。注意report.py第 42 行db.products.find({crawl_time: {$gt: datetime.now() - timedelta(hours24)}})使用datetime.now()必须确保服务器时区为Asia/Shanghai否则统计窗口偏移。用timedatectl set-timezone Asia/Shanghai校准。5.4 一个真实踩坑后的习惯每次更新setting.json后强制跑一次test_taobao.py淘宝 Cookie 的cookie2字段有效期极短通常 2–4 小时且t字段每 30 分钟刷新一次。我曾因忘记更新setting.json导致凌晨 3 点爬虫批量失败日志里全是{error: invalid cookie2}。现在我的流程是修改setting.jsoncd EvaluateCrawl python2.7 test_taobao.py确认输出Valid cookie2: True, Expires in: 2.3 hours才执行sh run.sh。这个习惯让我连续 11 个月没出现过淘宝全量失败。希望帮到你。本文还有配套的精品资源点击获取