ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

async-sema 爬虫并发控制实战:如何稳定抓取 10 万条数据而不触发限流

async-sema 爬虫并发控制实战:如何稳定抓取 10 万条数据而不触发限流 async-sema 爬虫并发控制实战如何稳定抓取 10 万条数据而不触发限流【免费下载链接】async-semaSemaphore using async and await项目地址: https://gitcode.com/gh_mirrors/as/async-sema写爬虫最头疼的事情之一不是反爬虫机制而是被自己爬挂——一次性发出上千个并发请求网站立刻触发限流、封禁 IP任务直接报废。async-sema 正是解决这个问题的轻量级神器一个基于async和await的信号量Semaphore实现让你用短短几行代码就把 Node.js 爬虫的并发数量牢牢控制在安全范围之内。本文是一篇面向新手的爬虫并发控制实战教程手把手教你用 async-sema 稳定抓取 10 万条数据而不触发限流全程干货、代码量极少读完就能直接上手。为什么你的爬虫总是触发限流先搞懂并发失控的后果很多新手写爬虫时会这样写把 10 万条 URL 全部扔进Promise.all让它们一拥而上。结果往往是症状原因返回 429 / 403同一秒内请求太多触发网站限流IP 被封禁高频请求被识别为恶意爬虫内存暴涨、进程崩溃同时挂起上万个 Promise内存被拖垮数据库连接耗尽写入并发太高连接池瞬间打满问题的本质是没有控制并发数。服务器能接受的并发是有限的而你的代码却在无限并发。解决办法就是引入信号量——让最多 N 个任务同时执行其余任务排队等待。async-sema 是什么为什么爬虫并发控制首选它async-sema 是一个专为async/await设计的信号量库核心优势非常突出轻量零依赖整个核心实现只有 src/index.ts 一个文件安装后几乎不增加包体积严格信号量语义区别于社区里常见的最后统一同步写法它真正做到了同一时刻只有 N 个任务在跑其余排队等待内置限流器除了信号量还附带RateLimit一库两用。它的 API 极其精简核心只有Sema类和RateLimit函数两个出口新手 10 分钟就能掌握全部用法。快速上手async-sema 一键安装步骤安装非常简单任选一种包管理器即可npm install --save async-semayarn add async-sema安装完成后在你的爬虫项目里引入即可const { Sema, RateLimit } require(async-sema);爬虫并发控制核心用法用 Sema 限制并发数信号量的使用模式固定为三步acquire取令牌→ 干活 → release还令牌。下面是一个并发上限为 4 的经典示例const s new Sema(4); // 最多 4 个任务同时执行 async function fetchPage(url) { await s.acquire(); // 1. 取令牌没位置就排队等 try { // 2. 在这里发请求、存数据…… await axios.get(url); } finally { s.release(); // 3. 无论成败finally 里还令牌 } } const data await Promise.all(urls.map(fetchPage));几个要点务必牢记✅release一定要放在finally中否则请求报错会导致令牌丢失信号量越用越少最终卡死✅ 并发数new Sema(n)中的 n建议设为510既能保证抓取速度又不容易触发限流✅ 想实时观察排队情况用s.nrWaiting()查看当前有多少任务在等待方便调试。如何避免触发网站限流配合 RateLimit 精确控速有些网站不看并发数而是看每秒请求数QPS。这时候就要动用 async-sema 内置的RateLimit限流器了const lim RateLimit(5); // 每秒最多 5 个请求 async function fetchPage(url) { await lim(); // 超速先等着等窗口放行 // ... 发送请求 }RateLimit 还支持两个实用参数参数作用适用场景timeUnit设置限流窗口宽度毫秒默认 1000想按每分钟 N 次限速时设为60 * 1000uniformDistribution让请求在窗口内均匀分布而不是瞬间打满再干等持续不间断地读文件、发请求的高频场景 实战建议并发控制 限流器双管齐下。用Sema限制同时在飞的请求数用RateLimit限制每秒请求数双保险几乎不会触发限流。内存优化技巧capacity 预分配与 pauseFn 暂停恢复抓 10 万条数据时如果 URL 是一次性全部读入内存Promise 会堆积如山。async-sema 为此提供了两个高级功能1️⃣ capacity预分配等待队列如果你能估算出并发任务的大致规模可以在构造时指定容量避免运行期反复扩容const s new Sema(8, { capacity: 10000 });2️⃣ pauseFn / resumeFn暂停数据流入当排队任务过多时暂停数据源比如暂停读取文件流等有位置了再恢复。完整的示例可以参考 examples/pausing.js核心写法如下const s new Sema(5, { pauseFn: () readline.pause(), // 排队满了暂停流入 resumeFn: () readline.resume() // 有位置了恢复流入 });⚠️ 注意pauseFn和resumeFn必须成对声明否则会直接报错。实战演练稳定抓取 10 万条数据的完整流程下面把前面所有知识点串起来形成一套可直接落地的抓取方案数据分片把 10 万条 URL 按每批 1000 条分批读取避免一次性占满内存并发限流创建new Sema(8)控制并发配合RateLimit(20)控制每秒请求数失败重试捕获请求异常记录失败 URL最后统一重试 3 次分批落库每抓完一批就批量写入数据库防止连接池耗尽优雅退出任务结束后调用await s.drain()排空所有令牌确认没有遗留任务再退出进程参考 examples/pooling.js 的资源回收思路。按这套流程10 万条数据的抓取全程平平稳稳不会出现一次限流、一个封禁速度还比梭哈式写法慢不了多少。常见问题排查FAQQ1明明限制了并发为什么还是被限流A可能是每秒请求数超了试试叠加RateLimit也可能是需要随机延时 随机 User-Agent让请求更像真人。Q2程序跑着跑着卡死了nrWaiting()数字一直不变A多半是某个请求抛错后没走finally令牌泄漏了。检查所有release是否都放在了finally里。Q3tryAcquire()是干嘛的A非阻塞地尝试获取令牌拿到就返回拿不到立刻返回undefined适合用来做能抓就抓、不能就跳过的弹性逻辑。Q4想复用数据库连接池这类资源怎么办A使用initFn初始化令牌让信号量直接管理真实资源见 examples/pooling.js 中管理 Redis 连接的写法。总结爬虫并发控制并不神秘限制并发数 控制请求速率 做好异常兜底这三点做到位10 万条数据就是轻松活。async-sema 体积小、API 简单、语义严格是 Node.js 爬虫控制并发的理想选择。现在就装上它给你的爬虫加一道安全阀吧【免费下载链接】async-semaSemaphore using async and await项目地址: https://gitcode.com/gh_mirrors/as/async-sema创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表