ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python淘宝评论采集实战:接口分析与JS逆向签名算法全流程

2026/8/30 9:20:04 拓冰建站 浏览量
Python淘宝评论采集实战:接口分析与JS逆向签名算法全流程 简介本资源是一套面向Python爬虫开发者与电商数据分析学习者的淘宝商品评论采集实战代码聚焦于突破平台反爬机制的逆向工程实践适用于舆情分析、竞品研究及用户行为建模等场景。压缩包共5个文件含核心采集脚本.py、逆向关键逻辑的JavaScript签名生成片段.js、项目说明文档.md、示例截图.png及版本控制配置.gitignore整体仅227KB轻量易部署。已有162人学习下载体现了其在小规模电商数据获取任务中的实用价值。读者可直接复用完整采集流程从HTTP/2协议请求构造、动态sign参数逆向解析到评论分页抓取与结构化存储所有源码均组织在source_code目录下采集结果自动落盘至data文件夹兼顾可读性与工程规范性。 做电商数据采集的人基本都绕不开淘宝这个平台。商品详情、价格、销量、评论每一项都是很有价值的数据资产。尤其是商品评论直接关系到用户反馈分析、竞品调研、选品决策这些场景很多做数据分析、电商运营的朋友都动过抓评论的念头。但真上手之后才发现淘宝的接口不像公开API那么好说话请求参数加密、签名校验、滑块验证一层套一层不把逆向这关过了连数据都摸不到。这个项目“基于Python实现淘宝商品评论采集含逆向源代码.zip”说白了就是一整套从接口分析、加密参数逆向到数据落地的完整流程。标题里最值钱的两个字是“逆向”因为采集本身不复杂复杂的是怎么让服务端认为你是一个正常的客户端。这篇博文不整虚的直接拆项目把设计思路、逆向要点、代码实现、常见坑位全部捋一遍。适合已经会Python基础、想接触电商数据采集和JS逆向的读者看完之后你能独立走通一条采集链路也知道遇到封控、签名变化时该往哪个方向排查。1. 项目整体设计与核心思路1.1 为什么把目标定为“商品评论”先聊选题。市面上爬虫教程铺天盖地但很多都在拿静态页、公开API练手跟真实生产环境脱节。淘宝评论这个目标难度卡在一个非常合适的位置比爬静态页难因为它有动态请求和加密参数比逆向APP简单因为H5端的JS代码相对容易定位和调试。对一个想进阶的爬虫开发者来说这是最好的实战素材既练了抓包又练了JS逆向还能把完整的采集链路跑通。从数据价值上看商品评论的采集需求非常真实不是为爬而爬。电商运营要看用户对竞品评价的集中吐槽点产品经理要做需求挖掘数据分析师要算好评率、关键词分布。这些场景都需要结构化的评论数据包括评分、内容、标签、追评、时间、买家信息等字段。所以这个项目选的不是技术上的冷门方向而是数据需求侧的刚需方向。1.2 技术栈选型与整体采集链路整个项目的技术选型比较经典没有花里胡哨的框架核心就是Python加请求库配合抓包工具和浏览器调试工具完成逆向分析。具体来说编程语言Python 3.8爬虫领域最顺手的选择请求库requests或者httpx负责发HTTP请求、维持会话抓包工具Charles或Fiddler用来截获PC端或手机端发出的真实请求接口分析Chrome DevTools定位接口、查看JS调用栈逆向定位通过搜索关键词定位加密函数必要时用补环境或JS注入数据存储标准库sqlite3或csv轻量够用采集链路其实不复杂核心就四步分析接口、逆向参数、构造请求、解析存储。真正花时间的是第二步也就是逆向。很多人一听到“逆向”两个字就头大实际上在Web端这个场景下逆向工作的本质就一句话找出请求参数是怎么生成的然后用Python模拟这个生成过程。1.3 逆向在项目中的位置我必须先泼一盆冷水很多人以为淘宝评论采集难在解析和存储其实这些部分哪怕用正则硬写都能搞定。真正的拦路虎是接口的签名参数。淘宝的评论接口不是直接暴露出来的页面上看到的数据是通过异步接口加载的而这个接口要求携带一组动态参数比如sign、t、appKey这些字段其中sign是根据请求内容和时间戳动态生成的每次请求都不一样。如果你少了这个sign接口直接返回错误连评论数据的影子都见不到。这一步就是逆向存在的意义——分析出sign的生成规则在Python里复现它。整个项目的所有代码、所有流程其实都是围绕这个逆向结果展开的。这也是为什么我把这个项目称为“含逆向”而非普通爬虫项目因为逆向才是它的灵魂。2. 环境准备与工具链2.1 Python环境与依赖库动手之前先把环境收拾利索。Python版本建议3.8以上太老的版本有些新语法和类型注解支持不好调试起来憋屈。依赖库方面我列一份实际用得上的清单库名用途安装方式requests发送HTTP请求pip install requestshttpx备用HTTP客户端支持HTTP/2pip install httpxpyexecjs执行JavaScript代码pip install pyexecjsnodejs环境调试JS代码片段官网下载安装lxml解析HTML/XMLpip install lxmlpandas数据处理与CSV导出pip install pandas这里重点说下pyexecjs和nodejs。逆向过程中你会经常需要验证某个JS函数在特定输入下是否输出正确结果与其在浏览器里反复调试不如直接把这个函数抠出来在Python里调用JS引擎执行。pyexecjs就是干这个的但它的底层依赖一个JS运行时Windows下默认用系统自带JScript能力有限强烈建议装Node.js然后让pyexecjs走Node引擎效率和兼容性都会好很多。2.2 抓包工具的选择与配置抓包是整个逆向分析的第一步没有真实请求数据后面全是瞎猜。我自己的习惯是用Charles跨平台、界面清晰、过滤器好用。Fiddler在Windows下也很流行两者选一个就行关键是配置好HTTPS解密。为什么必须解密HTTPS因为现在几乎所有接口都是HTTPS加密传输不装证书、不开解密你看到的就是一堆乱码。Charles配置HTTPS解密分三步安装Charles根证书到系统信任区、在SSL Proxying设置里添加目标域名、手机端或PC端代理指向Charles。手机端抓包还需要把证书安装到手机里并且信任该证书。这里有个细节容易踩坑淘宝App和H5的请求都涉及多个域名你不需要全部解密只需要关注评论接口所属的域名。开太多解密规则反而拖慢抓包速度甚至触发一些异常。精确配置目标域名既能看清数据又能减少干扰。2.3 逆向辅助工具的搭配除抓包工具外另外两个工具也非常重要。第一个是Chrome DevTools浏览器自带的开发者工具在“Sources”面板里可以搜索JS文件内容、打断点、查看调用栈是定位加密函数的主战场。第二个是AST相关工具比如babel或webpack解析工具用于处理混淆严重的JS代码不过一般场景下用不上淘宝H5端的JS更多是变量名压缩可读性还不算太恶劣。如果遇到的是webpack打包出来的JS结构会比较复杂。这时候可以用webpack-merge的思路去分析模块加载器或者直接在全局对象上下断点hook关键函数。但这些都是进阶玩法项目里如果只是采集评论通常不需要把整包JS啃下来精准定位目标函数就够了。3. 逆向核心环节拆解3.1 评论数据从哪里来很多人一开始会去翻页面源码试图在HTML里找评论数据翻半天一无所获最后在Network面板里看到一堆XHR请求才恍然大悟评论是异步加载的。顺着XHR请求一个个点过去你会看到一个和评论高度相关的接口返回的是JSON格式数据里面嵌套着评论列表、评分、标签、追评等信息。这里有个小技巧要分享与其在请求列表里大海捞针不如直接在页面上触发“加载更多评论”或“只看当前页”观察新增了哪个请求。用这个方式能非常快地锁定接口URL。锁定之后再看它的请求参数和响应结构逆向目标就明确了。3.2 请求参数逐一拆解点开评论接口的详情你会看到一串参数不要被吓到绝大多数参数是固定值或者可以从页面上下文中直接提取。真正需要逆向的通常只有那么一两个。以评论接口为例常见的参数结构大致如下参数名类型是否动态备注itemIdint固定商品ID从商品页URL提取pageSizeint自定义每页数量一般20或40pageNumberint动态当前页码翻页时递增sellerIdint固定卖家ID从商品页数据中提取appKeystring固定客户端标识如12574478tstring动态当前时间戳毫秒值signstring动态以上参数的签名结果在这个表格里itemId和sellerId属于业务参数从页面上下文或详情接口中就能拿到。pageSize和pageNumber是自己控制的翻页参数。appKey一般是固定的标识请求来自哪个客户端。真正的重头戏是t和signt是时间戳动态变化的sign是对一组参数做哈希计算后得到的签名串也是服务端校验请求合法性的核心凭证。3.3 Token与Sign的逆向思路逆向签名的第一步是搞清楚sign是用什么算法算出来的。常见做法是在JS文件中搜索关键词比如sign、md5、sha256、hex、digest通过关键词定位到生成签名的函数。如果JS经过压缩搜索出来的结果可能是一堆压缩后的变量名这时候要结合调用栈看这个函数是被谁调用的参数又从哪里传入。我见过不少初学者卡在这一步搜到了疑似加密函数但看不明白逻辑。我的建议是先看函数入参再看函数内部调用了哪些内置方法。如果函数里出现了类似md5的调用、对字符串做拼接、最后输出32位或16位hex字符串那大概率就是MD5签名。淘宝的评论接口签名逻辑并不复杂很多情况下就是按一定顺序拼接参数加上一个固定的密钥字符串再做哈希。你不需要把整段JS背下来只需要看懂拼接规则在Python里用hashlib.md5()复现即可。这里要特别提醒签名算法里的密钥字符串通常不会直接暴露在JS变量中可能在代码中经过拼接、反转、编码等处理。逆向时要留意字符串拼接的细节比如是否有前置或后置的固定字符串是否对参数做过排序这些都会直接影响签名的最终结果。验证签名是否正确的方法很简单在Python里按规则生成签名和浏览器请求里的签名比对一致就说明逆向正确。3.4 滑块验证与风控应对的合规处理签名逆向了请求构造了但你可能还是拿不到数据因为淘宝的风控系统会识别异常请求常见的手段就是弹出滑块验证要求你拖动滑块完成人机校验。很多爬虫项目到了这一步就猝死了。我需要先强调一个基本观念任何绕过验证码或风控系统的自动化操作都必须限定在合法的数据采集与研究范围内并且要尊重目标网站的规则和法律法规。本文讨论的技术内容仅用于学习和研究接口交互原理请勿用于任何非法用途或对平台造成实质性压力的批量采集。在合规前提下从纯技术研究的角度看处理滑块验证的思路通常是分析滑块图片的缺口位置、构造拖拽轨迹、模拟真实用户行为。具体来说缺口识别可以用OpenCV的边缘检测算法来找拼图缺口坐标拖拽轨迹则需要模拟从慢到快再到慢的加速度曲线因为机器匀速拖拽非常容易暴露。但说实话在评论采集这个场景下我并不建议投入太多精力去攻克滑块。更合理、更稳妥的做法是降低请求频率、随机化访问间隔、使用质量好的代理IP、避免在同一时间发起大量并发请求从源头降低触发验证的概率。如果确实触发了滑块就停下来让当前IP冷却一段时间而不是硬刚。4. 采集模块的完整实现4.1 代码结构总览项目源码的目录结构我建议这样组织清晰且易于扩展taobao_comment_spider/ ├── main.py # 主入口调度采集流程 ├── config.py # 配置文件存放商品ID、Cookie、请求头等 ├── sign.py # 签名生成模块逆向产物 ├── api_client.py # 请求封装含会话保持、重试机制 ├── parser.py # 评论数据解析 ├── storage.py # 数据存储支持CSV和SQLite └── logs/ # 日志目录这种结构的好处是把签名、请求、解析、存储拆开互相解耦。后续签名算法变了只改sign.py其他模块不用动换存储方式只改storage.py主流程完全不受影响。4.2 签名模块的实现基于逆向分析结果签名模块的代码大致长这样。这段代码是我根据常见逆向结果整理的一个模拟实现实际项目里的参数拼接顺序和密钥占位符必须替换成你自己逆向得到的结果import hashlib import time def generate_sign(params: dict, secret: str) - str: # 按参数名ASCII码排序拼接成 keyvaluekeyvalue 形式 sorted_keys sorted(params.keys()) raw_string .join(f{k}{params[k]} for k in sorted_keys) # 前后加密钥 raw_string secret raw_string secret # MD5签名 md5 hashlib.md5() md5.update(raw_string.encode(utf-8)) return md5.hexdigest() def build_params(item_id: str, page_number: int, page_size: int, app_key: str) - dict: params { itemId: item_id, pageSize: page_size, pageNumber: page_number, appKey: app_key, t: str(int(time.time() * 1000)), } # 这里secret是从JS逆向分析得到的密钥请替换为实际值 sign generate_sign(params, secretyour_secret_key) params[sign] sign return params这段代码的核心逻辑就是排序、拼接、加盐、哈希。因为签名对参数顺序敏感sorted_keys这一行非常重要先排序再拼接才能保证和JS端生成的结果一致。4.3 请求封装与会话保持请求层的设计要考虑几个实际问题Cookie的维持、请求头的模拟、超时和重试。我用requests的Session来维持会话模拟浏览器请求头并增加重试机制import requests import time from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry class ApiClient: def __init__(self, cookies: str): self.session requests.Session() self.session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://item.taobao.com/, Accept: application/json, text/plain, */*, Content-Type: application/x-www-form-urlencoded;charsetUTF-8, }) # 把浏览器里复制的Cookie字符串设置进会话 for cookie in cookies.split(;): if in cookie: k, v cookie.strip().split(, 1) self.session.cookies.set(k, v) # 重试策略 retry Retry(total3, backoff_factor1, status_forcelist[500, 502, 503, 504]) adapter HTTPAdapter(max_retriesretry) self.session.mount(https://, adapter) def fetch_comments(self, params: dict) - dict: url https://rate.taobao.com/xxxx # 替换为逆向得到的真实接口地址 try: resp self.session.get(url, paramsparams, timeout10) resp.raise_for_status() return resp.json() except requests.exceptions.RequestException as e: print(f请求失败: {e}) return {}Cookie从哪里来最简单的方式是自己在浏览器里登录淘宝随便打开一个商品页面在DevTools的Network面板里复制Cookie。用真实浏览器的Cookie去请求被风控识别的概率会低很多。这里还加了一个小细节请求头里的Referer指向商品页因为淘宝部分接口会校验来源。4.4 数据解析与清洗拿到接口JSON响应后解析的重点是把嵌套的评论列表提取出来转成扁平化的结构化数据。评论接口的JSON一般长这样外层是状态码和消息中间是data字段data里有comments列表每条评论包含rateContent、rateDate、auctionSku、displayUserNick、rateScore等字段有的还包含追评appendComment和卖家回复reply。解析代码可以做成一版通用工具核心思路是用递归方式遍历嵌套字典把目标字段路径告诉解析器它自动提取。但实际项目里直接硬编码字段名更快因为接口结构相对稳定def parse_comments(json_data: dict) - list: comments [] data json_data.get(data, {}) for item in data.get(comments, []): row { 商品ID: item.get(itemId), 评论内容: item.get(rateContent), 评论时间: item.get(rateDate), 评分: item.get(rateScore), 规格: item.get(auctionSku), 买家昵称: mask_nickname(item.get(displayUserNick, )), 追评内容: , } append_comment item.get(appendComment) if append_comment: row[追评内容] append_comment.get(content, ) comments.append(row) return comments def mask_nickname(nick: str) - str: # 对买家昵称做脱敏只保留首尾字符 if len(nick) 2: return * * len(nick) return nick[0] * * (len(nick) - 2) nick[-1]我在解析时特意加了昵称脱敏处理因为评论数据里的买家信息属于个人信息入库前做脱敏是基本的合规意识。字段名我也从中文字段转成了带有意义的中文键名方便非技术背景的人使用。4.5 多线程采集与限速策略评论接口是分页的一个商品的评论可能有几百上千页单线程跑起来太慢穿页还会超时所以要用多线程加速。但多线程不是无脑加线程数淘宝有风控短时间内大量请求很容易触发滑块反而更慢。我的经验是线程数控制在3到5个每个线程访问不同的页码线程之间用threading.Barrier或简单队列来同步。更关键的是每页请求之后要随机sleep间隔在1到3秒之间随机而不是固定值。固定间隔也是有规律的随机间隔能有效降低被识别为机器的概率import threading import random import time from queue import Queue def worker(worker_id, task_queue, api_client, results): while not task_queue.empty(): try: page_number task_queue.get_nowait() except QueueEmpty: break params build_params(item_id, page_number, page_size, app_key) json_data api_client.fetch_comments(params) rows parse_comments(json_data) results.extend(rows) print(f线程{worker_id} 完成第{page_number}页获取{len(rows)}条评论) time.sleep(random.uniform(1, 3)) task_queue.task_done()这个代码片段里results.extend(rows)在多线程下可能会产生竞态实际项目里建议给结果列表加锁或者用concurrent.futures.ThreadPoolExecutor的map返回值来规避。这里为了展示核心逻辑简化了并发安全处理生产环境要补上。4.6 数据落地CSV与SQLite采集到的数据最终要落盘。需求简单就存CSV用pandas一行代码导出方便Excel打开做初步分析。数据量大、需要查询筛选就存SQLitePython标准库自带sqlite3不需要额外安装服务。两种存储方式可以做成一个通用接口传入数据直接保存import csv import sqlite3 def save_to_csv(rows: list, filename: str): if not rows: return fieldnames list(rows[0].keys()) with open(filename, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnamesfieldnames) writer.writeheader() writer.writerows(rows) def save_to_sqlite(rows: list, db_path: str): conn sqlite3.connect(db_path) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_id TEXT, content TEXT, comment_time TEXT, score TEXT, sku TEXT, nickname TEXT, append_content TEXT ) ) for row in rows: cursor.execute( INSERT INTO comments (item_id, content, comment_time, score, sku, nickname, append_content) VALUES (?, ?, ?, ?, ?, ?, ?), (row[商品ID], row[评论内容], row[评论时间], row[评分], row[规格], row[买家昵称], row[追评内容]) ) conn.commit() conn.close()CSV文件用utf-8-sig编码是一个细节因为直接把带中文的数据用普通utf-8写进CSV用Excel打开会乱码。utf-8-sig带BOM头Excel才能正确识别。5. 常见问题与排查技巧实录5.1 高频报错速查表实际操作中你会遇到各种报错。我整理了一张高频问题对照表都是我或者身边朋友踩过的坑问题现象可能原因解决办法接口返回“参数错误”或非法请求签名生成错误重新比对sign拼接规则和密钥请求返回登录失效或跳转登录页Cookie过期重新在浏览器登录并更新Cookie出现滑块验证码请求频率过高或IP被标记降低频率、暂停一段时间、切换干净IP获取到的评论一直缺字段接口返回结构变化重新抓包分析响应JSON结构Node.js环境未找到pyexecjs缺少JS运行时安装Node.js并配置环境变量CSV打开乱码编码没用utf-8-sig改用encodingutf-8-sig这些报错里签名错误和Cookie过期占八成以上。签名错就回头抠JS细节Cookie过期就重新复制都很好排查。滑块验证是最烦的但也不是无解先缓一缓再继续通常过一段时间就恢复了。5.2 逆向过程中最容易踩的坑逆向签名这个环节有三个高频坑位我一一说明。第一个坑是忽略参数排序。不少签名算法要求参数按ASCII码升序拼接一些JS代码里用的是Object.keys(params).sort()你如果在Python里不排序就直接拼签出来的结果必然对不上。排查方法在JS端把raw_string打印出来在Python端也打印逐字符比对一眼就能看出差异。第二个坑是密钥藏得深。密钥字符串不会光明正大写在变量名里常见伪装包括分几段拼接、用atob解码、在数组里取下标、用String.fromCharCode生成。遇到这种情况别急着硬啃直接在浏览器Console里把可疑变量打出来看真实值是多少然后回到Python里硬编码或用相同逻辑生成。第三个坑是动态值多了一个。有些请求除了t之外还可能带上一个uuid或者sessionId每次会话或者每次请求都会变。很多人逆向时拿到一次请求的参数就固定了结果第二次请求就失败。排查思路是连续发送两次请求对比参数差异把变动的参数找出来再定位它的生成逻辑。这个做起来要多花点时间但也是最锻炼逆向能力的地方。5.3 稳定性与合规性建议最后说点实在的。爬虫项目的核心挑战不是写代码本身而是长期稳定运行。要想让采集任务跑得久、跑得稳我的建议是遵循几条基本原则。第一是控制频率。把请求间隔设置在合理范围宁慢勿快不要为了赶数据量把IP和账号都搭进去。第二是做好日志。每次请求的状态码、耗时、异常信息都记录下来出了问题能快速回溯而不是靠猜。第三是数据备份。采集结果分批次落盘不要把所有数据堆在内存里进程崩溃就全丢了。第四是我反复强调的合规意识。做技术研究、小范围数据采集本身是学习进步的过程但任何项目上线前都要评估法律风险遵守目标网站的robots协议和使用条款不采集敏感个人信息不批量爬取数据用于商业用途。这些红线碰不得一旦越界前面所有的技术积累都白搭。用这个项目跑通一遍下来你能掌握的东西其实远超“采集评论”本身。接口分析、签名逆向、反爬对抗、数据解析每一环都是爬虫领域最核心的通用技能。把这些技能沉淀下来换到其他电商平台或其他数据源套路都是一样的只是参数名和加密规则变了而已。这就是这类项目最大的价值。本文还有配套的精品资源点击获取