基于 Selenium 的淘宝爬虫
一、问题背景
目标很明确:在真实用户环境下,从淘宝搜索结果页批量采集商品信息(名称、价格、店铺、链接),并支持结构化导出。
约束条件:
淘宝具备较强反自动化机制(登录校验、滑块验证、行为检测)
页面为动态渲染(懒加载 + 多版本 DOM)
搜索结果可能在新标签页打开
翻页结构不稳定
因此,本项目核心不是“爬”,而是在接近真实用户行为的前提下,稳定获取结构化数据
二、整体架构
流程拆分为五个模块:
浏览器初始化 → 登录 → 搜索 → 数据采集 → 数据保存
对应代码结构:
main()
├── login(driver)
├── search(driver)
├── collect(driver)
└── save_data(data)三、浏览器初始化与反检测
核心问题
Selenium 默认特征非常明显,会被识别为自动化工具。
解决方案
通过 Edge + CDP + 指纹伪装:
options = Options()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument(
'user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
)进一步隐藏:
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})四、登录逻辑(重点难点)
淘宝登录包含三类阻碍:
账号密码输入
滑块验证
手机验证码
关键实现
username_input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#fm-login-id"))
)
username_input.send_keys(login_username)
password_input = driver.find_element(By.CSS_SELECTOR, "#fm-login-password")
password_input.send_keys(login_password)滑块处理(模拟人类轨迹)
track = [20, 40, 60, 80, 50, 30, 10, 5, 2]
for x in track:
action.move_by_offset(xoffset=x, yoffset=random.randint(-2, 2)).perform()
time.sleep(random.uniform(0.1, 0.3))验证逻辑
driver.find_element(By.LINK_TEXT, "我的淘宝")五、搜索模块(兼容多版本 DOM)
淘宝搜索框存在多个版本:
selectors = [
(By.ID, "q"),
(By.CSS_SELECTOR, "input[name='q']"),
(By.CSS_SELECTOR, ".search-combobox-input"),
]逐个尝试:
for by, sel in selectors:
try:
search_input = driver.find_element(by, sel)搜索触发策略
优先回车:
search_input.send_keys(product_name + '\n')失败 fallback:
driver.execute_script("arguments[0].click();", btn)新标签页处理
handles = driver.window_handles
if len(handles) > 1:
driver.switch_to.window(handles[-1])六、数据采集(核心逻辑)
1. 懒加载处理
for i in range(3):
driver.execute_script(
f"window.scrollTo(0, document.body.scrollHeight * {(i+1)/3});"
)2. 商品卡片定位(多策略兜底)
products = driver.find_elements(By.CSS_SELECTOR, "a[class*='doubleCardWrapperAdapt--']")兜底:
div[class*='search-content-col'] > a
div[class*='Card--']3. 字段解析
title_elem = product.find_element(By.CSS_SELECTOR, "div[class*='title--']")
product_name = title_elem.get_attribute("title") or title_elem.textprice_elem = product.find_element(By.CSS_SELECTOR, "div[class*='innerPriceWrapper--']")shop_elem = product.find_element(By.CSS_SELECTOR, "a[class*='shopName--']")4. 翻页机制(关键稳定性设计)
不依赖固定 class,而是基于“语义匹配”:
next_btn_selectors = [
"//button[contains(., '下一页')]",
"//a[contains(., '下一页')]",
]过滤无效按钮:
if el.get_attribute("disabled"):
continue点击:
driver.execute_script("arguments[0].click();", next_btn)验证采集成功
输出:
print(f"第 {current_page} 页采集完毕,累计 {len(product_list)} 条")七、数据导出模块
支持四种格式:
示例:Excel 导出
df = pd.DataFrame(data, columns=['商品名称', '价格', '店铺名称', '商品链接'])
df.to_excel(filepath, index=False)兼容处理(无 pandas)
自动降级:
fallback_filepath = f"{filename}_excel_fallback.csv"八、完整执行流程
driver.get("https://www.taobao.com")
login(driver)
search(driver)
collect(driver)
save_data(product_list)九、实际问题与原因分析
1. 登录失败
可能原因:
DOM 结构变化
触发风控(IP / 行为异常)
需要短信验证
处理:
增加人工介入(input暂停)
降低自动化速度
2. 商品抓取为空
原因:
懒加载未触发
selector 失效
处理:
增加 scroll 次数
扩展 CSS 匹配规则
3. 翻页失效
原因:
按钮被遮挡
class 动态变化
处理:
改用 XPath + 文本匹配
强制 JS 点击
十、结论(实事求是)
该脚本本质不是“高并发爬虫”,而是一个模拟真实用户行为的浏览器自动化采集工具
其有效性的前提:
不追求速度(否则触发风控)
接受人工参与(验证码环节)
持续适配页面结构变化
十一、可扩展方向
接入代理池(降低风控概率)
引入 OCR 自动识别验证码
数据入库(MySQL / MongoDB)
分布式调度(但风险显著上升)
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 Vincent Cassano