You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 11:50:33