拼多多数据抓取:Python 爬虫中的 JS 逆向基础案例分析

一、拼多多反爬虫机制与 JS 逆向的必要性

拼多多的前端页面数据加载并非传统的服务端渲染,而是大量采用异步请求(AJAX)加载数据。这些异步请求的参数(如<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font><font style="color:rgba(0, 0, 0, 0.85) !important;">token</font>等)往往经过 JavaScript 加密处理,直接通过 Python 的<font style="color:rgba(0, 0, 0, 0.85) !important;">requests</font>库发送请求,会因参数无效被服务器拒绝。

例如,当我们在拼多多搜索 "手机" 时,浏览器的网络请求中会出现一个获取商品列表的接口,其请求参数包含一串加密的<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>值。这个<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>值是由前端 JS 根据请求参数、时间戳、固定密钥等信息计算得出的。如果无法还原这个加密过程(即 JS 逆向),就无法构造有效的请求参数,自然无法获取数据。

JS 逆向的本质,是通过分析前端 JavaScript 代码,还原其数据加密、参数生成的逻辑,再将该逻辑用 Python 或其他语言复现,从而构造出符合服务器要求的请求。对于拼多多这类平台,入门级的 JS 逆向主要聚焦于参数加密逻辑的还原,这也是本文的核心内容。

二、JS 逆向的基础步骤(以拼多多商品接口为例)

步骤 1:抓包分析请求参数

首先需要使用浏览器的开发者工具(Chrome/Firefox 的 F12)抓取目标接口的请求信息。以拼多多网页版商品列表接口为例:

  1. 打开拼多多网页版,搜索 "手机";
  2. 打开开发者工具的「Network」标签,筛选「XHR/Fetch」类型的请求;
  3. 找到商品列表对应的接口(如<font style="color:rgb(0, 0, 0);">/api/search/get</font>),查看其请求参数响应数据

此时会发现,请求参数中包含<font style="color:rgba(0, 0, 0, 0.85) !important;">page</font>(页码)、<font style="color:rgba(0, 0, 0, 0.85) !important;">keyword</font>(关键词)、<font style="color:rgba(0, 0, 0, 0.85) !important;">timestamp</font>(时间戳)、<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>(签名)等参数,其中<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>是加密后的字符串,也是我们需要逆向的核心。

步骤 2:定位加密 JS 代码

找到<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>参数的生成逻辑,是 JS 逆向的关键。常用方法有两种:

  1. 全局搜索 :在开发者工具的「Sources」标签中,使用快捷键<font style="color:rgb(0, 0, 0);">Ctrl+Shift+F</font>搜索<font style="color:rgb(0, 0, 0);">sign</font><font style="color:rgb(0, 0, 0);">sign=</font>,定位到包含该参数生成的 JS 代码段;
  2. 断点调试 :在请求发起的代码处设置断点,逐步执行代码,观察<font style="color:rgb(0, 0, 0);">sign</font>参数的生成过程。

拼多多的前端代码经过了压缩混淆,但入门级的加密逻辑往往不会过于复杂。我们可以通过观察代码中的加密函数(如 MD5、SHA256 等哈希函数,或自定义的拼接加密),确定<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>的生成规则。

步骤 3:还原加密逻辑

找到加密代码后,需要理解其逻辑并记录关键信息:

  • 加密所使用的算法(如 MD5);
  • 参与加密的参数顺序(如<font style="color:rgb(0, 0, 0);">timestamp+keyword+page+密钥</font>);
  • 固定密钥(可能是硬编码在 JS 中的字符串,如<font style="color:rgb(0, 0, 0);">pdd_123456</font>)。

例如,假设拼多多某接口的<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>生成逻辑为:将<font style="color:rgba(0, 0, 0, 0.85) !important;">timestamp</font><font style="color:rgba(0, 0, 0, 0.85) !important;">keyword</font><font style="color:rgba(0, 0, 0, 0.85) !important;">page</font>和固定密钥<font style="color:rgba(0, 0, 0, 0.85) !important;">pdd_secret</font>按顺序拼接,再进行 MD5 加密得到小写字符串。我们需要将这一逻辑准确还原。

步骤 4:Python 复现加密逻辑

将还原的 JS 加密逻辑用 Python 代码实现,生成对应的<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>参数,再构造 HTTP 请求获取数据。

三、代码实现:拼多多商品数据抓取的 JS 逆向案例

前置说明

本文案例中的接口和加密逻辑为拼多多入门级模拟场景(因拼多多真实加密逻辑会持续更新,且涉及平台合规性,此处采用简化的模拟逻辑),核心是演示 JS 逆向的流程。实际场景中,需结合具体抓包结果调整逻辑。

步骤 1:抓包与 JS 加密逻辑分析(模拟)

假设抓包得到的请求参数为:

json

json 复制代码
{
  "keyword": "手机",
  "page": 1,
  "timestamp": 1718000000000,
  "sign": "a1b2c3d4e5f67890abcdef1234567890"
}

通过全局搜索和断点调试,找到 JS 加密代码如下(压缩后的简化版):

javascript

运行

javascript 复制代码
function generateSign(params, secret) {
  // 1. 按参数名升序排序
  let sortedKeys = Object.keys(params).sort();
  let str = '';
  // 2. 拼接参数名和值
  for (let key of sortedKeys) {
    str += key + params[key];
  }
  // 3. 拼接固定密钥
  str += secret;
  // 4. MD5加密并转小写
  return md5(str).toLowerCase();
}
// 调用示例:
let params = {
  keyword: "手机",
  page: 1,
  timestamp: 1718000000000
};
let secret = "pdd_2024_secret"; // 固定密钥
let sign = generateSign(params, secret);

这段代码的逻辑是:将请求参数按名升序排序,拼接参数名和值,再拼接固定密钥,最后 MD5 加密得到<font style="color:rgba(0, 0, 0, 0.85) !important;">sign</font>

步骤 2:Python 复现加密逻辑

首先安装所需依赖:

然后编写 Python 代码,实现参数拼接、MD5 加密,并构造请求:

python

python 复制代码
import requests
import hashlib
import time

def generate_sign(params, secret):
    """
    复现JS的sign生成逻辑
    :param params: 请求参数字典
    :param secret: 固定密钥
    :return: 加密后的sign
    """
    # 1. 按参数名升序排序
    sorted_keys = sorted(params.keys())
    str_temp = ''
    # 2. 拼接参数名和值
    for key in sorted_keys:
        str_temp += key + str(params[key])
    # 3. 拼接固定密钥
    str_temp += secret
    # 4. MD5加密并转小写
    md5_obj = hashlib.md5()
    md5_obj.update(str_temp.encode('utf-8'))
    sign = md5_obj.hexdigest().lower()
    return sign

def get_pdd_goods(keyword, page):
    """
    获取拼多多商品数据
    :param keyword: 搜索关键词
    :param page: 页码
    :return: 商品数据
    """
    # 固定配置
    url = "https://api.pinduoduo.com/api/search/get"  # 模拟接口,实际需替换为真实接口
    secret = "pdd_2024_secret"  # 从JS中提取的固定密钥
    # 构造基础参数
    timestamp = int(time.time() * 1000)  # 生成当前时间戳(毫秒)
    params = {
        "keyword": keyword,
        "page": page,
        "timestamp": timestamp
    }
    # 生成sign参数
    sign = generate_sign(params, secret)
    params["sign"] = sign  # 将sign加入参数

    # 发送请求
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        "Referer": "https://www.pinduoduo.com/",
        "Cookie": ""  # 实际场景中需添加抓包得到的Cookie
    }

    # 配置代理信息
    proxyHost = "www.16yun.cn"
    proxyPort = "5445"
    proxyUser = "16QMSOML"
    proxyPass = "280651"
    # 构建代理URL(支持HTTP和HTTPS)
    proxy_url = f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"
    proxies = {
        "http": proxy_url,
        "https": proxy_url
    }

    try:
        # 发送请求时添加proxies参数
        response = requests.get(url, params=params, headers=headers, proxies=proxies)
        if response.status_code == 200:
            return response.json()
        else:
            print(f"请求失败,状态码:{response.status_code}")
            return None
    except Exception as e:
        print(f"请求异常:{e}")
        return None

# 主函数调用
if __name__ == "__main__":
    goods_data = get_pdd_goods("手机", 1)
    if goods_data:
        print("获取的商品数据:")
        print(goods_data)
    else:
        print("未获取到商品数据")

代码说明

  1. generate_sign 函数:完全复现了 JS 中的加密逻辑,包括参数排序、拼接、MD5 加密;
  2. get_pdd_goods 函数 :构造请求参数,生成<font style="color:rgb(0, 0, 0);">sign</font>,发送 HTTP 请求并返回数据;
  3. 注意事项 :实际场景中,<font style="color:rgb(0, 0, 0);">url</font>需要替换为抓包得到的真实接口,<font style="color:rgb(0, 0, 0);">Cookie</font>需要添加浏览器中的有效 Cookie,<font style="color:rgb(0, 0, 0);">secret</font>需要从真实 JS 代码中提取。

四、JS 逆向的进阶与合规性说明

1. 进阶挑战

拼多多的真实 JS 代码会采用代码混淆 (如变量名混淆、控制流平坦化)、动态密钥 (密钥从服务器获取,而非硬编码)、浏览器指纹验证(如验证 User-Agent、Canvas 指纹)等手段,增加逆向难度。此时需要掌握:

  • 使用<font style="color:rgb(0, 0, 0);">ast</font>模块解析混淆后的 JS 代码;
  • 使用<font style="color:rgb(0, 0, 0);">execjs</font>库直接执行 JS 代码(避免手动复现);
  • 模拟浏览器环境(如使用 Selenium、Playwright)绕过指纹验证。

2. 合规性重要提醒

本文的案例仅用于技术学习,抓取拼多多数据需遵守平台的《用户协议》和《robots.txt》规则,不得用于商业用途或恶意攻击。根据《中华人民共和国网络安全法》和《反不正当竞争法》,未经授权的大规模数据抓取可能涉嫌违法违规。

五、总结

本文以拼多多数据抓取为例,讲解了 Python 爬虫中 JS 逆向的基础流程:抓包分析参数→定位加密 JS 代码→还原加密逻辑→Python 代码复现。对于入门者而言,核心是理解 JS 逆向的本质是逻辑还原,而非单纯的代码编写。

在实际应用中,JS 逆向的难度会随着平台反爬虫技术的升级而增加,但基础思路始终不变。同时,必须牢记合规性原则,将技术用于合法的场景中。通过本文的案例,希望能帮助入门者迈出 JS 逆向的第一步,为后续的爬虫开发和数据分析工作打下基础。

相关推荐
superman超哥3 小时前
仓颉语言中基本数据类型的深度剖析与工程实践
c语言·开发语言·python·算法·仓颉
Liu.7743 小时前
vue3使用vue3-print-nb打印
前端·javascript·vue.js
不爱吃糖的程序媛4 小时前
Ascend C开发工具包(asc-devkit)技术解读
c语言·开发语言
bu_shuo4 小时前
MATLAB奔溃记录
开发语言·matlab
Learner__Q4 小时前
每天五分钟:滑动窗口-LeetCode高频题解析_day3
python·算法·leetcode
————A4 小时前
强化学习----->轨迹、回报、折扣因子和回合
人工智能·python
你的冰西瓜4 小时前
C++标准模板库(STL)全面解析
开发语言·c++·stl
dly_blog4 小时前
Vue 逻辑复用的多种方案对比!
前端·javascript·vue.js
徐先生 @_@|||4 小时前
(Wheel 格式) Python 的标准分发格式的生成规则规范
开发语言·python
利剑 -~5 小时前
jdk源码解析
java·开发语言