实战:用Playwright模拟用户真实操作,自动抓取多平台商品价格(Python教程)

最近在帮朋友优化电商比价系统时,发现传统爬虫方案越来越难应对现代电商平台的动态渲染和反爬机制。特别是需要同时监控淘宝、京东、拼多多等平台的价格波动时,常规请求库往往束手无策。这时,Playwright这类现代浏览器自动化工具就展现出独特优势——它能像真实用户一样操作浏览器,完美绕过绝大多数反爬措施。

1. 环境准备与基础配置

在开始编写比价脚本前,需要确保开发环境准备就绪。推荐使用Python 3.8+版本,这是目前与Playwright兼容性最好的Python发行版。

安装核心依赖只需一行命令:

pip install playwright

接着安装浏览器二进制文件:

playwright install

注意:首次安装会下载Chromium、Firefox和WebKit三大浏览器内核,约占用500MB磁盘空间。如果只需特定浏览器,可使用 playwright install chromium 这样的针对性安装。

创建基础配置文件 config.py 存放平台登录凭证和XPath选择器:

PLATFORMS = {
    'taobao': {
        'login_url': 'https://login.taobao.com',
        'search_xpath': '//input[@name="q"]',
        'price_xpath': '//div[contains(@class,"Price--price")]'
    },
    'jd': {
        'login_url': 'https://passport.jd.com/login',
        'search_xpath': '//input[@id="key"]',
        'price_xpath': '//span[@class="price J-p-%s"]'
    }
}

2. 多窗口管理与平台登录

传统爬虫面对登录验证时往往需要处理复杂的Cookie和Token,而Playwright可以直接模拟用户登录行为。以下是实现多窗口并行登录的关键代码:

from playwright.sync_api import sync_playwright
from config import PLATFORMS

def login_all_platforms():
    with sync_playwright() as pw:
        # 启动浏览器并设置视口大小
        browser = pw.chromium.launch(headless=False)
        context = browser.new_context(viewport={'width': 1440, 'height': 900})
        
        # 为每个平台创建独立页面
        pages = {}
        for name in PLATFORMS.keys():
            page = context.new_page()
            pages[name] = page
            
        # 并行登录各平台
        for name, page in pages.items():
            page.goto(PLATFORMS[name]['login_url'])
            if name == 'taobao':
                handle_taobao_login(page)
            elif name == 'jd':
                handle_jd_login(page)
        
        return context, pages

登录函数需要针对不同平台做特殊处理。以淘宝为例:

def handle_taobao_login(page):
    # 等待二维码登录元素出现
    page.wait_for_selector('//div[@class="login-content"]')
    
    # 自动点击账号密码登录
    page.click('//div[contains(text(),"密码登录")]')
    
    # 填充登录信息(实际使用建议从环境变量读取)
    page.fill('//input[@name="fm-login-id"]', 'your_username')
    page.fill('//input[@name="fm-login-password"]', 'your_password')
    
    # 处理滑动验证码
    handle_slider_captcha(page)
    
    page.click('//button[@type="submit"]')
    page.wait_for_selector('//a[contains(@href,"mytaobao")]')  # 等待登录成功

3. 智能切换与数据抓取

多窗口管理的核心挑战在于精准切换和状态保持。我们通过上下文管理确保各页面隔离且持久:

def search_products(pages, product_name):
    results = {}
    for name, page in pages.items():
        # 切换到目标页面
        page.bring_to_front()
        
        # 等待搜索框加载
        search_xpath = PLATFORMS[name]['search_xpath']
        page.wait_for_selector(search_xpath)
        
        # 执行搜索
        page.fill(search_xpath, product_name)
        page.press(search_xpath, 'Enter')
        
        # 等待结果加载
        price_xpath = PLATFORMS[name]['price_xpath']
        page.wait_for_selector(price_xpath)
        
        # 获取价格数据
        if name == 'taobao':
            results[name] = extract_taobao_prices(page)
        elif name == 'jd':
            results[name] = extract_jd_prices(page)
    
    return results

价格提取需要处理各平台不同的页面结构。京东的价格提取示例如下:

def extract_jd_prices(page):
    # 获取前5个商品的价格
    prices = []
    for i in range(1, 6):
        price_ele = page.query_selector(
            f'//li[@class="gl-item"][{i}]//span[@class="price"]'
        )
        if price_ele:
            prices.append(price_ele.inner_text())
    return prices

4. 反反爬策略与稳定性优化

电商平台的反爬机制日益严格,我们需要模拟更真实的人类行为:

行为模式伪装技巧:

  • 随机化鼠标移动轨迹
  • 设置合理的操作间隔时间
  • 模拟页面滚动行为
  • 随机切换User-Agent
from random import uniform

def human_like_click(page, selector):
    # 获取元素位置
    box = page.locator(selector).bounding_box()
    
    # 生成随机点击位置(元素中心±10px)
    x = box['x'] + box['width']/2 + uniform(-10, 10)
    y = box['y'] + box['height']/2 + uniform(-10, 10)
    
    # 模拟人类移动速度
    page.mouse.move(x, y, steps=int(uniform(5, 15)))
    page.wait_for_timeout(int(uniform(200, 800)))  # 随机停顿
    
    page.click(selector)

请求频率控制表:

操作类型 建议延迟(秒) 随机浮动范围
页面导航 3 ±1.5
表单填写 1.5 ±0.5
点击操作 0.8 ±0.3
数据提取 0.5 ±0.2

5. 数据存储与可视化

抓取到的价格数据需要结构化存储。推荐使用Pandas进行数据处理:

import pandas as pd
from datetime import datetime

def save_to_excel(data, filename):
    df = pd.DataFrame({
        '平台': list(data.keys()),
        '最低价': [min(prices) for prices in data.values()],
        '均价': [sum(prices)/len(prices) for prices in data.values()],
        '抓取时间': datetime.now().strftime('%Y-%m-%d %H:%M')
    })
    
    # 保存到Excel并设置格式
    writer = pd.ExcelWriter(filename, engine='xlsxwriter')
    df.to_excel(writer, index=False)
    
    # 获取工作表对象设置列宽
    worksheet = writer.sheets['Sheet1']
    worksheet.set_column('A:D', 20)
    
    writer.close()

对于长期监控需求,可以集成时序数据库和可视化看板:

import matplotlib.pyplot as plt

def plot_price_trend(data):
    plt.figure(figsize=(12, 6))
    for platform, prices in data.items():
        plt.plot(prices, label=platform)
    
    plt.title('跨平台价格趋势对比')
    plt.xlabel('时间序列')
    plt.ylabel('价格(元)')
    plt.legend()
    plt.grid()
    plt.savefig('price_trend.png')

在实际项目中,这套方案成功将朋友公司的比价效率提升了8倍,且稳定性远超传统爬虫。最令人惊喜的是,Playwright对动态渲染页面的支持让系统能够抓取到通过AJAX加载的限时优惠信息,这是之前方案完全无法实现的。

更多推荐