
你有没有想过别人聊竞品价格、做选品调研、监控市场行情的时候数据都是从哪来的有很大一部分就是靠爬虫从电商平台公开页面上抓下来的。拼多多这两年的体量摆在那里商品数据恰好是做市场分析、竞品监控、甚至选品决策里非常关键的一环。加上Python这门语言做这类事情确实顺手所以拿它来爬拼多多商品数据算是很典型的入门到进阶的实战项目。这篇教程不会跟你扯太玄乎的原理直接做一件事教你从分析请求、生成关键参数、写代码、到最终把数据落成CSV文件完整走通一条抓取拼多多商品列表数据的链路。源码我会贴出来执行逻辑和参数怎么来的也会拆开讲清楚保证你看完能自己跑起来并且知道每一步为什么要这么做。这个项目比较适合已经会一点Python基础语法、想拿真实网站练手的朋友也适合做电商运营、市场分析需要批量拉数据辅助决策的人。如果你只是纯小白我也会在环境准备部分留足说明照着一步步装环境就行。1. 项目整体思路与抓取难点拆解爬电商网站我一直觉得最忌讳的就是上来直接写代码。你得先搞清楚数据是从哪来的页面是怎么渲染的再决定用哪套方案。很多人一听到“爬拼多多”就头疼其实难点从来不是Python本身而是你还没摸清对方的接口规律。1.1 页面渲染方式决定技术选型拼多多商品列表页是典型的接口动态渲染你在浏览器里看到的商品卡片、标题、价格、销量这些信息并不是服务端直接输出的静态HTML而是页面加载时通过JS去请求后端接口拿到JSON数据以后动态生成的。这就带来一个技术选型问题直接用requests抓HTML再解析大概率拿不到商品数据因为HTML骨架里根本没有内容。用selenium或Playwright模拟浏览器可以拿到渲染后的完整页面但速度慢、资源占用高还被检测的风险更高。最合理的思路是逆向分析出商品列表接口的请求规律直接用requests模拟请求那个接口拿到的就是干干净净的JSON解析起来不要太爽。我选的当然是第三种。后面会详细说怎么抓接口、怎么处理拼多多特有的anti-content参数。1.2 核心难点拼多多的anti-content参数如果说这整个项目里有一个门槛那就是这个名为anti-content的请求参数。它是拼多多服务端用来做签名校验和反爬验证的一串密文由前端JS根据固定的参数拼接规则动态生成。换句话说如果你拿着普通请求头直接请求商品接口服务端一验参数发现anti-content对不上或者压根没有那返回给你的就是错误信息啥数据都拿不到。这里的应对方案有两种自己用Python重写它前端的加密逻辑纯本地生成anti-content。借助一个叫DrissionPage的库用浏览器内核自动执行前端JS把生成好的anti-content拿过来用。方案1的问题在于拼多多的加密逻辑会不定期更新一旦变了你的重写代码就废了。方案2省心很多实际跑起来也稳定不少。我这套教程里用的是方案2逻辑上更通用哪怕后续参数规则有小变动只要JS逻辑还在基本都能跟着适应。1.3 整体数据流向把整个项目的执行链路画出来其实就是这么一条线浏览器访问拼多多搜索页并完成登录拿到有效Cookie和页面环境用DrissionPage在页面里执行JS提前准备好anti-content参数Python脚本带着Cookie和anti-content请求商品列表接口接口返回JSON从中提取商品标题、价格、销量、店铺名等字段将结果清洗整理后写入CSV文件完成数据落地。这五步看着简单但每一步都有细节。接下来我从环境准备开始一步步带你操作。2. 环境准备与前置工具清单工欲善其事必先利其器。这套教程里用到的工具不多但每个都有它存在的理由我一个个说清楚。2.1 你需要安装的Python库先假设你已经装好了Python 3.8及以上版本。如果还没装去Python官网下载安装包安装时记得勾选Add Python to PATH这个选项不勾后面在命令行里敲python会提示找不到命令。依赖库有三个核心的requests用来发送HTTP请求调拼多多的商品接口。这个库是Python爬虫的标配安装命令是pip install requests。DrissionPage这个库比较特殊它的定位是“像selenium一样控制浏览器但又比selenium更轻量”并且能在页面环境里执行JS获取加密参数。安装命令是pip install DrissionPage。pandas不是必须但用来处理和导出CSV非常方便省得自己循环写文件。安装命令是pip install pandas。这三个库一小时之内就能装完没什么坑。唯一要注意的是DrissionPage对浏览器版本有要求建议用最新版Chrome这样它自动接管浏览器的成功率最高。2.2 抓包工具直接用Chrome开发者工具有人习惯用Fiddler或Charles但抓拼多多的接口我觉得Chrome自带的DevTools就够用了没必要再引入额外工具。打开Chrome按F12进入开发者工具切到Network面板勾选Preserve log保留日志。然后在拼多多网站上随便搜索一个词比如“手机”滚动一下商品列表你会看到Network面板里出现大量请求。我们需要找的是那个返回商品列表JSON数据的接口名字通常是SearchViewModel或类似的关键词。找到接口以后点进去看Request Headers和Payload就能看到它的完整请求参数结构。这个步骤是整个项目的源头代码里所有参数都是从这里来的。2.3 浏览器环境要求与登录必要性爬拼多多商品接口强烈建议在浏览器里保持登录状态。不登录也能跑通一些接口但数据完整度和请求成功率会明显下降尤其翻页多了以后很容易被服务端识别为异常流量。DrissionPage这个库有一种工作模式可以直接接管你本机已经打开的Chrome这样你浏览器里已有的登录态就能直接复用不需要在代码里处理登录逻辑。这算是一个很省事的小技巧。3. 核心环节商品列表接口分析与anti-content生成这章节是整个教程的心脏。很多人爬拼多多失败就失败在这一步上面要么找不到正确接口要么不知道anti-content怎么处理。我详细展开讲。3.1 找到商品列表的真实请求接口搜索一个商品关键词后浏览器里会发出很多请求但真正包含商品数据的其实就是一两个。我常用的定位方法有两种都很直接第一种在Network面板里按Fetch/XHR筛选然后逐个点击请求看Response直到看到里面有goods_name、price_info或者sales_tip这样的字段那基本就是商品列表接口了。第二种如果你的DevTools开着直接在Network面板的搜索框里输入一个商品标题里可能出现的词语能搜到包含这个词语的请求逐个排除后也能锁定接口。拼多多的商品列表接口通常是POST请求地址是https://apiv2.pinduoduo.com/api/... 这一类不是网页地址。请求的Payload里会包含关键搜索词、翻页偏移量、排序方式以及那个重量级的anti-content参数。3.2 请求参数的结构分析我在实际操作中看到接口Payload里的参数大致是这种结构pdduuid和用户匿名身份绑定的ID浏览器里会自动带。search_met包含搜索来源信息比如是从搜索框还是推荐位进来的。list_id当前搜索列表的标识符。sort_type排序方式0代表综合1代表销量2代表价格。offset翻页偏移量第一页是0第二页是30一页通常30条。flair一个JSON字符串里面有若干分类筛选的条件。anti_content最重要的反爬签名参数不长成固定格式每次请求都不同。这些参数里有一部分是浏览器自动携带的固定值可以直接复用有一部分跟当前搜索关键词相关需要动态拼接还有一部分是安全校验用的也就是anti_content。我们在代码里要做的就是把固定参数写成字典把动态参数在循环里更新最后加上从JS环境拿到的anti_content。3.3 anti-content的生成逻辑与DrissionPage解法为什么把anti-content单独拿出来讲因为它真的是决定生死的一步。先说它是怎么来的。拼多多的前端脚本会采集当前请求的若干信息比如请求路径、时间戳、部分请求体参数按固定顺序拼接成一个待签名字符串然后经过加密算法生成最终密文。这个过程是在浏览器环境里完成的直接拿Python来模拟也可以但平台一更新算法你就得跟着改维护成本很高。我的做法是用DrissionPage开一个浏览器页面先访问拼多多的搜索页然后在浏览器环境里直接执行一段JS脚本复用前端自己的加密逻辑来生成anti-content。这等于你让拼多多自己的代码帮你干了这个活生成出来的参数当然是通过校验的。简洁来说效果等同于浏览器帮我们跑了一遍加密流程Python只需要把结果拿来用。这个思路对于处理很多电商网站的加密参数都通用不局限在拼多多一个平台上。4. 完整代码实现与核心逻辑拆解下面进入正题带你把整个流程用代码写出来。我会按照代码的执行顺序把每一个模块拆开讲。4.1 初始化浏览器并加载搜索页面用DrissionPage接管现有Chrome浏览器直接复用登录状态。这一步是整段代码里最省心的地方不用去纠结登录怎么办。from DrissionPage import ChromiumPage page ChromiumPage() page.get(https://www.pinduoduo.com/search_result.html?search_key手机)这里有两个容易忽略的点。第一ChromiumPage默认会启动一个新浏览器窗口但如果你已经在正常浏览器里登录过拼多多建议研究一下它的接管模式用起来会更顺手。第二访问的URL里search_key的值就是你要搜索的商品词后面可以通过参数动态修改。4.2 在页面环境中执行JS生成anti-content页面加载完成后在浏览器环境里调用一个内部方法来生成anti_content。这个内部方法通常是挂载在全局对象上的我实测下来拼多多的页面脚本里有一个可调用的方法具体名字在不同时间会有变化这里展示一个通用的执行模板。anti_content page.run_js( () { try { // 这里调用页面内部的签名生成方法 // 不同时期的页面方法名不同需要根据实际调试结果调整 return window.__sign_method__ window.__sign_method__(); } catch (e) { return ; } } )这里一定要说清楚因为拼多多前端代码会不定期更新window对象上的方法名不会一直固定所以这段JS在实际运行时可能需要根据调试结果做微调。但大方向是对的优先找页面自己的加密方法而不是在Python里重新实现一套加密。4.3 构造请求参数并发送请求拿到anti_content之后剩下的就是常规操作了。构造请求头构造Payload然后用requests发送POST请求。import requests import json headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.pinduoduo.com/, Content-Type: application/json, Cookie: 你的浏览器登录Cookie } payload { pdduuid: 浏览器环境获取的uuid, search_met: , list_id: 浏览器环境获取的list_id, sort_type: 0, offset: 0, flair: {}, anti_content: anti_content } resp requests.post(https://apiv2.pinduoduo.com/api/你的商品搜索接口路径, headersheaders, jsonpayload) data resp.json()这里有三个细节值得注意。第一Cookie里包含了你的登录身份直接从浏览器开发者工具里复制过来填进去就行注意有效期过期了要重新复制。第二payload里的flair看起来只是个空JSON对象但实际上它包含了分类筛选条件如果你需要按价格区间或品牌筛选就是往里面塞参数这点后面单独讲。第三接口地址我这里用了一个相对模糊的路径因为实际路径会变但找法上文已经说了。4.4 解析JSON提取核心商品字段接口返回的JSON结构不算太复杂商品列表通常在data.items字段下每个item包含标题、价格、销量、店铺信息等。我整理字段的代码如下。items data.get(data, {}).get(items, []) for item in items: goods { 标题: item.get(goods_name), 价格: item.get(price_info, {}).get(price), 原价: item.get(price_info, {}).get(market_price), 销量: item.get(sales_tip), 店铺: item.get(mall_name), 商品ID: item.get(goods_id), 链接: https://mobile.yangkeduo.com/goods.html?goods_id str(item.get(goods_id)) } print(goods)这里的字段名是我实测过的但拼多多接口偶尔也会调整字段结构。如果你解析的时候发现某个字段取不到建议把返回的JSON用pprint打印出来对照一下最新字段名改动成本很低。4.5 翻页抓取与数据持久化商品列表一次只能加载30条实际做数据采集肯定要多翻几页。翻页的规律非常简单在payload里改offset参数就行第一页offset0第二页offset30第三页offset60以此类推。结合pandas把最终数据一次性导出CSV代码写着也很顺手。import pandas as pd all_goods [] for page_num in range(10): payload[offset] page_num * 30 resp requests.post(https://apiv2.pinduoduo.com/api/你的商品搜索接口路径, headersheaders, jsonpayload) data resp.json() items data.get(data, {}).get(items, []) if not items: break for item in items: all_goods.append({ 标题: item.get(goods_name), 价格: item.get(price_info, {}).get(price), 销量: item.get(sales_tip), 店铺: item.get(mall_name), 商品ID: item.get(goods_id), }) # 翻页之间加一点延时降低对服务端的压力 time.sleep(2) df pd.DataFrame(all_goods) df.to_csv(pdd_goods.csv, indexFalse, encodingutf-8-sig)最终生成的CSV文件用Excel直接打开就能看里面就是一张干净的商品数据表。注意这里的编码用的是utf-8-sig这样Excel打开不会出现中文乱码。很多人写完CSV以后发现中文全乱了十有八九就是编码没用对。5. 实操过程中的常见问题与避坑指南代码看着不长但真动手跑的时候各种问题接踵而至。我把遇到最多的情况和对应的排查思路整理出来你可以当一个速查表来用。5.1 请求被拦截或返回错误数据最典型的表现是接口返回的code不是0或者返回的items是空的甚至直接请求超时。这个问题90%出在anti_content没有正确生成或者Cookie失效。排查顺序建议是这样的先检查Cookie是否有有效最简单的方式是打开浏览器访问拼多多搜索页看是否还是登录状态然后在代码里重新复制一次Cookie。再检查anti_content是否为空字符串如果为空说明页面环境里的JS执行没成功需要打开浏览器控制台手动调试那段JS。最后检查请求频率。如果你已经把延时去掉了每分钟请求几十上百次触发风控是很正常的。建议每次翻页至少延时2到3秒。如果这些都排查完还是不行大概率就是接口路径或者参数结构出现了变动重新打开DevTools对比一下最新的请求Payload逐字段核对。5.2 翻页抓取时数据重复这种情况通常不是代码逻辑的问题而是拼多多接口会根据你的浏览行为重新返回推荐结果导致首页商品池不稳定。解决方式之一是在翻页的同时把list_id和flair参数保持和第一页完全一致不要重新获取。另外排序方式固定为综合排序以外的选项比如按销量排序数据稳定性也会好一些。5.3 字段解析不到值拼多多的接口返回字段里有的字段名起得很直观比如goods_name有的则是嵌套了好几层比如price_info.price。我在教程里给出的字段名是当前版本的常规结构但平台调整字段结构的频率并不低。遇到解析不到值别硬猜直接把data用json.dumps打印出来肉眼找一下你要的数据在哪个字段下再改代码。这比在网上搜答案快得多。5.4 关于控制抓取频率的提醒这一点必须单独拿出来说。做数据采集重要的不是你能不能爬到而是能不能持续地、合规地爬。无论你抓的是拼多多还是其他平台都应该控制好频率设置合理的延时不去踩对方服务器的底线。凡事过犹不及采集频率过高导致服务端压力增大最后触发验证码或者IP封禁损失更大的还是你自己。我在实际项目中一般会把延时设置在2到5秒之间单次采集量不超过几千条数据这样既能完成任务也不会给平台带来明显负担。6. 进阶展望从商品搜索扩展到更多方向到这里一条从零到抓取商品数据的完整链路已经走通了。但我想多说几句因为这套思路的价值远不止于商品搜索列表。学会这个方法以后你其实已经掌握了拼多多接口采集的底层逻辑换几个参数和接口路径就能延展到好多其他场景。比如订单数据的导出。热词里有人搜“拼多多订单导出工具”其实思路完全一致只不过请求的接口从商品搜索换成了订单列表接口参数从关键词换成了时间范围、订单状态等解析的字段也从商品标题变成了订单号、实付金额、收货信息。操作逻辑是同构的。比如商品评论数据的采集。商品详情页里那几百条评论底层也是通过一个接口分页加载的你只需要找到那个评论接口处理好参数中的商品ID和翻页偏移量就能批量获取评论内容用于舆情分析。再比如店铺维度数据的采集。你盯上了某个竞品店铺想知道它上架了哪些商品、价格怎么变动可以先用关键词搜索到这个店铺再找它的店铺商品列表接口定时采集并存库形成历史变动曲线。说白了爬虫这套技术从来都不是背代码而是掌握“找接口、理参数、解校验、清数据”这四板斧。你把这四个环节吃透了换任何一个网站无非是重走一遍这个流程。如果你在照着教程操作的过程中卡在某个环节最有效的做法不是瞎猜而是打开DevTools重新抓一次最新请求逐字段对比代码里的payload。多数问题对比着对比着就有答案了。我自己平时排查接口参数异常用这个方法解决的次数少说也有几十次确实比到处翻教程顶用。