zoukankan      html  css  js  c++  java
  • python读写word文档 -- python-docx从入门到精通

    两种安装方式:

    pip install python-docx
    conda install -c conda-forge python-docx
    

    常用到的导入命令

    import docx
    from docx import Document
    from docx.shared import Pt,Cm,Inches
    from docx.oxml.ns import qn  #python-docx中设置中文字体
    from docx.shared import RGBColor
    from docx.enum.text import WD_ALIGN_PARAGRAPH   #设置对齐方式
    from docx.enum.style import WD_STYLE_TYPE
    from docx.enum.text import WD_LINE_SPACING
    

    官网文档:https://python-docx.readthedocs.io/en/latest/index.html

    documnet/paragraph/run 的关系


    不管是paragraph还是title,它们在python里的type都是docx.text.paragraph.Paragraph

    功能简介:

    1.建立标题的方法

    document.add_heading()

    #方法1 - 用level设置,level为0-9,对应不同级别的标题, 不写level时,默认level=1
    # level =0  是一种特殊的heading(字体1号而且有下划线,但是没有导航)
    document.add_heading('Heading 1', level=1)
    
    #方法2 - 用style来设置不同级别的标题
    document.add_paragraph('Heading 1', style="Heading 1") 
    

    应用:要设置格式就需要用add_run, add_paragraph()生成的段落不能直接设置字体

    #设置大标题level=0,及其格式,先不在add_heading中写文字,而在add_run中添加,
    head0=document.add_heading(level=0)
    #设置标题居中,这一句导入 from docx.enum.text import WD_ALIGN_PARAGRAPH
    head0.alignment = WD_ALIGN_PARAGRAPH.CENTER
    title_run=head0.add_run('90天Cashflow现金流表数据统计',)
    title_run.font.size = Pt(20)    #14是四号字
    # 设置标题英文字体
    title_run.font.name = 'Times New Roman'
    # 设置标题中文字体
    title_run.element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
    # 设置字体颜色
    title_run.font.color.rgb = RGBColor(54,95,145)
    

    可以对照‘RGB颜色对照表’,设置更多的颜色

    2.建立段落

    document.add_paragraph() #建立段落

    也可以将一个段落用作“光标”,并在其上方直接插入一个新段落:
    prior_paragraph = paragraph.insert_paragraph_before('Lorem ipsum') #这里的paragraph.是要插入的paragraph name, 这里的Lorem ipsum是要插入的文字内容。

    这样可以将段落插入文档的中间,这在修改现有文档而不是从头开始生成文档时通常很重要。

    应用:

    from docx.shared import Pt,Cm
    from docx.oxml.ns import qn
    
    #以下为段落正文的全局设置
    document = Document()
    style = document.styles['Normal']
    # 设置西文字体
    style.font.name = 'Times New Roman'
    style.font.size = Pt(12)
    # 设置中文字体
    style.element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
    # 设置首行缩进, 先获取段落样式
    paragraph_format = style.paragraph_format
    # 首行缩进0.74厘米,即2个字符
    paragraph_format.first_line_indent = Cm(0.74)
    

    段落的对齐方式 WD_ALIGN_PARAGRAPH.LEFT

    行距的设置

    from docx.shared import Pt
    p = file.add_paragraph()
    p.paragraph_format.line_spacing = Pt(16) #行距,16磅对应三号字体大小
    p.add_run('设置行距的示例文字')
    

    段落间距的设置

    from docx.shared import Pt
    p = file.add_paragraph()
    p.paragraph_format.space_before = Pt(14) #段前间距,14磅对应四号字体大小
    p.paragraph_format.space_after = Pt(14) #段后间距
    p.add_run('设置段前/段后的示例文字')
    

    段落还可以使用style设置风格:

    # 圆点列表
    document.add_paragraph('first item in unordered list', style='List Bullet') 
    
    # 序号列表
    document.add_paragraph( 'first item in ordered list', style='List Number') 
    
    # 引用
    document.add_paragraph('Intense quote', style='Intense Quote')
    

    运行如下:

    设置中文字体

    设置标题heading的中文字体类型 + 设置正文的中文字体类型

    #依赖包:
    from docx import Document
    from docx.shared import Pt
    from docx.shared import Inches
    from docx.oxml.ns import qn
     
    #修改正文的中文字体类型,示例代码:(全局设置)中文字体设置好象不加u也可以
    document=Document()
    document.styles['Normal'].font.name=u'微软雅黑'
    document.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'微软雅黑')
     
    #修改3级标题的字体类型,示例代码:
    run = document.add_heading('',level=3).add_run(u"应用场景示例: ")#应用场景示例标题
    run.font.name=u'微软雅黑'
    run._element.rPr.rFonts.set(qn('w:eastAsia'), u'微软雅黑') 
    

    更详细的字体设置指引:http://www.jhanmath.com/?p=130

    设置中文字体与西文字体不同,可能是word内部处理方式不同,主要是通过以下这句:

    style.element.rPr.rFonts.set(qn('w:eastAsia'), '宋体') # style中
    r._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312') # run中
    

    以下给出在style和run中设置的代码。

    style中的设置

    更改现有style

    style = document.styles['Normal']
    style.font.name = 'Times New Roman' # 必须先设置font.name
    style.font.size = Pt(14)
    style.element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
    

    创建新style

    from docx.enum.style import WD_STYLE_TYPE
    from docx.enum.text import WD_ALIGN_PARAGRAPH
    from docx.enum.text import WD_LINE_SPACING
    
    mystyle = document.styles.add_style('titlepage_title', WD_STYLE_TYPE.PARAGRAPH)
    mystyle.font.name = 'Times New Roman'   # 必须先设置font.name
    mystyle.font.size = Pt(16)
    mystyle.font.bold = True
    mystyle.element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
    mystyle.paragraph_format.space_after = Pt(0)
    # mystyle.paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
    mystyle.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
    mystyle.paragraph_format.line_spacing = 1.8
    

    对创建的段落应用设置好的style即可改变中文字体。

    run中的格式设置

    p = document.add_paragraph()
    r = p.add_run('文字')
    r.font.name = '仿宋_GB2312'   # 必须先设置font.name
    r._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
    r.font.size = Pt(14)
    

    3.追加文字,设定粗体或斜体等等特殊格式

    add_run(),他是属于 paragraph 之下的方法,所以必须搭配 paragraph 对象使用。

    #插入段落, 同时设置粗体和斜体~
    p = document.add_paragraph('A plain paragraph having some ')
    p.add_run('bold').bold = True #粗体
    p.add_run(' and some ')
    p.add_run('italic.').italic = True #斜体
    

    运行得到:

    设置字体大小

    from docx.shared impore Pt
    p = document.add_paragraph()
    run = p.add_run('我喜欢你')
    font = run.font  #调用font属性
    font.size = Pt(26)
    

    设置其它字体格式

    font.italic = True  #设置斜体
    font.underline = True  #设置下划线
    font.bold = True  #设置粗体
    

    设置首行缩进

    from docx.shared import Inches
    p = document.add_paragraph()
    p.paragraph_format_line_indent = Inches(0.32)  #假设这里的文本大小是小四,0.16英寸,缩进2个就是0.32
    p.add_run('设置首行缩进的文字') 
    

    字体大小对照表

    插入空行
    document.add_paragraph() #相当于插入一个回车
    document.add_paragraph(' ') #相当于插入一个下箭头

    4.插入图片

    document.add_picture()

    #插入宽度设定好的图片
    from docx.shared import Inches
    document.add_picture('image-filename.png', width=Inches(1.0))
    

    5.建立表格

    document.add_table(rows=?, cols=?) ,表格传入参数为行数与列数,并且透过 tuple 指定数据。要注意,表格的行列都是从0开始的,如cell(0,0)表示第1行第一列的数,cell(0,1)表示第1行第2列的数。

    add_table() # 新建表格
    add_row() # 添加行
    add_col() # 添加列
    table.cell(i, j).text() # 往表格中添加内容
    table.rows() # 行数
    table.cols() # 列数
    

    6.插入换页符号

    document.add_page_break()

    7.储存 docx 档案到 demo.docx

    document.save('demo.docx')

    document.save(path) # 指定路径
    象这样:
    document.save(r"d:demo.docx")
    会在D:根目录下生成demo.docx

    先上一段代码

    from docx import Document
    from docx.shared import Inches
    
    #透过 Document()建构函数声明一个 Document 对象
    document = Document()
    #add_heading() 是建立标题的方法
    document.add_heading('Document Title', 0)
    
    #document.add_paragraph()则是建立段落
    p = document.add_paragraph('A plain paragraph having some ')
    #add_run() 可以设定粗体或斜体等等特殊格式,他是属于 paragraph 之下的方法,所以必须搭配 paragraph 对象使用。
    p.add_run('bold').bold = True
    p.add_run(' and some ')
    p.add_run('italic.').italic = True
    
    
    document.add_heading('Heading, level 1', level=1)
    document.add_paragraph('Intense quote', style='Intense Quote')
    
    document.add_paragraph(
        'first item in unordered list', style='List Bullet'
    )
    document.add_paragraph(
        'first item in ordered list', style='List Number'
    )
    
    #document.add_picture() 用来插入图片
    #document.add_picture('monty-truth.png', width=Inches(1.25))
    
    records = (
        (3, '101', 'Spam'),
        (7, '422', 'Eggs'),
        (4, '631', 'Spam, spam, eggs, and spam')
    )
    
    #document.add_table(rows=?, cols=?) 用来建立表格,表格传入参数为行数与列数,并且透过 tuple 指定数据。
    table = document.add_table(rows=1, cols=3)
    hdr_cells = table.rows[0].cells
    hdr_cells[0].text = 'Qty'
    hdr_cells[1].text = 'Id'
    hdr_cells[2].text = 'Desc'
    for qty, id, desc in records:
        row_cells = table.add_row().cells
        row_cells[0].text = str(qty)
        row_cells[1].text = id
        row_cells[2].text = desc
    
    #document.add_page_break() 插入换页符号
    document.add_page_break()
    
    #document.save('demo.docx') 储存 docx 档案到 demo.docx
    document.save('demo.docx')
    

    得到这样一个WORD文档 (默认位于C:UsersYourName 下):

    结合pandas的iloc函数,将dataframe写入word

    import pandas as pd
    from docx import Document # 输出docx
    from docx.shared import Pt # 设置字号
    
    document = Document()
    df = pd.read_csv(a.csv, sep="	")
    rowNum = df.shape[0] + 1 # 行数,加标题栏
    colNum = df.shape[1] # 列数
    table = document.add_table(rows=rowNum, cols=colNum, style = "Light Grid")
    table.cell(0,0).text = "a"
    table.cell(0,1).text = "b"
    table.cell(0,2).text = "c"
    table.cell(0,3).text = "d"
    for i in range(1, rowNum):
        for j in range(colNum):
            cell = table.cell(i,j)
            cell.text = str(df.iloc[i-1,j])
    
    table.autofit = True
    table.style.font.name = u'等线'
    table.style.font.size = Pt(12)
    document.save(outPutDocx)
    

    得到:

    TIPS

    1.生成Dataframe的docx代码函数:

    #以下为公共设置区域---打印df的函数
    def add_df2docx(df):
        rowNum = df.shape[0] + 1 # 行数,加标题栏
        colNum = df.shape[1] # 列数
        table = document.add_table(rows=rowNum, cols=colNum, style = "Table Grid")
        columns=list(df.columns)
        for i in range(0,colNum):
            table.cell(0,i).text = columns[i]
        for i in range(1, rowNum):
            for j in range(colNum):
                cell = table.cell(i,j)
                cell.text = str(df.iloc[i-1,j])
        table.autofit = True
        table.style.font.name = u'仿宋'
        table.style.font.size = Pt(12)
    

    2.设置一个加title的函数 my_add_head('tilename',1,WD_ALIGN_PARAGRAPH.CENTER,20,'仿宋')

    def my_add_head(name,level_num,align,font_size,cfont):
        head0=document.add_heading(level=level_num)
    #设置标题居中
        head0.alignment = align
        title_run=head0.add_run(name)
        title_run.font.size = Pt(font_size)    #14是四号字
    # 设置标题英文字体
        title_run.font.name = 'Times New Roman'
    # 设置标题中文字体
        title_run.element.rPr.rFonts.set(qn('w:eastAsia'), cfont)
        return
    

    3.为段落正文的全局设置

    document = Document()
    style = document.styles['Normal']
    # 设置西文字体
    style.font.name = 'Times New Roman'
    style.font.size = Pt(12)
    # 设置中文字体
    style.element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
    # 设置首行缩进, 先获取段落样式
    paragraph_format = style.paragraph_format
    # 首行缩进0.74厘米,即2个字符
    paragraph_format.first_line_indent = Cm(0.74)
    

    具体的一些表格设计可以参考:https://zhuanlan.zhihu.com/p/82880510
    以及官网:https://python-docx.readthedocs.io/en/latest/user/text.html
    还有一些更加详细的命令可以参考:http://www.ityouknow.com/python/2019/12/31/python-word-105.html

    如果想要获得所有的表样,可以参考:https://blog.csdn.net/ibiao/article/details/78595295

    下列代码可以将所有表样导出到文件

    from docx.enum.style import WD_STYLE_TYPE
    from docx import *
    document = Document()
    styles = document.styles
     
    #生成所有表样式
    for s in styles:
        if s.type == WD_STYLE_TYPE.TABLE:
            document.add_paragraph("表格样式 :  "+ s.name)
            table = document.add_table(3,3, style = s)
            heading_cells = table.rows[0].cells
            heading_cells[0].text = '第一列内容'
            heading_cells[1].text = '第二列内容'
            heading_cells[2].text = '第三列内容'
            document.add_paragraph("
    ")
     
    document.save('demo2.docx')
    

    得到:

    插入超级链接的函数

    def add_hyperlink(paragraph, url, text, color, underline):
        """
        A function that places a hyperlink within a paragraph object.
    
        :param paragraph: The paragraph we are adding the hyperlink to.
        :param url: A string containing the required url
        :param text: The text displayed for the url
        :return: The hyperlink object
        """
    
        # This gets access to the document.xml.rels file and gets a new relation id value
        part = paragraph.part
        r_id = part.relate_to(url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, is_external=True)
    
        # Create the w:hyperlink tag and add needed values
        hyperlink = docx.oxml.shared.OxmlElement('w:hyperlink')
        hyperlink.set(docx.oxml.shared.qn('r:id'), r_id, )
    
        # Create a w:r element
        new_run = docx.oxml.shared.OxmlElement('w:r')
    
        # Create a new w:rPr element
        rPr = docx.oxml.shared.OxmlElement('w:rPr')
    
        # Add color if it is given
        if not color is None:
            c = docx.oxml.shared.OxmlElement('w:color')
            c.set(docx.oxml.shared.qn('w:val'), color)
            rPr.append(c)
    
        # Remove underlining if it is requested
        if not underline:
            u = docx.oxml.shared.OxmlElement('w:u')
            u.set(docx.oxml.shared.qn('w:val'), 'none')
            rPr.append(u)
    
        # Join all the xml elements together add add the required text to the w:r element
        new_run.append(rPr)
        new_run.text = text
        hyperlink.append(new_run)
    
        paragraph._p.append(hyperlink)
    
        return hyperlink
    
    pp=document.add_paragraph()
    #add a hyperlink with the normal formatting (blue underline)
    hyperlink = add_hyperlink(pp, 'http://www.google.com', 'Google', None, True)
    
    qq=document.add_paragraph()
    #add a hyperlink with a custom color and no underline
    hyperlink = add_hyperlink(qq, 'http://www.google.com', 'Google', 'FF8822', False)
    

    读取 docx 文件

    文件如下图:

    上代码:

    import docx
    Doc = docx.Document(r"D:oxygenDesktop鐵人挑戰-程式教學	mp	est.docx")
    print("檔案內含段落數:",len(Doc.paragraphs),"
    ")
    #Doc.paragraphs 會回傳讀取到的段落,以 list 回傳,所以我們先用 len(Doc.paragraphs) 來取得總段落數
    
    #再用for循环读取Doc中的所有paragraphs,并存在我们新建的testList中,再print
    testList = []
    for text in Doc.paragraphs:
        testList.append(text)
    
    for pg in testList:
        print(pg.text)
    

    实现对word内段落文本及表格的读取

    在以下方法中用到的三方库是:python-docx

    from docx import Document
    #获取指定段落的文本
    def get_paragraph_text(path, n):
        """
        获取指定段落的文本
        :param path: word路径
        :param n: 第几段落,从0开始计数
        :return: word文本
        """
        document = Document(path)
        all_paragraphs = len(document.paragraphs)
        if all_paragraphs > n:
            paragraph_text = document.paragraphs[n].text
            return paragraph_text
        else:
            raise IndexError('paragraph index (%s) out of range, in total %s' % (n, all_paragraphs))
    #获取全部段落的文本
    def get_paragraphs_text(path):
        """
        获取所有段落的文本
        :param path: word路径
        :return: list类型,如:
            ['Test', 'hello world', ...]
        """
        document = Document(path)
        all_paragraphs = document.paragraphs
        paragraphs_text = []
        for paragraph in all_paragraphs:
            paragraphs_text.append(paragraph.text)
        return paragraphs_text
    #获取所有表格的文本
    def get_all_tables_text(path):
        """
        获取word中所有表格的文本
        :param path: word路径
        :return: list类型的二维数组
            如:[['年龄', '排序'], ['23', '00',], ...]
        """
        document = Document(path)
        all_tables = document.tables
        text_list = []
        for table in all_tables:
            for row in table.rows:
                text = []
                for cell in row.cells:
                    text.append(cell.text)
                text_list.append(text)
        return text_list
    获取指定表格的文本
    def get_table_text(path, n=0):
        """
        获取word中的第n个表格的文本
        :param path: word路径
        :param n: 第几个表格,从0开始计算
        :return: list类型的二维数组
            如:[['年龄', '排序'], ['23', '00',], ...]
        """
        document = Document(path)
        all_tables = len(document.tables)
        if all_tables > n:
            table = document.tables[n]
            text_list = []
            for row in table.rows:
                text = []
                for cell in row.cells:
                    text.append(cell.text)
                text_list.append(text)
            return text_list
        else:
            raise IndexError('table index (%s) out of range, in total %s' % (n, all_tables))
    获取指定表格内指定单元格文本
    def get_cell_text(path, n=0, row=0, col=0):
        """
        获取某个表格的某个单元格的值
        :param path: word路径
        :param n: 第几个表格,从0开始计算
        :param row: 第几行,从0开始计算
        :param col: 第几列,从0开始计算
        :return: 单元格的值,str类型
        """
        document = Document(path)
        all_tables = len(document.tables)
        if all_tables > n:
            rows = len(document.tables[n].rows)
            cols = len(document.tables[n].columns)
            if rows > row and cols > col:
                tab = document.tables[n].rows[row].cells[col]
                return tab.text
            else:
                raise IndexError('cell index out of range, %s;%s' % (row, col))
        else:
            raise IndexError('table index (%s) out of range, in toatl %s' % (n, all_tables))
    

    官网样式:
    https://python-docx.readthedocs.io/en/latest/user/styles-understanding.html#understanding-styles

  • 相关阅读:
    HDU-3555-Bomb
    hihoCoder-1015-KMP
    HDU-1251-统计难题
    hihoCoder-1014-Trie树
    BZOJ-4326: NOIP2015 运输计划 (二分+LCA+树上差分)
    BZOJ-1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 (筛法暴力)
    BZOJ-1419: Red is good (期望DP)
    BZOJ-1798: [Ahoi2009]Seq 维护序列seq & BZOJ-5039: [Jsoi2014]序列维护 (线段树)
    BZOJ-3732: Network (kruskal+LCA)
    BZOJ-1787: [Ahoi2008]Meet 紧急集合 (LCA)
  • 原文地址:https://www.cnblogs.com/treasury-manager/p/14037183.html
Copyright © 2011-2022 走看看