Scrapling StealthySession 如何用 max_pages 控制浏览器标签池并发抓取多页面
用 Scrapling 的 StealthySession/AsyncStealthySession 抓取多个页面时,默认所有请求会串行地复用同一个浏览器标签页。如果你的目标是让多个 URL 在同一个浏览器实例中同时抓取、用有限的标签页资源换取更高吞吐,可以依赖 max_pages 参数:它限制同一时刻最多打开的标签页数,Scrapling 内部会维护一个轮换的标签池(rotating pool of Browser tabs),在标签释放后为新请求开新标签。下面给出从安装到并发抓取、再到查看标签池状态的完整操作路径。
准备条件
Scrapling 要求 Python 3.10 或更高版本。基础安装只包含解析引擎,导入 scrapling.fetchers 会抛 ModuleNotFoundError,所以必须额外安装 fetchers 依赖并下载浏览器:
pip install "scrapling[fetchers]"
scrapling install # normal install
scrapling install --force # force reinstall
scrapling install 会下载所有浏览器及其系统依赖和指纹操作依赖;如果已经装过可以不加 --force 重跑。
标签池的工作机制
设置 max_pages=N 后,每次请求时 Scrapling 会先关闭已完成任务的标签,再检查当前标签数是否低于 N,然后:
- 如果还在允许范围内,直接创建新标签,流程与单标签时一致;
- 如果已达上限,它会以亚秒级频率持续检查是否可以开新标签,最长等待 60 秒;超时后抛出
TimeoutError——这种情况通常出现在被抓取网站卡死、页面迟迟不结束时。
这套逻辑让多个 URL 能在同一个浏览器里同时抓取,文档强调它节省资源且速度很快。注意版本背景:0.3 和 0.3.1 版本中池子曾复用已完成的标签以省资源,但作者认为该逻辑有缺陷(标签难以避免被上一个请求的配置污染),因此新版本采用"用完关闭、再开新标签"的方式。
并发抓取多个页面
并发场景使用 AsyncStealthySession,配合 asyncio.gather 发起多个请求。下面的示例来自 StealthyFetcher 文档:
import asyncio
from scrapling.fetchers import AsyncStealthySession
async def scrape_multiple_sites():
async with AsyncStealthySession(
real_chrome=True,
block_webrtc=True,
solve_cloudflare=True,
timeout=60000, # 60 seconds for Cloudflare challenges
max_pages=3
) as session:
# Make async requests with shared browser configuration
pages = await asyncio.gather(
session.fetch('https://site1.com'),
session.fetch('https://site2.com'),
session.fetch('https://protected-site.com')
)
return pages
把三个 URL 换成你要抓取的目标页面即可。几个参数的适用条件:
max_pages=3:本例中同时发起 3 个请求,标签池上限设为 3,任意请求结束释放标签后,新请求可以立刻拿到新标签。timeout=60000:所有页面操作和等待使用的超时(毫秒),默认 30,000 ms。如果启用了solve_cloudflare,文档要求超时至少 60 秒,给挑战留出足够的解决时间,本例正是这么设置的。real_chrome=True:使用本机已安装的 Chrome 实例,按需开启;不开则用内置浏览器。
README 中还有一个更紧凑的写法,用任务列表循环提交请求,适合 URL 来自列表的场景:
import asyncio
from scrapling.fetchers import AsyncStealthySession
async with AsyncStealthySession(max_pages=2) as session:
tasks = []
urls = ['https://example.com/page1', 'https://example.com/page2']
for url in urls:
task = session.fetch(url)
tasks.append(task)
print(session.get_pool_stats()) # Optional - The status of the browser tabs pool (busy/free/error)
results = await asyncio.gather(*tasks)
print(session.get_pool_stats())
max_pages 也可以直接传给同步的 StealthySession(浏览器控制器层对同步/异步会话都支持该参数),但文档中给出的并发示例都是异步版本,推荐按上面的路径操作。
结果验证
asyncio.gather返回的pages是一个Response对象列表,每个元素对应一个请求,可以像文档其他部分那样用 CSS/XPath 提取内容。session.get_pool_stats()返回标签池当前状态(文档标注为 busy/free/error),可以在gather前后各打印一次,观察标签从被占用到全部释放的过程。- 失败现象按文档判断:如果某个目标网站无响应导致标签一直被占用,其他请求会等待标签释放,等待满 60 秒后抛出
TimeoutError。此时应检查该 URL 是否卡死、是否把timeout调大或给该请求单独设置等待条件(wait_selector等)。
限制与边界
- 标签池上限只决定并发度,不决定总耗时:并发数超过
max_pages的请求会排队等待标签释放。 - 0.3/0.3.1 之前版本会复用已完成标签,当前版本不复用,避免标签被上一个请求的配置污染,这是有意为之的行为变化。
- 会话级配置对整个会话生效,个别请求仍可按标签级别覆盖
timeout、wait、page_action、extra_headers、wait_selector、proxy等参数(完整列表见 StealthyFetcher 文档的参数表)。 StealthySession建立在DynamicSession之上,参数和行为细节可对照 DynamicFetcher 文档 的 Session Management 一节,两处的max_pages说明一致。
完成以上步骤后,你可以按目标网站的响应速度调整 max_pages:URL 数较多且站点响应正常时提高上限,站点响应慢或出现 TimeoutError 时降低上限并配合 timeout/wait_selector 调整每个标签的等待策略。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00