使用python-docx在文档的某书签下方添加表格

使用python-docx在文档的书签下方添加表格包含以下三个流程:

  1. 把要插入的数据调整为dataframe格式
  2. 插入表格并移动表格到书签下方
  3. 保存修改后的结果

比如我们在一个文档【书签1】中,希望在书签1这个位置下面插入一个表格,使用方法如下:
使用python-docx在文档的某书签下方添加表格_第1张图片
比如随便插入一个dataframe:

# 1. 把要插入的数据调整为dataframe格式
dataframe = pd.DataFrame(np.random.randint(0, 10, size=(10, 4)))
dataframe.columns = [f"列{_ + 1}" for _ in dataframe.columns]

预期显示结果如下:
使用python-docx在文档的某书签下方添加表格_第2张图片

完整的代码如下:

from docx import Document, oxml
import pandas as pd
import numpy as np
from docx.oxml.ns import qn
from docx.oxml import OxmlElement


def get_bookmark_par_element_start(document, bookmark_name):
    """查找标签的起始位置(所在的段落)"""
    doc_element = document.part.element
    bookmarks_list = doc_element.findall('.//' + qn('w:bookmarkStart'))
    for bookmark in bookmarks_list:
        name = bookmark.get(qn('w:name'))
        if name == bookmark_name:
            par = bookmark.getparent()
            if not isinstance(par, oxml.CT_P):
                return 2
            else:
                return par, bookmark.get(qn('w:id'))
    return 1


def set_bookmark_df(document, bookmark_name, table):
    """
    :param document:
    :param bookmark_name:
    :param table:
    :return:
    """
    bookmark_par, _id = get_bookmark_par_element_start(document, bookmark_name)
    bookmark_par_parent = bookmark_par.getparent()
    # 下面是将表格移动到书签所在位置下方
    index = bookmark_par_parent.index(bookmark_par)
    base_paragraphs = document.paragraphs[index]
    base_paragraphs._p.addnext(table._tbl)


# 设置 table 的边框,用法与 cell 类似
def set_table_boarder(table, **kwargs):
    """
    Set table`s border
    Usage:
    set_table_border(
        cell,
        top={"sz": 12, "val": "single", "color": "#FF0000"},
        bottom={"sz": 12, "color": "#00FF00", "val": "single"},
        left={"sz": 24, "val": "dashed"},
        right={"sz": 12, "val": "dashed"},
    )
    """
    borders = OxmlElement('w:tblBorders')
    for tag in ('bottom', 'top', 'left', 'right', 'insideV', 'insideH'):
        edge_data = kwargs.get(tag)
        if edge_data:
            any_border = OxmlElement(f'w:{tag}')
            for key in ["sz", "val", "color", "space", "shadow"]:
                if key in edge_data:
                    any_border.set(qn(f'w:{key}'), str(edge_data[key]))
            borders.append(any_border)
            table._tbl.tblPr.append(borders)
    return table


def set_table_singleBoard(table):
    """为表格添加边框"""
    return set_table_boarder(
        table,
        top={"sz": 4, "val": "single", "color": "#000000"},
        bottom={"sz": 4, "val": "single", "color": "#000000"},
        left={"sz": 4, "val": "single", "color": "#000000"},
        right={"sz": 4, "val": "single", "color": "#000000"},
        insideV={"sz": 4, "val": "single", "color": "#000000"},
        insideH={"sz": 4, "val": "single", "color": "#000000"}
    )


def convert_df_to_table(document, dataframe: pd.DataFrame, index_list=None, column_list=None):
    """把table转为dataframe
    :param document: 文档对象
    :param dataframe: dataframe格式数据
    :param index_list: 最左边一列显示的内容
    :param column_list: (第一行)列名称需要显示的内容
    """
    rows = dataframe.shape[0]
    cols = dataframe.shape[1]
    if index_list is not None:
        cols += 1
    if column_list is not None:
        rows += 1
    table = document.add_table(rows=rows, cols=cols)
    row_i = 0
    col_i = 0
    if index_list is not None:
        raise
    if column_list is not None:
        hdr_cells = table.rows[row_i].cells
        for _col_i, _v in enumerate(column_list):
            hdr_cells[_col_i].text = str(_v)
        row_i += 1
    for _i, series_info in enumerate(dataframe.iterrows()):
        series = series_info[1]
        hdr_cells = table.rows[row_i + _i].cells
        for _c_i, _cell_value in enumerate(series):
            hdr_cells[col_i + _c_i].text = str(_cell_value)
    return table


def main():
    path = '测试1.docx'
    document = Document(path)
    # 1. 把要插入的数据调整为dataframe格式
    dataframe = pd.DataFrame(np.random.randint(0, 10, size=(10, 4)))
    dataframe.columns = [f"列{_ + 1}" for _ in dataframe.columns]
    
    # 2. 插入表格并移动表格到书签下方
    table = convert_df_to_table(document, dataframe, column_list=dataframe.columns.tolist())
    table = set_table_singleBoard(table)  # 表格添加边框
    set_bookmark_df(document, '书签1', table)
    
    # 3. 保存修改后的结果
    document.save('测试2.docx')  # 保存后导出


if __name__ == '__main__':
    main()

你可能感兴趣的:(自动化办公,python,python,开发语言)