金融量化学习---Python, MySQL, Pandas

这里用来记录一些在金融领域,尤其是银行相关的资金、债券、票据中应用到的数据管理与分析, 编程等心得或笔记,以及个人的一点小小兴趣(易经八卦、藏密禅修)等

导航

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('\n') #相当于插入一个下箭头

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:\Users\YourName 下):

结合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="\t")
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("\n")
 
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:\oxygen\Desktop\鐵人挑戰-程式教學\tmp\test.docx")
print("檔案內含段落數:",len(Doc.paragraphs),"\n")
#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
用docx生成多个文档:https://zhuanlan.zhihu.com/p/398846110

posted on 2020-11-25 17:07  chengjon  阅读(3765)  评论(0编辑  收藏  举报