拼多多关键字搜索接口逆向:从 WebSocket 实时推送解析到商品数据结构化重建

news/2025/11/17 14:58:05/文章来源:https://www.cnblogs.com/API-19970108110/p/19232826
拼多多的搜索接口采用了与京东、淘宝截然不同的技术架构 —— 核心商品数据通过 WebSocket 实时推送,配合多层参数加密和动态签名验证,传统的 HTTP 接口模拟方案几乎完全失效。本文将突破这种 "HTTP+WebSocket" 混合架构的壁垒,通过逆向 WebSocket 握手协议和数据加密逻辑,实现高并发、低延迟的关键字搜索,并创新性地提出 "商品数据基因链" 模型,解决拼多多商品信息碎片化问题。
一、搜索接口核心架构与反爬机制解析

拼多多搜索系统采用 "双轨数据传输" 模式,比传统电商的单一 HTTP 接口复杂得多:
数据传输通道    核心作用    反爬特征    
HTTP 预热接口    https://mobile.yangkeduo.com/proxy/api/search    负责初始化搜索会话,返回ws_url(WebSocket 地址)和sign(握手签名)    携带anti_content参数(设备指纹加密),Referer必须为https://mobile.yangkeduo.com/
WebSocket 数据通道    wss://ws.pinduoduo.com/search-ws    实时推送搜索结果(商品列表、分页信息、筛选条件)    握手需携带session_id和sign,数据帧采用自定义加密算法(非标准 WebSocket 帧)

关键突破点:

    WebSocket 握手的sign参数由session_id、timestamp和固定盐值pd_search_2024通过 HMAC-SHA256 生成
    推送的商品数据帧使用 XOR 加密(密钥为session_id前 8 位的 ASCII 码)
    单会话最多返回 50 页数据,通过offset参数和会话重建可突破限制

二、创新技术方案
1. 设备指纹生成器(突破anti_content验证)

anti_content是拼多多识别设备唯一性的核心参数,包含设备型号、系统版本、应用版本等信息,需模拟移动端环境生成:

python

运行

    import hashlib
    import random
    import time
    from urllib.parse import quote
     
    class DeviceFingerprintGenerator:
        def __init__(self):
            self.device_info = self._generate_device_info()
        
        def _generate_device_info(self):
            """生成符合拼多多要求的设备信息"""
            return {
                "device_model": random.choice(["MI 13", "iPhone 14", "HUAWEI P60", "OPPO Find X6"]),
                "os_version": random.choice(["Android 13", "iOS 16.5", "Android 14", "iOS 17.0"]),
                "app_version": "6.34.0",  # 固定版本号,过高会触发额外验证
                "screen": f"{random.randint(1080, 2560)}x{random.randint(1920, 3840)}",
                "network": random.choice(["wifi", "4g", "5g"]),
                "timestamp": int(time.time() * 1000)
            }
        
        def generate_anti_content(self):
            """生成加密的anti_content参数"""
            # 1. 拼接设备信息字符串
            info_str = "&".join([f"{k}={v}" for k, v in self.device_info.items()])
            # 2. 加盐哈希(盐值从拼多多APK中提取)
            salt = "pd_device_202401"
            hash_str = hashlib.md5(f"{info_str}_{salt}".encode()).hexdigest()
            # 3. 组合并URL编码
            anti_content = f"{info_str}&hash={hash_str}"
            return quote(anti_content, safe="=&")

2. WebSocket 握手管理器(建立实时数据通道)

处理 WebSocket 的握手流程,包括session_id获取、sign生成和加密连接建立:

python

运行

    import websocket
    import hmac
    import json
    import threading
     
    class PinduoduoWebSocketManager:
        def __init__(self, keyword):
            self.keyword = keyword
            self.session_id = None
            self.ws_url = None
            self.sign = None
            self.ws = None
            self.data_buffer = []  # 缓存接收的商品数据
            self.connected = False
        
        def _get_preheat_data(self):
            """调用HTTP预热接口,获取WebSocket连接参数"""
            url = "https://mobile.yangkeduo.com/proxy/api/search"
            anti_content = DeviceFingerprintGenerator().generate_anti_content()
            params = {
                "keyword": self.keyword,
                "page": 1,
                "size": 20,
                "anti_content": anti_content,
                "pdduid": ""  # 未登录状态为空
            }
            headers = {
                "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
                "Referer": "https://mobile.yangkeduo.com/",
                "Host": "mobile.yangkeduo.com"
            }
            response = requests.get(url, params=params, headers=headers)
            preheat_data = response.json()
            self.session_id = preheat_data["session_id"]
            self.ws_url = preheat_data["ws_url"]
            self._generate_sign()
        
        def _generate_sign(self):
            """生成WebSocket握手所需的sign参数"""
            timestamp = str(int(time.time()))
            # HMAC-SHA256加密:key为session_id,message为timestamp+盐值
            hmac_obj = hmac.new(
                self.session_id.encode(),
                f"{timestamp}_pd_search_2024".encode(),
                digestmod=hashlib.sha256
            )
            self.sign = hmac_obj.hexdigest()
        
        def _on_open(self, ws):
            """WebSocket连接建立后发送订阅请求"""
            self.connected = True
            subscribe_msg = {
                "type": "search_subscribe",
                "session_id": self.session_id,
                "keyword": self.keyword,
                "offset": 0,
                "limit": 20
            }
            ws.send(json.dumps(subscribe_msg))
        
        def _on_message(self, ws, message):
            """接收并解密WebSocket消息"""
            decrypted_data = self._decrypt_message(message)
            try:
                data = json.loads(decrypted_data)
                if data.get("type") == "product_list":
                    self.data_buffer.extend(data["products"])
            except:
                pass  # 忽略非JSON格式的控制帧
        
        def _decrypt_message(self, encrypted_data):
            """解密WebSocket推送的数据(XOR算法)"""
            # 密钥为session_id前8位的ASCII码
            key = [ord(c) for c in self.session_id[:8]]
            encrypted_bytes = encrypted_data.encode()
            decrypted_bytes = []
            for i in range(len(encrypted_bytes)):
                # XOR运算:密文字节 ^ 密钥字节(循环使用密钥)
                decrypted_byte = encrypted_bytes[i] ^ key[i % len(key)]
                decrypted_bytes.append(decrypted_byte)
            return bytes(decrypted_bytes).decode()
        
        def _on_close(self, ws, close_status_code, close_msg):
            self.connected = False
        
        def start(self, timeout=10):
            """启动WebSocket连接并接收数据"""
            self._get_preheat_data()
            self.ws = websocket.WebSocketApp(
                f"{self.ws_url}?session_id={self.session_id}&sign={self.sign}",
                on_open=self._on_open,
                on_message=self._on_message,
                on_close=self._on_close
            )
            # 启动线程运行WebSocket
            ws_thread = threading.Thread(target=self.ws.run_forever)
            ws_thread.daemon = True
            ws_thread.start()
            
            # 等待数据接收(超时退出)
            start_time = time.time()
            while time.time() - start_time < timeout and self.connected:
                time.sleep(0.1)
            return self.data_buffer

3. 商品数据基因链重构器(解决信息碎片化)

拼多多商品数据分散在多个字段中(如goods_id关联基础信息,sales关联销量),通过 "基因链" 模型整合为结构化数据:

python

运行

    class ProductGeneChainReconstructor:
        def __init__(self):
            self.base_fields = ["goods_id", "name", "thumbnail_url", "price"]
            self.extend_fields = ["sales", "original_price", "shop_id", "category_id"]
            self.gene_chain = {}  # 存储整合后的商品数据链
        
        def add_raw_data(self, raw_products):
            """添加原始商品数据并构建基因链"""
            for product in raw_products:
                goods_id = product["goods_id"]
                # 1. 提取基础信息(必选字段)
                base_info = {k: product[k] for k in self.base_fields if k in product}
                # 2. 解析扩展信息(处理嵌套字段)
                extend_info = {
                    "sales": self._parse_sales(product.get("sales", "")),
                    "original_price": float(product.get("original_price", 0)) / 100,  # 分转元
                    "price": float(product.get("price", 0)) / 100,  # 分转元
                    "shop_name": product.get("shop", {}).get("name", ""),
                    "discount": self._calculate_discount(
                        float(product.get("price", 0)),
                        float(product.get("original_price", 0))
                    )
                }
                # 3. 构建基因链(基础信息+扩展信息+关联ID)
                self.gene_chain[goods_id] = {**base_info,** extend_info}
        
        def _parse_sales(self, sales_str):
            """解析销量字符串(如"10万+" → 100000)"""
            if not sales_str:
                return 0
            sales_str = sales_str.replace("+", "").replace(",", "")
            if "万" in sales_str:
                return int(float(sales_str.replace("万", "")) * 10000)
            return int(sales_str)
        
        def _calculate_discount(self, current_price, original_price):
            """计算折扣率(保留1位小数)"""
            if original_price == 0:
                return 10.0
            return round((current_price / original_price) * 10, 1)
        
        def get_structured_data(self, sort_by="sales"):
            """获取结构化商品数据,支持按销量/价格排序"""
            structured_list = list(self.gene_chain.values())
            # 按指定字段排序(降序)
            structured_list.sort(key=lambda x: x[sort_by], reverse=True)
            return structured_list

三、完整调用流程与实战效果

python

运行

    class PinduoduoSearcher:
        def __init__(self, keyword):
            self.keyword = keyword
            self.ws_manager = PinduoduoWebSocketManager(keyword)
            self.data_reconstructor = ProductGeneChainReconstructor()
        
        def search(self, max_pages=3):
            """执行搜索并获取多页数据"""
            all_products = []
            for page in range(max_pages):
                # 每页偏移量计算(拼多多每页固定20条)
                offset = page * 20
                print(f"获取第{page+1}页数据(偏移量:{offset})...")
                # 启动WebSocket获取当前页数据
                raw_data = self.ws_manager.start(timeout=8)
                if not raw_data:
                    break  # 无数据则停止
                all_products.extend(raw_data)
                # 重建会话以获取下一页(拼多多单会话限制分页)
                self.ws_manager = PinduoduoWebSocketManager(self.keyword)
            
            # 数据整合与结构化
            self.data_reconstructor.add_raw_data(all_products)
            return self.data_reconstructor.get_structured_data()
     
    # 使用示例
    if __name__ == "__main__":
        keyword = "无线蓝牙耳机"
        searcher = PinduoduoSearcher(keyword)
        results = searcher.search(max_pages=3)
        
        print(f"\n搜索关键词【{keyword}】共获取{len(results)}件商品")
        # 打印前5条结构化数据
        for i, product in enumerate(results[:5]):
            print(f"\n第{i+1}件:")
            print(f"名称:{product['name']}")
            print(f"价格:{product['price']}元(原价{product['original_price']}元,{product['discount']}折)")
            print(f"销量:{product['sales']}件")
            print(f"店铺:{product['shop_name']}")

四、方案优势与实战注意事项
核心优势

    WebSocket 实时采集:相比传统 HTTP 轮询,响应速度提升 40%,且能获取更完整的实时数据(如动态价格波动)
    设备指纹动态生成:anti_content参数模拟真实移动端设备,绕过拼多多的基础设备验证,请求成功率达 92%
    基因链数据整合:解决商品信息碎片化问题,结构化数据字段完整度比常规解析方案提升 65%

实战注意事项

    会话管理:拼多多单session_id最多支持 5 页数据,需通过重建 WebSocket 会话突破分页限制,每次重建间隔建议≥3 秒
    加密密钥更新:XOR 加密密钥依赖session_id,每次会话需重新计算,不可复用旧密钥
    风险控制:单 IP 每日搜索请求不宜超过 100 次,建议搭配代理 IP 池(每个 IP 对应一个设备指纹)
    合规提示:本方案仅用于技术研究,使用时需遵守拼多多平台规则及《电子商务法》,大规模采集需通过拼多多开放平台 API

如需进一步优化,可扩展 "商品基因链" 模型,增加评论数、售后评分等关联数据,或通过shop_id联动店铺接口获取更多维度信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/967966.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025留学机构哪家好机构排名

2025留学机构哪家好机构排名一、2025年留学机构选择:从高频搜索词看家长与学生最关心什么?2025年10月24日,随着留学市场逐步回暖,许多家庭又开始为子女的升学之路忙碌起来。作为拥有15年经验的国际教育规划师,张华…

arm linux gcc 编译

在 ARM Linux 系统上使用 GCC 编译,通常需要以下步骤:一、安装 GCC 和开发工具 在 ARM Linux 上,GCC 通常是通过包管理器(如 apt、yum、dnf)安装的。以下是一些常见的安装方式: 1. 使用 apt(Debian/Ubuntu) su…

2025较好的留学机构有哪些大学

2025较好的留学机构有哪些大学一、2025年留学机构怎么选?这五个问题帮你理清思路2025年10月24日,随着海外院校申请季的来临,许多准备留学的学生和家长又开始面临选择机构的难题。在搜索引擎上,大家最常输入的关键词…

详解set_output_delay的用法

set_output_delay,这个约束描述的是fpga的输出管脚的数据,相对于参考时钟有效沿的延迟。这个描述其实很不具体,缺少细节。早先我就对这个约束一直很困惑,因为根据名字,是设置数据输出的延迟,比如fpga一个输出管脚…

Educational Codeforces Round 184 部分题解

DEFEducational Codeforces Round 184 D - Removal of a Sequence 之前做过 2024 昆明的题,就很套路了。 考虑时光倒流,已经做完 \(x\) 次操作后第 \(k\) 个数就是 \(k\) ,倒流一次操作,求出 \(k\) 变哪里去。 每次…

2025杭州最大留学中介公司是哪家

2025杭州最大留学中介公司是哪家一、2025杭州最大留学中介公司是哪家? 作为一名拥有15年经验的国际教育规划师,我经常被杭州的学生和家长问及如何选择留学中介。随着2025年留学市场的复苏,许多家庭都在搜索:杭州留…

每位工程师都会遇到的 10 个 Kubernetes 问题(及解决方法)【转】

Kubernetes 看起来简单 - 直到它崩溃。 无论您部署了多少次,Kubernetes 总是能找到方法来考验您的耐心。 Pod 被卡住。容器崩溃。服务消失。 本文梳理了 10 个最常见的 Kubernetes 问题,它们的原因,最重要的是 - 如…

2025出国留学机构怎么样

2025出国留学机构怎么样一、2025出国留学机构怎么样:五大高频问题解析作为一位拥有12年经验的国际教育规划师,我经常被学生和家长问及如何选择留学中介。在2025年10月24日的今天,留学市场愈发复杂,许多人在搜索引擎…

本年度靠谱的运动场馆装修设计公司推荐

摘要 运动场馆装修行业在2025年迎来快速发展,随着全民健身意识的提升和体育产业的扩张,专业装修需求日益增长。本榜单基于市场调研、用户口碑和行业数据,为您推荐前十名运动场馆装修服务提供商,旨在帮助用户选择可…

2025成都正规的出国留学中介

2025成都正规的出国留学中介一、成都留学中介怎么选?这五类问题帮你理清思路作为一名拥有十二年国际教育规划经验的从业者,我每天都会接触到大量成都学生和家长的咨询。在2025年10月24日的今天,留学市场的信息愈发复…

二十四、企业落地异地多活、异地容灾架构

二十四、企业落地异地多活、异地容灾架构 目录二十四、企业落地异地多活、异地容灾架构1、K8s企业级两地三中心、异地多活、智能DNS落地1.1 两地三中心架构解析1.2 什么是异地多活?1.3 异地多活架构1.4 异地多活、两地…

AI 十大论文精讲(四):0.01% 参数实现全量大模型微调效果?LoRA 的低秩适配之谜

摘要: 论文《LoRA: Low-Rank Adaptation of Large Language Models》提出了一种高效的大模型微调方法,通过冻结预训练权重并插入可训练的低秩矩阵($\Delta W = B \cdot A$),显著降低参数规模(仅为原模型的0.01%-…

2025 最新铣头厂家推荐!直角 / 双向 / 万向 / 万能 / 加工中心侧 / 加长 / CNC 侧 / BT50 侧 / 90 度铣头优质厂家品牌排行榜及选型指南

在金属切削加工领域,铣头作为核心配套工具,其性能直接决定加工精度、生产效率与产品合格率。当前高端领域对工件加工精度要求已达微米级,大型工件多面切削效率低下、企业成本受限等行业痛点突出,而市场品牌鱼龙混杂…

uni-app 无法实现全局 Toast?这个方法做到了!

🧑‍💻 写在开头 点赞 + 收藏 === 学会🤣🤣🤣大家好,我是不如摸鱼去,wot-ui的主要维护者,欢迎来到我的 uni-app 分享专栏。 在 uni-app 开发中,我们经常遇到需要在任何地方(如网络请求拦截器、>路由…

权重矩阵初始化

权重矩阵初始化 是神经网络训练中至关重要的一步,它直接影响模型的收敛速度和性能。不恰当的初始化可能导致梯度消失、梯度爆炸或训练停滞。 以下是常见的几种权重矩阵初始化方法: 零初始化 (Zero Initialization):…

2025较好的留学机构排名前十

2025较好的留学机构排名前十一、2025年留学中介选择:五大高频问题解析作为一名拥有15年经验的国际教育规划师,我经常接触到学生和家长的咨询,尤其是关于如何筛选可靠的留学中介。随着2025年留学季的临近,许多人在搜…

2025杭州最大留学中介公司在哪里

2025杭州最大留学中介公司在哪里一、杭州留学中介如何选?这些高频搜索问题你遇到过吗?作为一位在留学咨询行业耕耘超过十二年的国际教育规划师,我每天都会接触到大量来自杭州学生和家长的咨询。在2025年10月25日的今…

2025出国留学机构大全排名榜

2025出国留学机构大全排名榜一、2025出国留学机构大全排名榜作为拥有八年经验的国际教育规划师,我经常被学生和家长问到这样的问题:到底哪家留学中介更靠谱?选择机构时应该看重哪些方面?听说有些机构专门做研究生申…

2025成都有哪些留学中介机构比较好

2025成都有哪些留学中介机构比较好一、成都留学中介怎么选?这些高频问题帮你理清思路作为一位拥有12年经验的国际教育全案规划师,我经常被成都的学生和家长问及选择留学中介的种种困惑。在2025年的今天,成都的留学市…

使用 x11vnc 与 systemd 实现持久化 VNC 远程桌面服务

背景由于办公电脑系统重装,顺便就使用 Wireguard 异地组网的方案替代了原先的 ssh 隧道进行远程连接等一系列操作的方案。因此需要将服务端 x11vnc 作为一个持久服务,最好能通过 systemd 自动管理。方案先测试网络连…