当前位置: 首页 > news >正文

Python爬虫实战:多线程与异步IO并发爬虫——从10倍到100倍提速

一、为什么你的爬虫那么慢?

很多新手写完爬虫后都会遇到同一个问题:单线程爬虫太慢了

你写了一个爬虫,抓取1000个页面要花30分钟。老板说"明天要这些数据",你直接加班到凌晨。

问题出在哪?看这个对比:

方式1000个页面耗时提升倍数
单线程顺序请求500秒(8分钟)1x
多线程(10线程)55秒9x
多线程(50线程)15秒33x
异步aiohttp(100并发)8秒62x
异步+连接池(200并发)5秒100x

原因很简单:大部分时间爬虫都在等待服务器响应。网络请求的瓶颈不是你的CPU,而是IO等待。单线程时,发一个请求后程序就傻等,等服务器回数据了再发下一个——这期间CPU完全空闲。

并发爬虫的核心思想就是:在等待网络响应的时候,同时发起更多请求


二、最简单的提速:threading多线程

先看一个单线程爬虫的典型写法:

import requests import time def crawl(url): resp = requests.get(url) return resp.status_code urls = [f"https://httpbin.org/get?id={i}" for i in range(100)] start = time.time() for url in urls: crawl(url) print(f"单线程耗时: {time.time()-start:.2f}秒")

改成多线程,只需加几行代码:

import requests import time from concurrent.futures import ThreadPoolExecutor, as_completed def crawl(url): resp = requests.get(url, timeout=10) return url, resp.status_code urls = [f"https://httpbin.org/get?id={i}" for i in range(100)] # ========== 多线程版本 ========== start = time.time() with ThreadPoolExecutor(max_workers=20) as executor: futures = {executor.submit(crawl, url): url for url in urls} for future in as_completed(futures): url, status = future.result() print(f"{url} -> {status}") print(f"多线程耗时: {time.time()-start:.2f}秒")

ThreadPoolExecutor 是Python标准库提供的线程池,核心参数就一个:max_workers——同时运行的线程数。

线程数怎么选?

  • IO密集型任务(爬虫大部分情况):20-100 线程
  • CPU密集型任务(数据解析如果很复杂):CPU核心数 × 2
  • 目标服务器较弱时:降低线程数,避免被封

三、多线程爬虫完整实战:批量采集新闻资讯

import requests import time import random import threading from concurrent.futures import ThreadPoolExecutor, as_completed from bs4 import BeautifulSoup import json import os class ConcurrentNewsCrawler: """多线程并发新闻采集器""" def __init__(self, max_workers=20): self.max_workers = max_workers self.results = [] self.lock = threading.Lock() self.session = requests.Session() # 随机UA列表 self.user_agents = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36", ] def get_headers(self): """生成随机请求头""" return { "User-Agent": random.choice(self.user_agents), "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", } def crawl_page(self, url): """抓取单个页面""" try: resp = self.session.get( url, headers=self.get_headers(), timeout=15, ) resp.raise_for_status() resp.encoding = resp.apparent_encoding soup = BeautifulSoup(resp.text, "html.parser") # 提取文章信息(根据实际网站结构调整选择器) item = { "url": url, "title": self._extract_title(soup),
http://www.jsqmd.com/news/1134947/

相关文章:

  • MediaCrawler-new:多平台社交媒体数据采集技术框架与自动化解决方案
  • ICM-42688-P与PIC24HJ256GP610在运动控制中的高效协同
  • 城市违章搭建识别、棚户区语义分割与YOLO格式数据集:基于深度学习的城市治理AI实践全解析10693期
  • 《从 300 行到 30 万行代码,我学到的 5 个重构教训》
  • 5分钟找回QQ空间全部历史说说的终极指南:GetQzonehistory帮你永久保存青春记忆
  • 好用的区域教育一体化管理平台哪个供应商好
  • Google谷歌浏览器 Chrome浏览器安装包 官方正版离线安装包,支持中文界面!
  • 【Redis八股|第1篇】Redis 是什么?为什么它这么快?
  • 2026视频转文字工具选择指南:拆解免费付费坑点,看懂隐私、水印、收费套路避踩雷
  • AI生成图片文字模糊?AnyText技术原理与实战指南
  • 第48期 OpenAI的钱都花哪了?Capex支出全景调研
  • 一款AI笔记助手和远程同步的markdown笔记idea-note
  • 英雄联盟玩家必备:如何用LCU工具箱提升你的游戏效率3倍?
  • 质量管理必备的10个基本思维方式
  • 《夫人要和离》藤鹿山|小说|txt下载|番外|免费阅读
  • 38、<简单>编程输入10个正整数,然后自动按从大到小的顺序输出
  • 《被错认成道侣后》山野行月|小说|txt下载|全文
  • 【共创季稿事节】HarmonyOS 6.1 API23新特性实战:Marquee跑马灯组件进阶用法
  • 抖音无水印视频下载神器:从零开始掌握批量下载技巧
  • Grafana Dashboard JSON 文件详解
  • Java计算机毕设之基于前后端分离的病毒靶点药物关系数据采集系统的设计与实现 基于 SpringBoot 的生物医药多源数据采集与归档系统(完整前后端代码+说明文档+LW,调试定制等)
  • Driver Store Explorer:Windows驱动管理的终极解决方案,三步释放系统空间
  • ArcGIS Pro 3.2 遥感影像语义分割标签制作:矢量转栅格3大坐标系对齐要点
  • 刷写协议(TODO)
  • 用Go语言构建微服务后端的经验分享
  • 【Java课程设计/毕业设计】基于 SpringBoot+Vue 的博物馆票务台账管理系统的设计与实现 基于 SpringBoot 的数字化文博预约服务系统【附源码、数据库、万字文档】
  • ORB-SLAM3 实战部署:Ubuntu 20.04 + ROS Noetic 完整环境配置 5 步指南
  • ImageNet-1K 数据集 3 种下载方案对比:官网、网盘与 Hugging Face 速度实测
  • 多教师知识蒸馏3种加权策略剖析:CA-MKD置信度 vs 平均 vs 熵加权
  • 使用Let‘s Encrypt与Certbot为Nginx网站免费配置HTTPS及自动续期