Serverless+Playwright的组合值得用吗?我们做了个测试

爬虫代理

——从一次冷启动事故开始谈

如果说过去的爬虫架构像一辆固定路线的公交车,那么 Serverless 的出现,让开发者突然拥有了“随叫随到的无人驾驶出租车”。不需要长时间维护服务器,不需要考虑资源闲置成本,只要写好脚本、部署到云端,触发时自动运行,空闲时不产生费用——听起来特别完美。

于是,越来越多团队开始尝试把数据抓取、文本分析、异步调度等工作往 Serverless 上迁移,尤其是定时任务型爬虫、事件触发型采集器、有波动特征的流量抓取任务。理论上,Serverless 可以天然适应这类模式:来任务就执行,不来就安静。

然而,技术世界里,总有一些看起来“特别合适”的组合,真正落地时却暴露出意想不到的问题。Serverless + 爬虫,就是其中一个典型案例——尤其是涉及浏览器自动化(如 Playwright/Chromium)和反爬策略敏感的网站,例如知乎。

这篇内容,就是基于一次真实迁移过程里发生的故障、排查和改进,来看看 Serverless 爬虫到底能不能走远,它的瓶颈在哪里,以及该怎么绕过去。

整个事故的时间线

为了让问题更直观,我们把整个过程按照时间顺序展开,像复盘一样:

09:00 —— 新架构上线

项目正式切到 Serverless 环境。部署方式是 AWS Lambda + Playwright,并接入代理池。迁移后的第一感受是轻松:没有常驻服务、没有监控守护进程、没有资源浪费。

09:10 —— 流量突然上涨

由于某个关键词相关话题登上趋势榜,触发器调用次数升级,Lambda 实例快速横向扩容。乍看一切正常,扩展能力符合预期。

09:11 —— 出现第一批错误

运行时延开始从原本 6-8 秒增长到 15 秒以上,日志里出现 Navigation Timeout。简单翻译一下:不是代码坏了,而是执行环境启动得太慢,浏览器又比较重,冷启动直接拖垮了任务执行窗口。

09:12 —— 失败率继续上升

随着更多实例被触发,每个实例都重复初始化 Playwright、创建浏览器上下文、完成代理认证。再叠加知乎对短时间重复访问的限制,失败任务占比一度突破 40%。

09:15 —— 代理池也被挤压

Serverless 扩容是瞬间并发,但代理出口带宽、并发连接数、可分配 IP 资源却不是无限的。结果就是:部分请求卡在 TLS 认证,部分 IP 被限制访问,还有部分请求压根没排到出口。

10:00 —— 临时降载 + 补偿机制上线

通过降低并发上限、增加延迟、启用备用代理池,任务逐渐恢复正常。这次事故让我们重新审视了“Serverless + 浏览器爬虫”这一组合的现实挑战。

问题到底出在哪里?

总结下来,问题不是某一块技术失效,而是多层叠加导致的连锁反应。

1. 冷启动是核心问题

浏览器环境不是轻量级脚本,Playwright 或 Chromium 启动本身就需要时间,而 Serverless 容器生命周期短,不可复用,导致初始化成本被无限放大。

2. 并发不是免费资源

Serverless 的扩容能力很强,但:

* 目标网站有限流

* 代理池有限并发

* 数据写入管道有限速

换句话说,外部环境不支持你无限扩容。

3. 可观测性差

传统服务器可跟踪进程状态,Serverless 则是一次性实例,排查日志需要聚合和关联分析。故障定位难度提升。

4. 反爬策略敏感度提高

知乎对高频访问的敏感度不低,而 Serverless 容易形成短时间分布式并发峰值,这种流量特征更接近异常行为。

那怎么优化?

把 Serverless 用好,不是简单迁移,而是要改造架构,让它适配运行方式。

我们做了下面这些调整:

问题

解决方向

冷启动太慢

使用 Browserless/Playwright Remote,让浏览器不随实例重复启动

并发压缩代理池

设计访问调度器,控制速率并动态轮换 IP

网络波动导致超时

增加重试规则、指数退避策略、任务补偿

监控碎片化

引入链路追踪与日志聚合

被目标站点识别为机器人

增加行为随机化策略、UA池、Cookie池

最终架构不再是“Serverless 单兵作战”,而是“调度层 + 执行层 + 浏览器服务 + 代理管理”。

示例代码: Serverless 爬虫核心逻辑

下面是教学示例,重点展示代理设置、UA 处理以及 Playwright 搜索逻辑。

"""

示例:Playwright + 代理 + 随机 UA

目标站点:知乎搜索页

注意:此代码用于技术研究,不用于违规用途

"""

import asyncio

import random

from playwright.async_api import async_playwright

# === 代理配置(替换为你自己的亿牛云代理账号信息 www.16yun.cn) ===

PROXY = {

    "server": "http://proxy.16yun.cn:12345",

    "username": "your_username",

    "password": "your_password"

}

# User-Agent 池,避免每次访问特征一致

UA_LIST = [

    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36",

    "Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/605.1.15 Safari/605.1.15"

]

async def crawl(keyword: str):

    playwright = await async_playwright().start()

    browser = await playwright.chromium.launch(

        headless=True,

        args=["--disable-blink-features=AutomationControlled"]

    )

    # 使用代理 + 随机 UA

    context = await browser.new_context(

        proxy=PROXY,

        user_agent=random.choice(UA_LIST)

    )

    page = await context.new_page()

    await page.goto(f"https://www.zhihu.com/search?q={keyword}", timeout=15000)

    await page.wait_for_selector("div.SearchResult-Card")

    cards = await page.query_selector_all("div.SearchResult-Card")

    results = []

    for c in cards[:3]:

        title = await c.inner_text()

        results.append(title)

    await browser.close()

    await playwright.stop()

    return results

if __name__ == "__main__":

    print(asyncio.run(crawl("AI 爬虫")))

最后的结论

Serverless 不是爬虫的终极答案,但它绝不是一个伪需求。对于任务周期性、流量波动明显、不需要 24 小时在线运行的采集系统,它依然有很高价值。

但要让它能跑稳,我们必须接受一个现实:

Serverless 不是“把脚本丢进去就能飞”的万能模型,而是需要配合浏览器常驻服务、访问调度器、代理策略和缓存体系,才能真正发挥优势。

换句话说,Serverless 爬虫能走多远,不取决于云服务,而取决于架构是否适配它的运行逻辑。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容