基于Requests的脚本中使用生成器优化性能的方法咨询
网络请求脚本优化:生成器的作用与实际提速方案
生成器能直接让脚本变快吗?
不能。你的脚本耗时超24小时,核心瓶颈是网络IO等待——每个GET请求都要等远程设备响应,这部分时间生成器帮不了你。生成器的优势是节省内存、延迟加载,适合处理超大URL列表(比如CSV有几十万条),避免一次性把所有URL加载到内存里导致内存溢出,但它不会减少网络请求的等待时间。
不过生成器可以和并发处理结合,让脚本的资源利用更高效,间接提升整体运行效率。
怎么把生成器用到你的脚本里?
先写一个生成器函数来读取CSV里的URL,代替一次性把所有URL读成列表:
import csv def url_generator(csv_path): # 逐行读取CSV,每次只生成一个URL,内存占用极低 with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.reader(f) next(reader) # 跳过表头(如果CSV有表头的话) for row in reader: # 假设URL在CSV的第一列,根据你的实际格式调整索引 yield row[0].strip()
之后你就可以用for url in url_generator("your_urls.csv")来遍历所有URL,不用一次性加载全部数据到内存。
真正提速的关键:并发处理网络请求
既然瓶颈是网络等待,就要同时发送多个请求,用多线程或异步IO来利用等待时间做其他请求。下面是两种实用方案:
方案1:Requests + 线程池(简单易上手)
适合大多数场景,线程池专门处理IO密集型任务:
import requests import concurrent.futures import json def fetch_and_save(url): try: # 发送请求,设置超时避免无限等待 resp = requests.get(url, timeout=30) resp.raise_for_status() # 捕获HTTP错误 # 生成文件名,避免特殊字符问题 filename = f"{url.replace('://', '_').replace('/', '_').replace(':', '')}.json" # 保存JSON(如果是XML,改成对应的解析和保存逻辑) with open(filename, 'w', encoding='utf-8') as f: json.dump(resp.json(), f, indent=2) print(f"Successfully saved: {url}") except Exception as e: print(f"Failed to fetch {url}: {str(e)}") if __name__ == "__main__": csv_path = "your_urls.csv" # 用生成器提供URL url_gen = url_generator(csv_path) # 线程池大小:根据你的网络带宽和设备承受能力调整,建议20-50 with concurrent.futures.ThreadPoolExecutor(max_workers=30) as executor: # 批量提交任务,生成器会逐个供给URL executor.map(fetch_and_save, url_gen)
方案2:Aiohttp异步IO(更高性能)
如果URL数量特别多,异步IO的效率比线程池更高:
import aiohttp import asyncio import csv import json async def fetch_and_save(session, url): try: async with session.get(url, timeout=30) as resp: resp.raise_for_status() data = await resp.json() filename = f"{url.replace('://', '_').replace('/', '_').replace(':', '')}.json" with open(filename, 'w', encoding='utf-8') as f: json.dump(data, f, indent=2) print(f"Successfully saved: {url}") except Exception as e: print(f"Failed to fetch {url}: {str(e)}") async def main(csv_path): url_gen = url_generator(csv_path) # 创建异步会话 async with aiohttp.ClientSession() as session: # 生成所有异步任务 tasks = [fetch_and_save(session, url) for url in url_gen] # 等待所有任务完成 await asyncio.gather(*tasks) if __name__ == "__main__": csv_path = "your_urls.csv" asyncio.run(main(csv_path))
额外优化细节
- 重试机制:给请求加重试,比如用
tenacity库,避免因临时网络故障导致失败 - 限流:如果设备有请求频率限制,要控制并发数或加延迟,避免被拉黑
- 批量处理:如果设备API支持批量请求,尽量合并请求,减少总请求次数
- 日志记录:把失败的URL记录到文件,方便后续重跑
内容的提问来源于stack exchange,提问作者Rudy Gee
相关产品推荐
相关产品推荐

