【问题标题】:extremely slow add a table to python-docx from a csv file从 csv 文件向 python-docx 添加表非常慢
【发布时间】:2021-11-05 00:10:11
【问题描述】:

我必须在 docx word 文档中从 CSV 文件中添加一个大约 1500 行和 9 列(75 页)的表格。使用 python-docx。

我尝试了不同的方法,用 pandas 读取 csv 或直接打开 de csv 文件,我花了大约 150 分钟以我选择的方式独立完成工作

我的问题是这是否是正常行为,或者是否存在任何其他改进此任务的方法。

我正在使用这个 for 循环来读取几个 cvs 文件并以表格格式解析它

        for toTAB in listBRUTO:
            df= pd.read_csv(toTAB)
            
            # add a table to the end and create a reference variable
            # extra row is so we can add the header row
            t = doc.add_table(df.shape[0]+1, df.shape[1])
            t.style = 'LightShading-Accent1' # border
           
        
            # add the header rows.
            for j in range(df.shape[-1]):
                t.cell(0,j).text = df.columns[j]
                
            # add the rest of the data frame
            for i in range(df.shape[0]):
                for j in range(df.shape[-1]):
                    t.cell(i+1,j).text = str(df.values[i,j])
            
            #TABLE Format
            for row in t.rows:
                for cell in row.cells:
                    paragraphs = cell.paragraphs
                    for paragraph in paragraphs:
                        for run in paragraph.runs:
                            font = run.font
                            font.name = 'Calibri'
                            font.size= Pt(7)

            
            doc.add_page_break()
        doc.save('blabla.docx')

提前致谢

【问题讨论】:

  • 你做了什么花了这么长时间的尝试?
  • 从服务器中提取数据,例如:工作流程
  • 我的意思是你使用的代码是什么。如果您不发布您的最小复制代码,我们只是在猜测。
  • 你是对的,只是添加了一些代码来更好地理解我的问题

标签: python-3.x python-docx


【解决方案1】:

您需要尽量减少对table.cell() 的调用次数。由于单元格合并的工作方式,这些操作在紧密循环中执行时确实会增加成本。

我将从重构这个块开始,看看会产生多少改进:

# --- add the rest of the data frame ---
for i in range(df.shape[0]):
    for j, cell in enumerate(table.rows[i + 1].cells):
        cell.text = str(df.values[i, j])

【讨论】:

  • 哇 [Done] 在 465.551 秒内以 code=0 退出 - 我的代码 [Done] 在 106.166 秒内以 code=0 退出 - 您的代码几乎减少了 5 倍,我将运行更多示例
  • 很高兴它显示出改进:) 不要忽视接受最能回答您问题的答案。这就是您向那些花时间回答您问题的人致谢的方式。
  • RangeIndex: 474 个条目,0 到 473 数据列 10 # Column Non-Null Count Dtype --- ------ -------------- - --- 0 主机 474 非空对象 1 Enterprise474 非空对象 2 服务 474 非空对象 3 命令 474 非空对象 4 参数 474 非空对象 5 用户名 474 非空对象 6 简单标识 474 非-null object 7 Process id 474 non-null int64 8 Request Time 474 non-null object 9 OS 474 non-null object
  • 少了 5 倍,谢谢 Scanny
【解决方案2】:

每次访问它的“单元格”属性时,python-docx 都会遍历整个表格。
所以你最好尽可能少调用“.cell”,而是使用单元缓存。
这是两个访问大小为 3*1500 的表的示例:

代码 1:大约 150.0s

for row in table.rows:
    print('processing: {0:30s}'.format(row.cells[0].text),end='\r')

代码 2:大约 1.4 秒

clls=table._cells
for row_idx in range(len(clls)//table._column_count):
    print('processing: {0:30s}'.format( 
       clls[0 + row_idx*table._column_count].text),end='\r')

clls=table._cells 在代码 2 中使用 "_cells" 来处理单元格合并,因此 ccls[column_idx + row_idx*table._column_count].texttable.rows[row_idx].cells[column_idx].text 一样好,并且不需要 table 完全是矩形

【讨论】:

    【解决方案3】:

    对于没有合并单元格的矩形表格,您可以将所有单元格导出到列表结构中并非常快速地填充它们(小于 0.5 秒,而对于 3 列的约 300 行表格则需要 15 秒):

    from docx.table import _Cell
    
    def get_cells_grid(table):
        cells = [[]]
        col_count = table._column_count
        for tc in table._tbl.iter_tcs():
            cells[-1].append(_Cell(tc, table))
            if len(cells[-1]) == col_count:
                cells.append([])
        return cells
    
    cells = get_cells_grid(t)
    
    for i in range(df.shape[0]):
        for j in range(df.shape[i]):
                cells[i][j].text = str(df.values[i, j])
    

    函数基于table._cells()代码:https://github.com/python-openxml/python-docx/blob/da75fcf01f7f322e846e2ac3e1936aedd766acc8/docx/table.py#L162

    【讨论】:

      【解决方案4】:

      只是为了补充我的经验,如果您必须创建一个巨大的表格,请先创建整个结构,这意味着您需要的所有行和单元格;然后像这样存储单元格

      table_cells = table._cell (cf @kztopia)

      从那里您可以根据需要操作单元格、合并、添加文本等...具有相当优化的速度,因为您只需调用一次 cell()

      在我的用例中,在我看来,一个表不是那么大(~130 行,每行 8 个单元格),它过去需要 9 秒来创建整个东西,现在我在 0.5 左右。

      请记住,表格越大,执行 cell() 所需的时间就越多

      【讨论】:

        猜你喜欢
        • 2018-08-17
        • 1970-01-01
        • 2016-09-14
        • 1970-01-01
        • 1970-01-01
        • 2021-09-30
        • 1970-01-01
        • 2016-04-07
        • 1970-01-01
        相关资源
        最近更新 更多