别再用脚本硬撸了:Playwright 才是企业级采集的正确打开方式

47 阅读6分钟

如果你玩过抓取,大概率都经历过这个阶段:
一开始写个 Playwright 脚本,点两下、滚一滚、打印个标题,觉得「真香」;
但当要跑几百个任务、几千个页面时,才发现这玩意开始卡、崩、被封、甚至浏览器不关干净。

这篇文章就来讲讲——Playwright 从“能跑”到“能撑”的那条进化路:
从单机脚本到分布式调度,我们到底要补上哪些坑。

整篇文章分成五个部分:
错误示例 → 正确姿势 → 原因解释 → 陷阱提示 → 模板推荐。
属于那种踩过坑的人写给后来人的实战笔记。

一、最常见的误区:单机脚本的「幻觉稳定」

很多人第一次接触 Playwright 的时候,写出来的代码大概是这样👇

from playwright.sync_api import sync_playwright

def scrape(url):
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(url)
        print(page.title())
        browser.close()

scrape("https://www.example.com")

跑一下,输出正常。
于是信心满满地开始爬几十、几百个 URL。

然后,灾难就来了:

  • IP 被封,返回 403 或直接空白页。
  • 浏览器实例一堆 zombie process,CPU 直接打满。
  • 任务出错就全盘崩溃,没有重试机制。
  • 想看日志或重放失败页面?抱歉,没有任何监控。

这种“看似能跑”的脚本,其实就是个演示级 demo。
真要放到企业项目里,它几乎撑不过一天。

二、正确打开方式:Playwright + 代理 + 调度

要让 Playwright 稳定跑在生产环境里,必须把它“架构化”起来。
至少要具备这几个要素:

  1. 有代理池,防止封禁。
  2. 有任务队列,能重试、能分发。
  3. 有浏览器池,控制资源、避免内存炸裂。
  4. 有调度器,统一管理任务、监控执行情况。

下面这段代码,是一个相对正确的“工程级”写法。
用了 Playwright + 异步协程 + 爬虫代理IP,模拟了一个简单的任务队列采集系统。

实战代码:Playwright + 爬虫代理 + 异步采集

"""
Playwright 企业采集模板(百度百科版)
支持:代理IP、任务队列、异常控制、内容提取
"""

import asyncio
from playwright.async_api import async_playwright

# ==== 亿牛云爬虫代理配置(示例) ====
PROXY_HOST = "proxy.16yun.cn"    # 代理域名
PROXY_PORT = "12345"             # 代理端口
PROXY_USER = "16YUN"             # 代理用户名
PROXY_PASS = "16IP"              # 代理密码

# ==== 模拟任务队列 ====
# 可以替换为数据库、Redis 或 MQ 队列,这里简单用列表代替
BAIKE_URLS = [
    "https://baike.baidu.com/item/人工智能",
    "https://baike.baidu.com/item/Python",
    "https://baike.baidu.com/item/量子计算",
    "https://baike.baidu.com/item/云计算",
    "https://baike.baidu.com/item/深度学习",
]

# ==== 页面采集逻辑 ====
async def fetch_baike_page(playwright, url):
    # 代理配置(Playwright 需要完整代理URL)
    proxy = f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}"

    # 启动浏览器(开启代理 + 无头模式)
    browser = await playwright.chromium.launch(
        headless=True,
        proxy={"server": proxy}
    )

    try:
        page = await browser.new_page()

        # 设置 UA 和超时,防止被识别
        await page.set_extra_http_headers({
            "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"
        })

        # 打开页面
        await page.goto(url, timeout=30000)

        # 等待主要内容加载完成
        await page.wait_for_selector(".lemma-summary", timeout=10000)

        # 提取标题与简介
        title = await page.title()
        summary = await page.locator(".lemma-summary").inner_text()

        print(f"\n[✅] {url}")
        print(f"标题:{title}")
        print(f"简介:{summary[:100]}...")  # 只显示前100字防止过长

    except Exception as e:
        print(f"[❌] 抓取失败:{url},错误原因:{e}")

    finally:
        await browser.close()


# ==== 主入口 ====
async def main():
    async with async_playwright() as p:
        # 并发执行多个任务
        tasks = [fetch_baike_page(p, url) for url in BAIKE_URLS]
        await asyncio.gather(*tasks)


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

这段代码其实已经具备了企业架构的雏形:

  • 代理IP防护
  • 异步并发采集
  • 异常处理和资源释放
  • 多任务同时执行

虽然它还不是真正的分布式架构,但已经能抗住中等规模的采集量。

三、为什么这种写法更靠谱?

说白了,就是让系统更“可控”。
以前那种单机脚本,是“凭运气跑”;
而这个版本是“按机制跑”。

  • 代理 IP:用来切换出口,防止被网站识别。
  • asyncio 并发:让 CPU 和网络 I/O 同时跑,性能比同步模式高一个数量级。
  • 异常捕获:不怕某个任务崩掉,全局还能继续。
  • 浏览器上下文隔离:每个任务一个 page,互不影响,减少干扰。

当这些基础都做完之后,你再往上接入 Redis 队列、Kafka 调度、Prometheus 监控,这个架构就自然能长成“企业级采集系统”。


四、那些容易忽略的坑

我见过太多采集项目,死在一些“微不足道”的细节上。
下面这几点真是血泪经验:

  • 不要一次开太多浏览器
    Playwright 不是轻量线程,它是真浏览器。建议维护浏览器池(固定几个实例,复用 Page)。
  • 不要频繁切代理
    很多新手以为“换得越勤越安全”,其实相反。代理握手频繁,反而容易连不上。一般每 5~10 次请求换一次就够。
  • 要有日志
    出错的时候能回溯,是生产环境生存的底线。哪怕只是简单的 print,也比什么都没有强。
  • 动态页面要等待
    别一打开就抓内容,很多网站前端数据是延迟加载的。page.wait_for_selector() 是好朋友。
  • 分布式节点要有心跳
    不然调度器会以为任务执行中,其实 worker 已经挂掉。

这些看似细碎的“工程卫生”,恰恰决定了采集系统能不能跑得稳。

五、从“能跑”到“能撑”的那一步

Playwright 本身非常强大,它的稳定性、协议兼容性、脚本语法都很现代。
但它只是底层引擎,真正让它强大的,是外围那套生态:
代理、队列、调度、日志、监控。

换句话说,Playwright 是发动机,但你还得有底盘、油路、仪表盘,才能跑出长距离。

在企业项目中,我们通常会这么搭:

  • 上层:调度系统(Kubernetes / Airflow / Celery)
  • 中层:任务队列(Redis / Kafka)
  • 底层:浏览器池 + 代理池
  • 数据层:结果入库(MongoDB / ClickHouse / Elasticsearch)

这样的组合,就能让采集系统具备:
高并发、自动恢复、抗封禁、可追踪、可复现。

六、最后的感想

我一直觉得 Playwright 是个“上限很高”的工具。
你可以用它写个 20 行的小脚本,也可以撑起一个分布式采集平台。
差别就在于:你是把它当工具,还是当架构核心。

真正的企业级采集,不在于能不能抓到数据,而在于——
能不能一直抓、稳定抓、合规抓。

所以别小看一行代理配置、一个异常捕获或一个任务重试逻辑。
这些看似琐碎的部分,决定了你的系统是“能跑一会儿”,还是“能撑很久”。