从SharePoint上的Excel文件中提取数据到一个DataFrame中

后端开发 2026-07-08

我想把存放在SharePoint的、结构完全相同的Excel文件中的数据提取出来,汇总到一个DataFrame中。

目前,下面的做法在常量填好后似乎可行,但速度相当慢。现在大约有60个文件,所有文件合计大约5,000条记录,运行大约需要5 分钟。不过,每增加一个新文件到源文件夹,耗时会明显增加。

我并不指望有大量更多的文件或数据,但如果有更简单高效地完成下面这件事的方法,我宁愿采用。

有没有办法改进下面的做法?

我还需要在每个Excel文件的前3-4行跳过,但具体怎么做还不太清楚。

import requests
import pandas as pd

HEADERS = ""
SITE_ID = ""
DRIVE_ID = ""
SHAREPOINT_PATH = ""
RANGE_TO_READ = ""

def extract_from_sharepoint_():

    folder_items_url = f"https://graph.microsoft.com/v1.0/sites/{SITE_ID}/drives/{DRIVE_ID}/root:/{SHAREPOINT_PATH}:/children"

    folder_items = requests.get(folder_items_url, headers=HEADERS)
    folder_items = folder_items.json().get('value', [])

    dataframes = []
    for x in folder_items:

        file_id = x['id']
        file_name = x['name']

        if not file_name.endswith('.xlsx'):
            continue

        worksheet_url = f'https://graph.microsoft.com/v1.0/drives/{DRIVE_ID}/items/{file_id}/workbook/worksheets'
        response = requests.get(worksheet_url, headers=HEADERS)
        worksheets_name = response.json()['value'][0]['name']

        download_url = f"https://graph.microsoft.com/v1.0/drives/{DRIVE_ID}/items/{file_id}/workbook/worksheets('{worksheets_name}')/range(address='{RANGE_TO_READ}')"

        file_response = requests.get(download_url, headers=HEADERS)
        file_response = file_response.json()['values']
        df = pd.DataFrame(file_response[1:], columns=file_response[0])
        df.columns = df.columns.map(lambda x: x.lower().strip())

        dataframes.append(df)

    combined_df = pd.concat(dataframes, ignore_index=True)

解决方案

60个文件(只有大约5,000行数据)用5 分钟太慢。

我建议:绕过Graph工作簿API。改为使用 /content 端点将原始二进制文件直接下载到内存中,并让 pandas 在本地解析。这样也把对API的请求次数降到每个文件1 次(目前每个文件3 次API请求)。

openpyxl 搭配 pip3 install openpyxl 安装。openpyxl 能够有效解析数据,速度能降到秒级。使用 skiprows 参数跳过前几行

import io
import requests
import pandas as pd

HEADERS = {"Authorization": "Bearer YOUR_TOKEN"} # Ensure correct auth formatting
SITE_ID = "YOUR_SITE_ID"
DRIVE_ID = "YOUR_DRIVE_ID"
SHAREPOINT_PATH = "YOUR_FOLDER_PATH"

def extract_from_sharepoint_():
    # Get the list of items in the folder
    folder_items_url = f"https://graph.microsoft.com/v1.0/sites/{SITE_ID}/drives/{DRIVE_ID}/root:/{SHAREPOINT_PATH}:/children"

    # Use a session for connection pooling (faster subsequent requests)
    session = requests.Session()
    session.headers.update(HEADERS)

    response = session.get(folder_items_url)
    response.raise_for_status() # Catch HTTP errors early
    folder_items = response.json().get('value', [])

    dataframes = []

    for item in folder_items:
        file_name = item['name']
        file_id = item['id']

        # Only process Excel files
        if not file_name.endswith('.xlsx'):
            continue

        # Get the direct binary download endpoint for the file
        download_url = f"https://graph.microsoft.com/v1.0/drives/{DRIVE_ID}/items/{file_id}/content"

        file_response = session.get(download_url)
        if file_response.status_code != 200:
            print(f"Failed to download {file_name}")
            continue

        # Read the binary data straight into Pandas without saving to disk
        # 'skiprows=4' skips the first 4 rows. Row 5 becomes your header.
        try:
            df = pd.read_excel(
                io.BytesIO(file_response.content), 
                sheet_name=0,  # Reads the first sheet dynamically
                skiprows=4,
                engine='openpyxl' # Use openpyxl
            )

            # Clean columns
            df.columns = df.columns.map(lambda x: str(x).lower().strip())
            dataframes.append(df)

        except Exception as e:
            print(f"Error parsing {file_name}: {e}")

    # Combine all DataFrames 
    if dataframes:
        combined_df = pd.concat(dataframes, ignore_index=True)
        return combined_df
    else:
        print("No data found.")
        return pd.DataFrame()

在上面的代码中,requests.Session() 重用同一个连接池(目前对于每一个HTTP请求都会新建一次握手连接)

io.BytesIO 会让文件始终驻留在RAM中。因此,你可以省去将临时文件写入硬盘的时间。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章