并发拉满后,抓取反而变慢?我踩了这个坑

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 本文分享了一次使用高并发与代理池爬取头条新闻热点数据的实战经验,深入剖析了因并发控制不当导致的数据抓取效率低下的问题,并提供了具体的优化方案与完整代码实现。

爬虫代理

1. 事情是这样开始的

上周临时接了个需求,要从某新闻站(https://www.toutiao.com)抓一波热点数据。
想着时间紧,就直接上了 高并发 + 代理池 ,心里还美滋滋地觉得这速度肯定飞起。 结果——上线一小时,发现数据量只有预期的 40%,延迟还奇高。

2. 排查过程(时间线)

Day 1 晚上
先怀疑代理 IP 不行,跑去看了下日志,嗯…成功率其实还可以,80% 左右。那问题不在代理质量。

Day 2 早上
继续翻日志,发现一些代理节点被用得特别狠,同一个 IP 同时跑了十几二十个请求,直接被目标站点限速,甚至封禁。
而有些代理就几乎没用上——这就很尴尬了。

Day 3 中午
确认了,罪魁祸首就是:全局并发没有限速 + 单 IP 并发没控制
加上失败后无脑重试,把带宽和 CPU 都消耗掉了。


3. 问题拆解

  1. 并发太猛,全局频率高到触发目标站限速。
  2. 单个代理 IP 压力过大,封了一个就拖一大片任务。
  3. 没有实时监控,出问题了也只能靠翻日志找线索。

4. 解决思路

  • 全局限速:用信号量限制任务总并发数。
  • 单节点限速:每个代理 IP 自己的并发阈值,超了就排队。
  • 失败退避:不要一秒一个重试,用指数退避,慢慢来。
  • 加点监控:用 tqdm 做个进度条,任务数一眼能看,抓完顺手输出节点健康状态。
  • 自动分析热点:爬到的标题直接做关键词统计,省得人工数。

5. 优化后代码(精简版)

import asyncio, random, re
from collections import Counter, defaultdict
from playwright.async_api import async_playwright
from tqdm.asyncio import tqdm_asyncio
#爬虫代理设置(亿牛云示例)
PROXIES = [{
   "host":"proxy.16yun.cn","port":10000,"user":"16YUN","pass":"16IP"}]
KEYWORDS = ["人工智能", "芯片", "特斯拉", "东京奥运"]

MAX_TOTAL, MAX_PER_PROXY = 6, 3
total_sem = asyncio.Semaphore(MAX_TOTAL)
proxy_sem = {
   i: asyncio.Semaphore(MAX_PER_PROXY) for i in range(len(PROXIES))}
proxy_stats = defaultdict(lambda: {
   "success": 0, "fail": 0})

def extract_words(titles):
    return re.findall(r"[\u4e00-\u9fa5]{2,}", " ".join(titles))

async def fetch_page(page, keyword):
    await page.goto(f"https://m.toutiao.com/search/?keyword={keyword}", timeout=15000)
    return [await el.inner_text() for el in await page.query_selector_all("div.result-item .title")]

async def worker(browser, proxy_idx, kw):
    proxy = PROXIES[proxy_idx]
    async with proxy_sem[proxy_idx], total_sem:
        ctx = await browser.new_context(proxy={
   
            "server": f"http://{proxy['host']}:{proxy['port']}",
            "username": proxy['user'],
            "password": proxy['pass']
        })
        page = await ctx.new_page()
        await asyncio.sleep(random.uniform(0.3, 1.0))
        for attempt in range(4):
            try:
                data = await fetch_page(page, kw)
                proxy_stats[proxy_idx]["success"] += 1
                await ctx.close()
                return data
            except:
                proxy_stats[proxy_idx]["fail"] += 1
                await asyncio.sleep((2 ** attempt) + random.random())
        await ctx.close()
        return []

async def main():
    async with async_playwright() as pw:
        browser = await pw.chromium.launch(headless=True)
        tasks = [worker(browser, i % len(PROXIES), kw) for i, kw in enumerate(KEYWORDS)]
        results = await tqdm_asyncio.gather(*tasks, desc="抓取进度", total=len(tasks))
        await browser.close()

        print("\n节点健康报告:")
        for idx, stat in proxy_stats.items():
            total_req = stat["success"] + stat["fail"]
            rate = (stat["success"] / total_req * 100) if total_req else 0
            print(f"节点 {idx}: 成功 {stat['success']} 次, 失败 {stat['fail']} 次, 成功率 {rate:.2f}%")

        print("\n热点关键词:")
        for word, count in Counter(extract_words([t for res in results for t in res])).most_common(10):
            print(f"{word} - {count} 次")

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

6. 优化效果

  • 成功率从 60% 提到了 85%+
  • 单节点没再被打爆
  • 热点数据直接生成,拿去分析就行

7. 最后感想

这事儿让我记住一句话:
并发不是越高越好,控制好节奏才是王道
特别是有限制的站点,猛冲只会给自己挖坑。
相关文章
|
4月前
|
人工智能 并行计算 API
全网最全的GPT-5测评文章!1.8万字详细实战测评!国内直接使用!
OpenAI 发布了期待已久的 GPT-5,其在数学、编程、视觉理解和健康等领域表现卓越,推理能力媲美 Gemini 2.5 Pro,代码能力媲美 Claude 4。GPT-5 与 GPT-5-thinking 双模型协同工作,带来更高效体验。国内用户可通过指定平台直接访问,提供免费授权码体验。
751 0
|
消息中间件 Java API
RocketMQ事务消息, 图文、源码学习探究~
介绍 RocketMQ是阿里巴巴开源的分布式消息中间件,它是一个高性能、低延迟、可靠的消息队列系统,用于在分布式系统中进行异步通信。 从4.3.0版本开始正式支持分布式事务消息~ RocketMq事务消息支持最终一致性:在普通消息基础上,支持二阶段的提交能力。将二阶段提交和本地事务绑定,实现全局提交结果的一致性。 原理、流程 本质上RocketMq的事务能力是基于二阶段提交来实现的 在消息发送上,将二阶段提交与本地事务绑定 本地事务执行成功,则事务消息成功,可以交由Consumer消费 本地事务执行失败,则事务消息失败,Consumer无法消费 但是,RocketMq只能保证本地事务
|
4月前
|
JSON API 数据格式
京东商品评论API秘籍!轻松获取商品评论数据
京东商品评论API是京东开放平台提供的数据接口,支持按商品ID获取评论,具备分页、评分筛选、排序等功能,适用于电商数据分析与用户反馈收集。接口采用HTTPS请求,数据格式为JSON,具备高并发处理能力。附Python请求示例代码,便于开发者快速集成。
|
关系型数据库 数据挖掘 分布式数据库
数据库+MCP,0编码自主完成数据洞察
本文介绍了一种全新的数据分析方案,结合PolarDB MySQL版与阿里云百炼,搭配MCP工具实现智能数据库分析应用。该方案解决传统数据分析工具高门槛、低效率的问题,通过零SQL操作和一站式部署,助力企业快速挖掘数据价值。方案具备高性能查询、快响应直连加速、高安全保障及易迁移上云等优势,并详细说明了部署资源、应用配置及验证步骤,帮助用户轻松完成实践体验。
1454 15
|
5月前
|
机器学习/深度学习 自然语言处理 搜索推荐
搜索结果太乱?5种重排序模型让你的搜索系统准确率提升40%
本文将系统性地分析重排序模型的技术原理,深入探讨从传统学习排序方法到基于Transformer架构的前沿解决方案。
564 0
搜索结果太乱?5种重排序模型让你的搜索系统准确率提升40%
|
4月前
|
机器学习/深度学习 存储 分布式计算
Java 大视界 --Java 大数据机器学习模型在金融风险压力测试中的应用与验证(211)
本文探讨了Java大数据与机器学习模型在金融风险压力测试中的创新应用。通过多源数据采集、模型构建与优化,结合随机森林、LSTM等算法,实现信用风险动态评估、市场极端场景模拟与操作风险预警。案例分析展示了花旗银行与蚂蚁集团的智能风控实践,验证了技术在提升风险识别效率与降低金融风险损失方面的显著成效。
|
7月前
|
网络安全 开发工具 git
Git仓库创建与代码上传指南
本教程介绍了将本地项目推送到远程Git仓库的完整流程,包括初始化本地仓库、添加和提交文件、创建远程仓库、关联远程地址及推送代码。同时,还提供了`.gitignore`配置、分支管理等可选步骤,并针对常见问题(如认证失败、分支不匹配、大文件处理及推送冲突)给出了解决方案。适合初学者快速上手Git版本控制。