754 字
4 分钟
基于 Selenium 和 PyQuery 爬取淘宝数据:全自动无头模式实战

1. 爬虫工作原理图#

在抓取淘宝这类由 JavaScript 动态渲染的页面时,传统的 requests 库难以获取完整源码。我们使用 Selenium 模拟真实浏览器行为,其核心交互逻辑如下:


2. 环境准备与高级配置#

2.1 依赖安装#

Terminal window
pip install selenium pyquery

2.2 绕过机器人检测(关键)#

淘宝会对 window.navigator.webdriver 属性进行检测。如果是 true,系统会立刻弹出滑动验证码。我们必须在启动时通过选项隐藏这个特征。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = webdriver.ChromeOptions()
# 现代无头模式写法
options.add_argument('--headless=new')
# 禁用沙盒,提升稳定性
options.add_argument('--no-sandbox')
# 屏蔽 webdriver 特征,防止反爬识别
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)
browser = webdriver.Chrome(options=options)
# 执行 CD P命令,修改浏览器内部属性
browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
wait = WebDriverWait(browser, 10)

3. 核心流程解析#

3.1 关键词搜索与元素等待#

在爬取过程中,网络波动是常态。我们使用 WebDriverWait 配合 Expected Conditions (EC) 来实现“显式等待”,只有当元素真正出现在页面上时才继续。

def search(keyword='美食'):
try:
browser.get("https://www.taobao.com")
# 等待搜索框加载
input_q = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#q')))
# 等待搜索按钮点击
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button.btn-search')))
input_q.send_keys(keyword)
submit.click()
# 获取总页数
total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.total')))
get_products()
return total.text
except Exception as e:
print(f"搜索失败: {e}")
return search(keyword)

3.2 使用 PyQuery 高效解析数据#

虽然 Selenium 可以提取文本,但 PyQuery 在解析海量节点时速度更快,且语法类似 jQuery,更加灵活。

from pyquery import PyQuery as pq
def get_products():
# 确保商品列表已加载
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
html = browser.page_source
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
product = {
'title': item.find('.title').text().strip(),
'price': item.find('.price').text(),
'deal': item.find('.deal-cnt').text(),
'location': item.find('.location').text(),
'shop': item.find('.shop').text(),
'image': item.find('.pic .img').attr('data-src') or item.find('.pic .img').attr('src')
}
# 建议此处接入 MongoDB 或 CSV 存储
print(f"抓取到: {product['title']}")

4. 翻页逻辑与性能建议#

翻页时,我们不点击“下一页”按钮,而是直接修改页码框并点击“确定”,这样可以有效防止页码漂移。

def next_page(page_number):
try:
page_input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'input.input.J_Input')))
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'span.btn.J_Submit')))
page_input.clear()
page_input.send_keys(page_number)
submit.click()
# 验证是否成功翻到指定页码
wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, 'li.item.active > span'), str(page_number)))
get_products()
except TimeoutException:
next_page(page_number)

5. 进阶反爬策略与总结#

爬取淘宝数据的三个重要准则:

  1. 登录问题:淘宝目前大部分搜索结果都需要登录。建议在启动时加载一个现有的 Chrome User Profile 以保持登录状态,避免频繁弹出的登录框。
  2. 速度控制:无头模式虽快,但过快的翻页频率会导致 IP 被临时封禁。建议每隔 3-5 页添加一个随机的 time.sleep()
  3. 解析后备:如果页面结构变动,优先检查选择器(CSS Selector)。

通过 Selenium + PyQuery 的组合,我们实现了对动态网页的完美兼容。如果你需要处理更复杂的登录验证,下一步可以尝试引入 Cookies 管理代理 IP 池

基于 Selenium 和 PyQuery 爬取淘宝数据:全自动无头模式实战
https://sw.rscclub.website/posts/python3pachongtbms100/
作者
杨月昌
发布于
2017-11-18
许可协议
CC BY-NC-SA 4.0