如何优化基于requests库的XML转DataFrame代码执行速度?
性能优化方案
你的核心耗时完全集中在网络请求+XML解析步骤上(df = pd.read_xml(requests.get(url).text, xpath='//item')),以下是针对性的优化方法:
一、核心优化:并发请求网络资源
网络IO是典型的阻塞操作,串行请求会浪费大量等待时间,改用多线程并发请求可将总耗时压缩至接近单个请求的耗时(受限于目标服务器的并发限制)。
二、辅助优化点
- 直接传递
requests.get的字节响应给pd.read_xml,避免text转换的字符串开销 - 提前提取循环中的重复取值,减少字典索引的重复计算
- 简化进度条打印逻辑,减少IO操作
修改后的代码
import os import pandas as pd import requests from concurrent.futures import ThreadPoolExecutor, as_completed FILE_FORMAT = 'xml' CURRENT_DIR = os.path.abspath('') SAVE_DIR = os.path.join(CURRENT_DIR, 'report') REPORT = 'oo1' YEAR = '2022-2023' BASE_URL = 'sensetive_link' def create_source(file_name): df = pd.read_excel(f'{file_name}.xlsx', dtype=object) columns = df.columns.tolist() result = { school: df[item].dropna(how='all').tolist() for school, item in zip( columns, df ) } return result # 单独抽取处理单个URL的函数,方便并发调用 def process_single_url(url, school_id): try: resp = requests.get(url) resp.raise_for_status() # 主动抛出HTTP错误 df = pd.read_xml(resp.content, xpath='//item') # 直接用字节流,不用转text df['value'] = df['value'].astype('float64') df.index = [school_id] * len(df) return df except Exception as e: print(f"{url} 处理失败: {str(e)}") return None def download_xml_to_df_list(source_dict): df_list = [] fillers = { 'base_url': BASE_URL, 'year': YEAR, 'report': REPORT, 'file_format': FILE_FORMAT, } # 先预先生成所有需要处理的(url, school_id)对 tasks = [] for mouo, school_list in source_dict.items(): for school_id in school_list: url = ( '{base_url}/{year}ob/{report}/61/{mouo}/oo1_{school}.{file_format}' .format(**fillers, mouo=mouo, school=school_id) ) tasks.append((url, school_id)) total_tasks = len(tasks) completed = 0 # 用线程池并发处理,max_workers根据目标服务器承受能力调整,建议5-20 with ThreadPoolExecutor(max_workers=10) as executor: # 提交所有任务 futures = {executor.submit(process_single_url, url, sid): (url, sid) for url, sid in tasks} for future in as_completed(futures): completed += 1 df = future.result() if df is not None: df_list.append(df) # 打印进度 print(f'已处理 {completed}/{total_tasks}', end='\r') print('\ndone') return df_list
额外说明
max_workers的值不要设置过大,避免触发目标服务器的反爬限制或被拒绝连接,建议从5开始测试调整- 如果目标服务器有速率限制,可以在
process_single_url函数中加入短暂休眠(比如time.sleep(0.1)) - 若XML文件较大,可考虑用
lxml库手动解析后再转DataFrame,比pd.read_xml更灵活高效,但代码量会增加
内容的提问来源于stack exchange,提问作者lineage_refugee
相关产品推荐
相关产品推荐

