
——从一次冷启动事故开始谈
如果说过去的爬虫架构像一辆固定路线的公交车,那么 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 爬虫能走多远,不取决于云服务,而取决于架构是否适配它的运行逻辑。