今天直接上一个完整的实战案例。拼多多商品数据采集是我被问得最多的问题,也是我踩坑最多的地方。
这篇文章不讲零散指令,直接给一个从登录到采集到清洗的完整流程,你复制调整后就能跑。重点讲拼多多特有的几个坑:移动端页面结构、价格区间清洗、翻页逻辑。
先说这个流程能做什么
输入:一个Excel文件,里面有一列商品关键词 输出:每个关键词对应的商品名称、价格区间、销量、店铺名、链接
适用范围: 竞品价格监控、选品分析、供应商比价
第一步:环境准备与登录态处理
拼多多采集最烦人的是登录态。PC端网页频繁操作容易被弹出验证码,手机端页面相对友好。
我的选型: 用影刀的移动端浏览器环境模拟手机访问 m.pinduoduo.com。
影刀RPA实操路径: 新建流程 → 选择“网页自动化” → 浏览器类型下拉选择“移动端(安卓)”。
登录态保持策略:
# 步骤1:打开拼多多移动端首页

打开网页("https://m.pinduoduo.com", 打开方式="新建标签页")
# 步骤2:检测登录态
# 捕获元素:判断是否存在“我的”按钮(已登录状态有个人入口)
//*[contains(text(),"我的")]

# 步骤3:如果未登录,执行登录
如果 判断元素是否存在("//*[contains(text(),'登录')]") == True:
# 点击登录按钮
点击元素("//*[contains(text(),'登录')]")

# 等待登录页加载
等待元素加载("//input[@placeholder='请输入手机号']", 超时时间=10秒)
# 输入账号密码(注意:这里用模拟输入而不是直接输入)
模拟输入("//input[@placeholder='请输入手机号']", 账号变量)
模拟输入("//input[@type='password']", 密码变量)
点击元素("//*[contains(text(),'登录')]")
# 等待登录完成
等待(3秒)
输出日志("登录完成")
否则:
输出日志("已登录,跳过登录步骤")
结束如果
容易踩的坑: 拼多多移动端的密码输入框用 input 指令直接写入有时不生效,用“模拟输入”更稳。另外登录后可能跳出滑块验证,这部分社区版处理不了,创业版有滑块识别模块。
第二步:搜索关键词并获取商品列表
核心逻辑: 输入关键词 → 点击搜索 → 等待结果加载 → 获取商品卡片列表。
# 先读取Excel获取关键词列表
读取Excel文件("C:/data/keywords.xlsx", 输出变量=keywords_data)
# 假设关键词在第一列,从第二行开始
关键词列表 = keywords_data[1:]

# 按列表循环每个关键词
按列表循环(关键词列表, 循环项=keyword_row):
keyword = keyword_row[0] # 第一列是关键词
# ----- 执行搜索 -----
# 捕获元素:搜索框(移动端通常是顶部输入框)
//input[@class="search-input" or contains(@placeholder,"搜索")]
点击元素(搜索框)
# 清空输入框(先全选再删除)
模拟按键("Ctrl+A")
模拟按键("Backspace")
# 输入关键词
模拟输入(搜索框, keyword)
# 点击搜索按钮
//*[contains(@class,"search-btn") or contains(text(),"搜索")]
点击元素(搜索按钮)
# 等待搜索结果加载
等待(3秒)
# ----- 获取商品卡片列表 -----
# 捕获元素:所有商品卡片
获取相似元素列表("//div[contains(@class,'goods-card') or contains(@class,'product-item')]", 存入列表=product_cards)
输出日志("关键词【" + keyword + "】找到" + 获取列表长度(product_cards) + "个商品")
# ----- 循环采集每个商品的信息 -----
按列表循环(product_cards, 循环项=card, 循环索引=idx):
# 捕获元素:商品名称

//div[@class="product-name" or contains(@class,"goods-name")]
获取元素文本(商品名称, 存入变量=product_name)
# 捕获元素:价格(注意:拼多多显示的是价格区间,如“¥99.00-¥199.00”)
//span[contains(@class,"price") or contains(@class,"sale-price")]
获取元素文本(价格元素, 存入变量=price_text)
# 捕获元素:销量
//span[contains(text(),"已拼") or contains(@class,"sales")]
获取元素文本(销量元素, 存入变量=sales_text)
# 捕获元素:店铺名
//a[contains(@class,"store-name") or contains(@class,"shop-name")]
获取元素文本(店铺名元素, 存入变量=store_name)
# 捕获元素:商品链接
获取元素属性(商品图片或标题, 属性名="href", 存入变量=product_url)
# 组装一行数据
新行 = [keyword, product_name, price_text, sales_text, store_name, product_url]
# 追加写入Excel(注意:这里用之前创建的“结果表”)
追加行数据到表格("C:/data/result.xlsx", 新行)
结束循环
# ----- 判断是否需要翻页 -----
# 通过判断“下一页”按钮是否存在来决定是否继续
条件循环(判断元素是否存在("//*[contains(text(),'下一页')]") == True):
点击元素("//*[contains(text(),'下一页')]")
等待(3秒)
# 获取当前页的商品卡片
获取相似元素列表("//div[contains(@class,'goods-card')]", 存入列表=product_cards)
按列表循环(product_cards, 循环项=card):
# 同上采集逻辑...
结束循环
结束条件循环
结束循环
第三步:价格清洗(核心难点)
拼多多的价格显示是 “¥99.00-¥199.00” 或 “¥99.00起” 的形式,不能直接拿来分析。需要拆成最低价和最高价。
用Python+Pandas清洗(在影刀的“执行Python代码”指令里跑):
import pandas as pd
import re
# 输入:raw_data 从影刀传入(二维列表)
# 输出:cleaned_data 返回影刀
df = pd.DataFrame(raw_data[1:], columns=raw_data[0])
# 列名:['关键词', '商品名', '价格文本', '销量', '店铺名', '链接']
# ===== 价格清洗函数 =====
def extract_price_range(price_str):
"""
输入:"¥99.00-¥199.00" 或 "¥99.00起" 或 "¥99.00"
输出:[最低价, 最高价]
"""
if pd.isna(price_str):
return [None, None]
text = str(price_str)
# 提取所有数字(含小数点)
numbers = re.findall(r'[\d.]+', text)
if len(numbers) == 0:
return [None, None]
# 转为浮点数
nums = [float(n) for n in numbers]
if len(nums) == 1:
# 只有一个价格:最低价=最高价=该价格
return [nums[0], nums[0]]
else:
# 多个价格:取最小和最大
return [min(nums), max(nums)]
# 应用清洗
df[['最低价', '最高价']] = df['价格文本'].apply(
lambda x: pd.Series(extract_price_range(x))
)
# ===== 销量清洗 =====
def clean_sales(text):
if pd.isna(text):
return 0
text = str(text)
# "10万+" → 100000
if '万' in text:
num = re.search(r'[\d.]+', text)
if num:
return int(float(num.group()) * 10000)
# "9999件" → 9999
num = re.search(r'[\d.]+', text)
return int(float(num.group())) if num else 0
df['销量_清洗'] = df['销量'].apply(clean_sales)
# ===== 去重:同一商品只保留一条 =====
df = df.drop_duplicates(subset=['商品名'], keep='first')
# ===== 输出 =====
cleaned_data = [df.columns.tolist()] + df.values.tolist()
第四步:翻页的坑与处理方案
拼多多搜索结果页的翻页有个特点:滚动加载而不是传统翻页。在移动端页面上,滑到页面底部会自动加载更多商品。
我的翻页方案(条件循环+滚动):
设置变量(连续无新增次数 = 0)
条件循环(连续无新增次数 < 3):
# 记录滚动前商品数量
获取相似元素列表("//div[contains(@class,'goods-card')]", 存入列表=before_cards)
前数量 = 获取列表长度(before_cards)
# 滚动到页面底部
滚动到元素("//*[@id='app']/div[last()]") # 滚动到页面最后
等待(2秒) # 等待加载
# 获取滚动后商品数量
获取相似元素列表("//div[contains(@class,'goods-card')]", 存入列表=after_cards)
后数量 = 获取列表长度(after_cards)
# 判断有没有新增
如果 后数量 > 前数量:
设置变量(连续无新增次数 = 0)
# 采集新增的商品(只采集新增部分,用索引范围取)
新增卡片 = after_cards[前数量:后数量]
按列表循环(新增卡片, 循环项=card):
# 采集逻辑同上...
结束循环
否则:
设置变量(连续无新增次数 = 连续无新增次数 + 1)
结束如果
结束条件循环
输出日志("滚动加载结束,共采集" + 后数量 + "个商品")
这个方案的优点:
- 不会无限滚动(连续3次没有新商品就停止)
- 每次只采集新增的商品,不重复采集
- 不会因为网络慢而漏数据
防限流策略
拼多多对高频访问有限流,我的经验是:
| 操作 | 建议间隔 | 原因 |
|---|---|---|
| 每次搜索 | 等待3-5秒 | 搜索结果加载需要时间 |
| 每采集一个商品 | 等待0.5-1秒 | 避免被判定为爬虫 |
| 每翻一页 | 等待2-3秒 | 页面滚动加载需要时间 |
| 每个关键词切换 | 等待5-8秒 | 重置搜索状态 |
我的限流检测方法: 在关键步骤后加“判断元素是否存在”检测异常页面。
# 检测是否被限流
如果 判断元素是否存在("//*[contains(text(),'验证') or contains(text(),'滑块')]") == True:
输出日志("检测到验证页面,暂停10秒")
等待(10秒)
# 创业版可以接入打码平台,社区版建议手动干预
否则:
# 正常采集
结束如果
完整流程结构图
开始
↓
创建结果Excel(含表头)
↓
读取关键词列表
↓
打开拼多多移动端 → 检测登录态 → 未登录则登录
↓
按列表循环每个关键词 ──────────────┐
├→ 输入关键词搜索 │
├→ 等待加载 │
├→ 获取商品卡片列表 │
├→ 循环采集每条商品数据 ──→ 追加写入Excel │
├→ 滚动加载翻页(条件循环) │
└→ 切换下一个关键词 ────────────────┘
↓
所有关键词处理完成
↓
执行Python清洗(价格/销量/去重)
↓
输出清洗后的Excel
↓
结束
常见问题速查
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 搜索结果为空 | 关键词特殊字符或页面未加载 | 加等待时间,检查关键词是否有特殊符号 |
| 价格提取失败 | 价格格式变化(如“¥”变“¥”) | 用正则提取数字,不依赖固定格式 |
| 翻页死循环 | 滚动判断条件设置不当 | 用“连续无新增次数”限制退出 |
| 登录态频繁失效 | Cookie过期 | 每次流程开始重新登录 |
| 流程被限流 | 请求频率过高 | 增加等待间隔,设置随机延迟 |
| 采集数据量对不上 | 滚动加载时漏采 | 用“增量采集”方案,每次只采新增的 |
推荐资源
- 影刀官方《拼多多自动化采集模板》——流程市场里可以直接下载参考
- 拼多多移动端页面结构更新频率较高,建议每次跑之前手动打开页面确认一下XPath是否还能用
#影刀RPA #RPA自动化 #拼多多 #电商自动化 #批量采集 #数据清洗
作者:林焱
本文为《影刀RPA学习手册》系列文章之一,内容源于实操经验的整理与分享。
