前几天在抓数据时,为了防止中途中断造成数据丢失将数据一次性写入excel改为了每一页写入一次。本来以为改动不大,结果发现每次到4000条时就会无法读写。于是就做了几个测试:

# -*- coding: utf-8 -*-

import pandas as pd
import os
import time

file = "append_test.xlsx"

# 初始化文件
if not os.path.exists(file):
    pd.DataFrame(columns=[
        "caseCode", "custNo", "custName",
        "overDuePay", "overDuePayPrin",
        "channelCustNo", "overDueDays", "contacts"
    ]).to_excel(file, index=False)

total_start = time.time()

for i in range(6000):

    # 每次生成1000行
    df = pd.DataFrame({
        "caseCode": range(i * 10, (i + 1) * 10),
        "custNo": "1234567890",
        "custName": "哈哈哈",
        "overDuePay": 35,
        "overDuePayPrin": 3456.78,
        "channelCustNo": "HZD0003",
        "overDueDays": 55,
        "contacts": "张三 13111223344 XX,李四 13111223344 XX,王五 13111223344 XX,"
    })

    write_start = time.time()

    # 追加写
    with pd.ExcelWriter(
            file,
            engine="openpyxl",
            mode="a",
            if_sheet_exists="overlay"
    ) as writer:

        sheet = writer.sheets["Sheet1"]

        df.to_excel(
            writer,
            index=False,
            header=False,
            startrow=sheet.max_row
        )

    write_cost = time.time() - write_start

    print(
        f"第{i + 1}次写入完成 | "
        f"写入行数: {len(df)} | "
        f"耗时: {write_cost:.4f}s"
    )

total_cost = time.time() - total_start

print(f"\n全部完成,总耗时: {total_cost:.2f}s")

程序在本机运行起来后,到400行左右并没崩溃,但是发现了一个现象,就是用的时间越来越长。从开始的很短,到2秒左右:第1次写入完成 | 写入行数: 10 | 耗时: 0.0490s
第2次写入完成 | 写入行数: 10 | 耗时: 0.0453s
第3次写入完成 | 写入行数: 10 | 耗时: 0.0484s
第4次写入完成 | 写入行数: 10 | 耗时: 0.0453s
第5次写入完成 | 写入行数: 10 | 耗时: 0.0487s
第6次写入完成 | 写入行数: 10 | 耗时: 0.0430s
第7次写入完成 | 写入行数: 10 | 耗时: 0.0336s
第8次写入完成 | 写入行数: 10 | 耗时: 0.0477s
第9次写入完成 | 写入行数: 10 | 耗时: 0.0490s
第10次写入完成 | 写入行数: 10 | 耗时: 0.0580s

第866次写入完成 | 写入行数: 10 | 耗时: 2.5864s
第867次写入完成 | 写入行数: 10 | 耗时: 2.5987s
第868次写入完成 | 写入行数: 10 | 耗时: 2.6189s
第869次写入完成 | 写入行数: 10 | 耗时: 2.7824s
第870次写入完成 | 写入行数: 10 | 耗时: 2.6807s
第871次写入完成 | 写入行数: 10 | 耗时: 2.4617s
第872次写入完成 | 写入行数: 10 | 耗时: 1.7832s
看样子还要增长下去。
好奇心驱使就查了一下Pandas + openpyxl 的追加写原理:

  • 读取整个工作表到内存(解析XML)
  • 在内存中构建新的DataFrame
  • 将整个工作表重新写入XML(即使只加1行)
  • 替换原有 sheet1.xml

特点:效率低,数据量大时很慢

有没有替代方案呢,查了一番,发现用csv速度和效率更高,而且读写稳定:

# -*- coding: utf-8 -*-

import pandas as pd
import os
import time

file = "append_test.csv"

# 如果存在先删除
if os.path.exists(file):
    os.remove(file)


# 模拟 4000 次追加写
for i in range(4000):
    df = pd.DataFrame({
        "caseCode": range(i * 1000, (i + 1) * 1000),
        "custNo": "1234567890",
        "custName": "哈哈哈",
        "overDuePay": 35,
        "overDuePayPrin": 3456.78,
        "channelCustNo": "HZD0003",
        "overDueDays": 55,
        "contacts": "张三 13111223344 XX,李四 13111223344 XX,王五 13111223344 XX,",
    })

    start = time.time()

    # 追加写关键参数
    df.to_csv(
        file,
        mode="a",
        header=not os.path.exists(file),
        index=False,
        encoding="utf-8-sig"
    )

    print(f"第{i+1}次追加完成,耗时: {time.time() - start:.4f}s")

这个的运行结果:
第1次追加完成,耗时: 0.0371s
第2次追加完成,耗时: 0.0070s
第3次追加完成,耗时: 0.0040s
第4次追加完成,耗时: 0.0045s
第5次追加完成,耗时: 0.0040s

第3995次追加完成,耗时: 0.0069s
第3996次追加完成,耗时: 0.0076s
第3997次追加完成,耗时: 0.0072s
第3998次追加完成,耗时: 0.0101s
第3999次追加完成,耗时: 0.0112s
第4000次追加完成,耗时: 0.0099s

结论就是非必要不要使用excel!

更多推荐