Python网络爬虫的效率提升需要从请求、并发、数据处理、反爬适配等多个环节入手,合理的优化方案能让爬虫的采集速度提升数倍甚至数十倍,同时降低运行过程中的资源消耗和被封禁风险。

一、优化请求方式减少无效耗时
请求环节是爬虫最基础的耗时点,优化请求方式能直接减少单个请求的等待时间。
1. 使用会话保持减少连接开销
默认的requests请求每次都会新建TCP连接,使用Session对象可以复用连接,减少握手耗时。
import requests
# 创建会话对象
session = requests.Session()
# 设置通用请求头,避免重复配置
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
})
# 复用会话发起请求
response1 = session.get("https://ipipp.com/api/data1")
response2 = session.get("https://ipipp.com/api/data2")
2. 设置合理的超时和重试机制
避免单个请求卡住导致整个爬虫阻塞,同时减少因网络波动导致的无效请求。
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import requests
session = requests.Session()
# 配置重试策略:总重试3次,重试间隔0.5秒,重试状态码为500/502/503/504
retry_strategy = Retry(
total=3,
backoff_factor=0.5,
status_forcelist=[500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
# 设置超时时间:连接超时3秒,读取超时10秒
try:
response = session.get("https://ipipp.com/api/target", timeout=(3, 10))
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
二、选择适配的并发方案提升吞吐量
单线程爬虫的采集效率极低,根据爬虫任务的特点选择合适的并发方案,能大幅提升单位时间内的请求数量。
1. IO密集型任务用异步请求
网络请求属于IO密集型操作,使用aiohttp配合asyncio可以单线程实现高并发,资源占用远低于多线程。
import asyncio
import aiohttp
async def fetch(session, url):
# 异步发起请求
async with session.get(url) as response:
return await response.text()
async def main(urls):
# 创建异步会话
async with aiohttp.ClientSession() as session:
# 创建所有请求任务
tasks = [fetch(session, url) for url in urls]
# 并发执行所有任务
results = await asyncio.gather(*tasks)
return results
if __name__ == "__main__":
urls = [
"https://ipipp.com/api/page1",
"https://ipipp.com/api/page2",
"https://ipipp.com/api/page3"
]
# 运行异步主函数
data_list = asyncio.run(main(urls))
print(f"共获取{len(data_list)}条数据")
2. 混合任务用进程池+线程池
如果爬虫同时包含大量数据解析等CPU密集型操作,可以结合进程池处理CPU任务,线程池处理IO请求。
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import requests
def fetch_url(url):
# 线程池处理请求任务
response = requests.get(url, timeout=5)
return response.text
def parse_data(html):
# 进程池处理数据解析任务
# 这里模拟解析逻辑
return html[:100]
if __name__ == "__main__":
urls = [f"https://ipipp.com/api/page{i}" for i in range(1, 11)]
# 线程池并发请求,最大线程数10
with ThreadPoolExecutor(max_workers=10) as thread_pool:
html_results = list(thread_pool.map(fetch_url, urls))
# 进程池并发解析,最大进程数4
with ProcessPoolExecutor(max_workers=4) as process_pool:
parse_results = list(process_pool.map(parse_data, html_results))
print(f"解析完成{len(parse_results)}条数据")
三、优化数据处理环节减少阻塞
数据采集后的处理环节如果设计不合理,也会成为效率瓶颈。
1. 使用生成器减少内存占用
如果不需要同时保存所有采集到的数据,使用生成器逐条产出数据,避免大量数据积压占用内存。
def data_generator(urls):
import requests
for url in urls:
response = requests.get(url, timeout=5)
# 逐条返回数据,不全部存入内存
yield response.json()
if __name__ == "__main__":
urls = [f"https://ipipp.com/api/item{i}" for i in range(1, 101)]
# 遍历生成器处理数据
for data in data_generator(urls):
# 这里可以做入库或本地保存操作
print(f"处理数据: {data.get('id')}")
2. 批量操作降低IO次数
如果采集的数据需要存入数据库,尽量批量写入,避免单条插入的频繁IO操作。
import pymysql
import requests
# 批量插入数据到MySQL
def batch_insert_data(data_list):
conn = pymysql.connect(
host="127.0.0.1",
user="root",
password="123456",
database="spider_db",
charset="utf8mb4"
)
cursor = conn.cursor()
# 拼接批量插入SQL
sql = "INSERT INTO spider_data (title, content) VALUES (%s, %s)"
# 一次插入多条数据
cursor.executemany(sql, data_list)
conn.commit()
cursor.close()
conn.close()
if __name__ == "__main__":
# 先采集一批数据
data_list = []
for i in range(10):
response = requests.get(f"https://ipipp.com/api/detail{i}")
item = response.json()
data_list.append((item["title"], item["content"]))
# 批量插入
batch_insert_data(data_list)
四、适配反爬策略降低封禁概率
频繁被目标网站封禁会导致爬虫频繁中断,反而降低整体效率,合理的反爬适配能减少不必要的重试耗时。
1. 随机化请求特征
避免固定的请求头和访问频率,模拟真实用户的访问行为。
import random
import time
import requests
user_agent_list = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15",
"Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"
]
def safe_fetch(url):
# 随机选取User-Agent
headers = {"User-Agent": random.choice(user_agent_list)}
# 随机等待1-3秒,模拟真实访问间隔
time.sleep(random.uniform(1, 3))
response = requests.get(url, headers=headers, timeout=5)
return response
if __name__ == "__main__":
for i in range(5):
data = safe_fetch(f"https://ipipp.com/api/list{i}")
print(f"第{i+1}次请求完成")
2. 使用代理池分散请求来源
当采集量大时,使用代理池轮换IP,避免单个IP请求过于频繁被封禁。
import random
import requests
proxy_pool = [
"http://192.168.0.1:8080",
"http://192.168.0.2:8080",
"http://127.0.0.1:8081"
]
def fetch_with_proxy(url):
# 随机选取代理
proxy = random.choice(proxy_pool)
proxies = {
"http": proxy,
"https": proxy
}
try:
response = requests.get(url, proxies=proxies, timeout=5)
return response
except Exception as e:
print(f"代理{proxy}请求失败: {e}")
return None
if __name__ == "__main__":
response = fetch_with_proxy("https://ipipp.com/api/target")
if response:
print("请求成功")
五、效率优化注意事项
优化爬虫效率时需要平衡速度和稳定性,不要盲目追求高并发:
- 目标网站有明确的反爬限制时,不要超过其允许的请求频率,避免承担法律责任
- 并发数量需要根据自身网络带宽和目标服务器的承载能力调整,过高的并发可能导致自身网络阻塞
- 定期监控爬虫运行状态,及时清理无效代理和异常请求,避免资源浪费
通过以上多个环节的合理优化,Python网络爬虫的采集效率可以得到显著提升,同时运行稳定性和资源利用率也会得到改善。