本文基于线上爬虫、自动化项目实操经验整理,分安装、基础API、同步/异步两种写法、元素定位、页面交互、网络监听、代理配置、防检测、批量爬虫、文件上传下载、Linux服务器部署、常见报错排错完整覆盖,所有代码均可直接复制运行,无空洞理论,适合开发、测试、运维人员自学,也可作为企业内部技术文档。

一、环境安装与基础依赖

1. 版本要求

Python 3.8及以上版本,Windows、macOS、CentOS、Ubuntu全平台支持。

2. 安装步骤

第一步安装Python依赖包

pip install playwright

第二步自动下载内置浏览器内核(Chromium/Firefox/WebKit)

# 安装全部三款浏览器
playwright install
# 只安装Chromium(爬虫常用,体积更小)
playwright install chromium

Linux服务器额外安装系统底层依赖,否则浏览器启动报错

playwright install-deps

3. 快速验证是否安装成功

新建test.py运行基础代码,能正常打开百度代表环境正常

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://www.baidu.com")
    print(page.title())
    browser.close()

二、两大执行模式:同步API与异步API

1. 同步API(新手首选,单页面简单任务)

逻辑直观,不用写await,适合简单自动化、单次抓取场景。with语句会自动释放浏览器资源,避免内存泄漏。

from playwright.sync_api import sync_playwright

def sync_demo():
    with sync_playwright() as p:
        # headless=False显示浏览器窗口,True无头后台运行
        browser = p.chromium.launch(headless=False)
        page = browser.new_page(viewport={"width": 1280, "height": 720})
        page.goto("https://www.baidu.com", wait_until="networkidle")
        # 输入搜索词
        page.locator("#kw").fill("Python Playwright")
        page.locator("#su").click()
        # 等待结果加载完成
        page.wait_for_load_state("domcontentloaded")
        print("页面标题:", page.title())
        # 截图保存
        page.screenshot(path="baidu_result.png")
        browser.close()

if __name__ == "__main__":
    sync_demo()

2. 异步API(批量爬虫、多并发场景推荐)

基于asyncio协程,同一浏览器创建多个页面并行执行,大幅提升抓取效率,大批量任务必须用异步。

import asyncio
from playwright.async_api import async_playwright

async def async_task(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto(url, timeout=30000)
        title = await page.title()
        print(f"{url} 标题:{title}")
        await browser.close()

async def batch_crawl():
    task_list = [
        async_task("https://www.baidu.com"),
        async_task("https://www.bing.com")
    ]
    await asyncio.gather(*task_list)

if __name__ == "__main__":
    asyncio.run(batch_crawl())

三、浏览器启动高级参数配置

launch方法支持大量实用参数,爬虫和自动化场景高频使用。

1. 关闭自动化特征、模拟真实浏览器

browser = p.chromium.launch(
    headless=True,
    # 关闭自动化检测标记,规避网站反爬
    args=[
        "--disable-blink-features=AutomationControlled",
        "--no-sandbox",
        "--disable-dev-shm-usage"
    ]
)
  • --no-sandbox:Linux服务器必加,否则root用户无法启动浏览器
  • --disable-dev-shm-usage:解决服务器共享内存不足崩溃问题

2. 自定义UA、视口、语言指纹

context = browser.new_context(
    user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    viewport={"width": 1920, "height": 1080},
    locale="zh-CN",
    timezone_id="Asia/Shanghai"
)
page = context.new_page()

3. 持久化登录态(保存Cookie,免重复登录)

登录一次后存储上下文,下次启动直接携带登录信息,适合需要登录才能抓取数据的网站。

# 登录后保存上下文
context.storage_state(path="login_cookie.json")
# 下次启动加载cookie
context = browser.new_context(storage_state="login_cookie.json")

四、元素定位核心:Locator API(官方推荐)

早期query_selector存在元素过期报错问题,Locator是稳定定位方案,支持链式调用、自动等待。

1. 常用定位方式

# 1. ID选择器
page.locator("#kw")
# 2. Class选择器
page.locator(".search-input")
# 3. 文本匹配(最常用,不受页面样式改动影响)
page.locator("text=登录")
page.locator("text=确认提交", exact=True) # 精确匹配完整文本
# 4. 属性匹配
page.locator("[placeholder='请输入账号']")
# 5. 组合筛选:包含指定文本的按钮
page.locator("button", has_text="搜索")
# 6. 多层嵌套定位
page.locator(".list-item").locator("a")

2. 批量提取列表数据(爬虫核心)

# 获取所有商品标题文本
title_list = page.locator(".goods-title").all_text_contents()
for title in title_list:
    print(title)
# 获取元素属性,如链接、图片地址
src = page.locator("img.cover").get_attribute("src")

五、页面交互操作大全

1. 输入、点击、单选复选

# 输入文本
page.locator("#username").fill("test_user")
# 清空输入框
page.locator("#password").clear()
# 点击按钮
page.locator("text=登录").click()
# 强制点击(元素被遮挡时使用)
page.locator("text=弹窗确认").click(force=True)
# 下拉选择框
page.locator("#city").select_option("shanghai")
# 复选框勾选
page.locator("#agree").check()

2. 鼠标滚动、下拉加载更多

# 滚动到指定元素
page.locator(".bottom-list").scroll_into_view_if_needed()
# 模拟页面向下滚动
page.evaluate("window.scrollTo(0, document.body.scrollHeight)")

3. 文件上传

# 上传本地文件到上传组件
page.locator('input[type="file"]').set_input_files("./upload.png")

4. 文件下载监听

# 监听下载事件
with page.expect_download() as download_info:
    page.locator("text=导出Excel").click()
download = download_info.value
# 保存到本地
download.save_as("./data.xlsx")

六、等待策略(杜绝time.sleep硬等待)

Playwright内置智能自动等待,操作元素前会自动等待元素可见、可点击,复杂页面搭配手动等待提升稳定性。

  1. wait_for_load_state 页面加载状态
# 仅DOM加载完成(速度快)
page.goto(url, wait_until="domcontentloaded")
# 所有网络请求基本结束(抓取接口数据推荐)
page.goto(url, wait_until="networkidle")
  1. 等待指定元素出现
# 等待商品列表渲染完成,超时10秒
page.wait_for_selector(".goods-item", timeout=10000)
  1. 全局默认超时设置
page.set_default_timeout(15000)

七、网络拦截、请求监听(抓取接口JSON)

1. 监听页面所有接口返回数据

不用解析DOM,直接抓取后端返回JSON,数据更干净稳定。

api_data = {}

def capture_response(response):
    # 过滤目标接口
    if "/api/goods/list" in response.url:
        if response.status == 200:
            nonlocal api_data
            api_data = response.json()

# 注册监听事件
page.on("response", capture_response)
page.goto("目标页面地址")
print(api_data)

2. 拦截请求,屏蔽图片、广告资源(提速省流量)

def block_resource(route):
    # 屏蔽图片、视频、字体
    if route.request.resource_type in ["image", "media", "font"]:
        route.abort()
    else:
        route.continue_()

page.route("**/*", block_resource)

3. Mock接口返回数据(自动化测试专用)

def mock_api(route):
    if "/api/user/info" in route.request.url:
        route.fulfill(
            status=200,
            content_type="application/json",
            body='{"code":0,"data":{"name":"测试用户"}}'
        )
    else:
        route.continue_()

page.route("**/api/user/**", mock_api)

八、代理IP配置(爬虫必备)

支持浏览器全局代理、单上下文独立代理,带账号密码认证。

1. 浏览器级别代理(所有页面共用IP)

browser = p.chromium.launch(
    headless=True,
    proxy={
        "server": "http://127.0.0.1:7890",
        "username": "proxy_user",
        "password": "proxy_pass"
    }
)

2. 单上下文独立代理(多IP并发抓取推荐)

browser = p.chromium.launch(headless=True)
# 同一个浏览器创建多个上下文,每个使用不同代理
context1 = browser.new_context(proxy={"server": "http://ip1:port"})
context2 = browser.new_context(proxy={"server": "http://ip2:port"})

九、反爬优化方案(降低被封禁概率)

  1. 启动浏览器添加关闭自动化特征参数(前文args配置)
  2. 自定义真实UA、时区、屏幕分辨率,统一浏览器指纹
  3. 使用持久化上下文保存Cookie,模拟真实用户登录行为
  4. 增加操作间隔,模拟人工浏览
import time
time.sleep(random.uniform(0.5, 1.5))
  1. 搭配代理池轮换IP,单IP控制访问频率
  2. 安装playwright-stealth插件,深度隐藏自动化标识
pip install playwright-stealth

使用示例:

from playwright_stealth import stealth_sync
stealth_sync(page)

十、Linux服务器无头部署实战

服务器无图形界面,必须使用headless模式,完整运行模板:

from playwright.sync_api import sync_playwright
import random

def server_crawl():
    with sync_playwright() as p:
        browser = p.chromium.launch(
            headless=True,
            args=[
                "--no-sandbox",
                "--disable-dev-shm-usage",
                "--disable-blink-features=AutomationControlled"
            ]
        )
        context = browser.new_context(
            user_agent="Mozilla/5.0 (X11; Linux x86_64) Chrome/120.0.0.0 Safari/537.36",
            viewport={"width": 1366, "height": 768}
        )
        page = context.new_page()
        page.set_default_timeout(20000)
        try:
            page.goto("https://target.com", wait_until="networkidle")
            title = page.title()
            print("抓取成功:", title)
        except Exception as e:
            print("抓取异常:", str(e))
        finally:
            page.close()
            browser.close()

if __name__ == "__main__":
    server_crawl()

后台常驻运行可搭配systemd、PM2托管脚本,崩溃自动重启。

十一、常见报错与排错指南

  1. TimeoutError 元素等待超时
    原因:页面加载慢、选择器写错、元素被弹窗遮挡
    解决:延长timeout、核对Locator文本/CSS、等待弹窗消失再操作

  2. Linux启动报错:no sandbox
    解决:launch参数添加--no-sandbox

  3. 浏览器内存占用持续飙升
    原因:page、context未正常关闭,循环内未释放资源
    解决:使用with语句,每次抓取完成执行page.close()

  4. 网站识别自动化,返回403/验证码
    解决:添加stealth、关闭AutomationControlled、更换代理IP、降低抓取频率

  5. playwright install 下载浏览器失败
    解决:切换国内镜像,或手动下载浏览器内核放置指定目录

  6. 文件下载无响应
    解决:使用page.expect_download()上下文捕获下载事件,不要直接点击后休眠

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐