Python办公自动化--Word、Excel、PDF

一、Python自动化之Excel 

python操作excel主要用到openpyxl库。其主要针对xlsx格式的excel进行读取和编辑。下面简单介绍其使用方法及命令。除openpyxl库外,还有xlwt及xlwd也可以对excel表格实现同样操作。

python读excel——xlrd,比如读取日期、读合并单元格内容。

python写excel——xlwt

学习Python处理Excel首先要知道excel各个名词含义,其结构如下图:

Python办公自动化--Word、Excel、PDF_第1张图片

data.xlsx
├── Sheet1
│   ├── A1
│   ├── A2
│   ├── B1
│   └── B2
├── Sheet2
│   ├── A1
│   ├── A2
│   ├── B1
│   └── B2
└── Sheet3
    ├── A1
    ├── A2
    ├── B1
    └── B2

一、工作簿新建保存
 

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.Workbook(路径) 
工作簿.save(路径)

二、打开工作簿

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['1月']
print(工作表)  #

三、工作表新建,删除,复制
一、显示工作簿中所有的工作表和表名

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)  #
所有工作表 = 工作簿.worksheets     # [, ]
for 工作表 in 所有工作表:
    print(工作表.title)

二、删除指定工作表

import openpyxl as opl
路径 = r'd:/DATAxlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['Sheet1']
工作簿.remove(工作表)
工作簿.save(路径)

三、新建指定工作表

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
工作簿.create_sheet('Sheet10')
工作簿.save(路径)

四、复制指定工作表

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
复制表 = 工作簿.copy_worksheet(工作簿['Sheet1'])  # 这里是工作表对象
复制表.title = '我是复制的表'                                       # 修改复制过来的表的名称
工作簿.save(路径)  

四、获取工作表的方法
(1)获取所有工作表的名称

工作簿 .sheetnames   # ['Sheet1', 'Sheet2', 'Sheet3']

(2)获取指定工作表

工作簿 ['Sheet2']     # 获取第2个工作表 #
工作簿.worksheets[0]  # 获取第1个工作表 #

(3)获取最后保存的那个工作表

工作簿.active             #

(4)获取工作表名称

工作表.title                # Sheet2

五、读单元格数据
一、获取一个单元格的值

**①通过指定坐标**

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['Sheet1']
单元格 = 工作表['A1'].value 
# 单元格 = 工作簿['Sheet1']['A1'].value  # 简写
print(单元格)  # 姓名

②通过指定行和列[cell(行,列)]
单元格 = 工作表.cell(row=1,column=1).value
print(单元格)  # 姓名

二、获取单元格对应的行、列和坐标

import openpyxl as opl
路径 = r'd:/好好学习.xlsx'
工作簿 = opl.load_workbook(路径)
单元格 = 工作簿['Sheet1']['A1']
print(单元格.row,单元格.column,单元格.coordinate)  # 1 1 A1    

三、获取一个区域的单元格

一、指定坐标范围

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['Sheet1']
单元格区域 = 工作表['A1:C10']
# 单元格区域 = 工作表['1:10']   # 第1行到第10行
# 单元格区域 = 工作表['A:C']    # 第A行到第C行
for 数据 in 单元格区域:    # 循环每行/每列
    for 单元格 in 数据:      # 循环每个单元格
        print(单元格.value)



注:单元格区域 = 工作表[2] # 只获取一行 , 2 就是第二行
单元格区域 = 工作表[B] # 只获取一列, B 就是 B列

二、自定范围
例:.iter_rows(min_row=最低行数,max_row=最高行数,min_col=最低列数,max_col=最高列数)
[一般情况下只需要定位起点,终点定位多了,会获取到好多空白]
①按行:

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径) 
工作表 = 工作簿['Sheet1']  
# 行和列的范围  iter_cols按列
for 行 in 工作表.iter_rows(min_row=1,max_row=10,min_col=1,max_col=3):
    for 单元格 in 行: 
        print(单元格.value)

②按列:

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径) 
工作表 = 工作簿['Sheet1']
# 行和列的范围  iter_cols按列
for 列 in 工作表.iter_cols(min_row=1(,max_row=10),min_col=1,max_col=3):
    for 单元格 in 列: 
        print(单元格.value)

注:设置了最大行和列,行和列内没有数据,就会获取到空None,一般不设置最大值,让程序自动获取。三、获取每一行

import openpyxl as opl
路径 = r'c:/测试.xlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['Sheet1']
# 因为按行,所以返回A1, B1, C1这样的顺序
for 行 in 工作表.rows:
    for 单元格 in 行:
        print(单元格.value)

获取每一列
# A1, A2, A3这样的顺序
for 列 in 工作表.columns:
    for 单元格 in 列:
        print(单元格.value)


前面总结练习
题目:找出text_1.xlsx中sheet1表中空着的格子,并输出这些格子的坐标

import openpyxl as opl
路径=r'C:\Users\49689\Desktop\pydir\test_1.XLSX'
工作簿 = opl.load_workbook(路径)   # 打开工作簿
工作表 = 工作簿['Sheet1']          # 打开工作表
for 单元格 in 工作表.columns:      # 遍历每列
    for i in 单元格:              # 遍历每列中的单元格
        if i.value==0:           # 判断单元格是否为0
print(i.coordinate)              # 打印坐标位置

六、写单元格数据
1、向一个单元格写入数据

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['Sheet1']
工作表.cell(1,5,value='学python')  # 通过行和列点位写入内容
工作表['E2']='学JAVA'              # 通过指定坐标写入内容
工作簿.save(路径)  # 存入原Excel表中,若创建新文件则可命名为不同名称

注:若原来的坐标上有数据,在写入数据会替代原来的内容

2、在最后一列写入数据

list=['海绵宝宝',2,5,10]
工作表.append(list)

#向一个区域内写入数据

for 行 in 工作表['B2:D4']:
    for 单元格 in 行:
        单元格.value = '良好'
 

4、用xlwt库向一个单元格写入内容

import xlwt
workbook = xlwt.Workbook(encoding = 'utf-8')  # 新建工作簿
sheet = workbook.add_sheet('My Worksheet')    # 创建一个sheet
# excel写入内容
# 参数对应   行, 列, 值
sheet.write(1,0,label = 'this is test')
# 保存
workbook.save('new_test.xls')

注:写入的行和列都是从索引0开始

5、用xlwt库写入多行内容

import xlwt
workbook = xlwt.Workbook(encoding='utf-8')
sheet = workbook.add_sheet('MyWorksheet')
data = [['hello',22,'hi'],
    ['hell',23,'h'],
    ['he',25,'him']]
for i in range(len(data)):                # 判断有几行
    for j in range(len(data[i])):         # 判断几列
        sheet.write(i,j,data[i][j])       # 写入数据
workbook.save('test.xlsx')  # 保存文档

七、行、列的插入与删除
插入语法:sheet.insert_cols(idx=?,amount=?)
idx=?—— 在第?行列前插入
amount=? —— 要插入的数量,无amount,就是插入一行

删除语法:sheet.delete_cols(idx=?,amount=?)
idx=?—— 在第?开始删除行列[包括?自己]
amount=? —— 要删除的数量,无amount,就是删除一行

import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['Sheet1']
工作表.insert_cols(idx=2)           # 在第2列前,插入1行
工作表.insert_cols(idx=2,amount=2)  # 在第2列前,插入2行
工作表.insert_rows(idx=2,amount=2)
工作表.delete_cols(idx=2,amount=2)  # 从第2列开始[包括自己]删除2行
工作表.delete_rows(idx=2,amount=2)
工作簿.save(路径)


八、 移动单元格
import openpyxl as opl
路径 = r'd:/DATA.xlsx'
工作簿 = opl.load_workbook(路径)
工作表 = 工作簿['Sheet1']
# rows和cols为正数为向下或向右、负数为向左或向上
工作表.move_range("A1:C3",rows=5,cols=5)  # 向下移动5行,在向右移动5行
工作簿.save(路径)

练习题

打开test文件,找出文件中购买数量buy_mount超过5的行,并对其标红、加粗、附上边框。

from openpyxl import load_workbook
from openpyxl.styles import Font, Side, Border 

workbook = load_workbook('./test.xlsx') 
sheet = workbook.active
buy_mount = sheet['F'] 
row_lst = []

for cell in buy_mount:
    if isinstance(cell.value, int) and cell.value > 5: 
        print(cell.row)
        row_lst.append(cell.row)
        
side = Side(style='thin', color='FF000000')
border = Border(left=side, right=side, top=side, bottom=side) 
font = Font(bold=True, color='FF0000')
for row in row_lst:
    for cell in sheet[row]: 
        cell.font = font 
        cell.border = border
workbook.save('new_test'.xlsx')

二、Python自动化之word

新建空白word并插入文字

# 导入库
from docx import Document

# 新建空白文档
doc_1 = Document()

#Add a title(0 equals the title of the article ,default level is 1,level range 0-9 )
doc_1.add_heading('create a new blank document title,level is 0',level=0)
doc_1.add_heading('create a new blank document title,level is 1',level=1)
doc_1.add_heading('create a new blank document title,level is 2',level=2)

# 新增段落
paragraph_1 = doc_1.add_paragraph('这是第一段文字的开始\n请多多关照!')
# 加粗
paragraph_1.add_run('加粗字体').bold = True
paragraph_1.add_run('普通字体')
# 斜体
paragraph_1.add_run('斜体字体').italic =True

# 新段落(当前段落的下方)
paragraph_2 = doc_1.add_paragraph('新起的第二段文字。')

# 新段落(指定端的上方)
prior_paragraph = paragraph_1.insert_paragraph_before('在第一段文字前插入的段落')

# 添加分页符(可以进行灵活的排版)
doc_1.add_page_break()
# 新段落(指定端的上方)
paragraph_3 = doc_1.add_paragraph('这是第二页第一段文字!')

# 保存文件(当前目录下)
doc_1.save('doc_1.docx')

Python办公自动化--Word、Excel、PDF_第2张图片

2.正式:python 自动化之 word 操作

Word文档的页面结构:

  • 文档-Document

  • 段落-Paragraph

  • 文字块-Run(最基本单位)

     Python办公自动化--Word、Excel、PDF_第3张图片

(2)字体设置

不放代码和运行结果,字体设置代码段(以宋体为例):

  • 方法一:调用已有库
#设置字体
style_font = document.styles.add_style('宋体', WD_STYLE_TYPE.CHARACTER)
style_font.font.name = '宋体'
document.styles['宋体']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')

paragraph1 = document.add_paragraph() # 添加段落
paragraph1.add_run(u'aBCDefg这是中文', style='楷体').font.name = 'Cambira'
  • 方法二:定义字体设置函数
#定义字体设置函数
def font_setting(doc,text,font_cn):
       style_add = doc.styles.add_style(font_cn, WD_STYLE_TYPE.CHARACTER)
       style_add.font.name = font_cn
       doc.styles[font_cn]._element.rPr.rFonts.set(qn('w:eastAsia'), font_cn)
       par = doc.add_paragraph()
       text = par.add_run(text, style=font_cn)
       
 font_setting(doc,a,'宋体')

(3) 插入图片与表格

#导入库
from docx import Document
from docx.shared import Inches

#打开文档
doc_1 = Document('周杰伦.docx')   #上面脚本存储的文档
#新增图片
doc_1.add_picture('周杰伦.jpg',width=Inches(1.0), height=Inches(1.0))

# 创建3行1列表格
table1 = doc_1.add_table(rows=2, cols=1)
table1.style='Medium Grid 1 Accent 1'  #表格样式很多种,如,Light Shading Accent 1等

# 修改第2行第3列单元格的内容为营口
table1.cell(0, 0).text = '营口'
# 修改第3行第4列单元格的内容为人民
table1.rows[1].cells[0].text = '人民'

# 在表格底部新增一行
row_cells = table1.add_row().cells
# 新增行的第一列添加内容
row_cells[0].text = '加油'

doc_1.save('周杰伦为营口加油.docx')

(4)设置页眉页脚

在 python-docx 包中则要使用节(section)中的页眉(header)和页脚(footer)对象来具体设置。

(5)其他设置

  • 对齐设置

  • 设置段落行距

  • 设置字体属性

3.项目实践:批量生成邀请函

# 导入库
from openpyxl import load_workbook
from docx import Document
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import RGBColor, Pt,Inches,Cm
from docx.oxml.ns import qn


path = r'D:\idea\cloud_analyse_game_sentiment\word自动化'
# 路径为Excel 文件所在的位置,可按实际情况更改

workbook = load_workbook(path + r'\excel到word.xlsx')
sheet = workbook.active   #默认的WorkSheet

n = 0   #为了不遍历标题(excel的第一行)
for row in sheet.rows:
    if n:
        company = row[0].value
        office = row[1].value
        name = row[2].value
        date = str(row[3].value).split()[0]
        print(company, office, name, date)


        doc = Document()
        heading_1 = '邀 请 函'
        paragraph_1 = doc.add_heading(heading_1, level=1)
        # 居中对齐
        paragraph_1.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
        # 单独修改较大字号
        for run in paragraph_1.runs:
            run.font.size = Pt(17)

        greeting_word_1 = '尊敬的'
        greeting_word_2 = '公司'
        greeting_word_3 = ',您好:'
        paragraph_2 = doc.add_paragraph()

        paragraph_2.add_run(greeting_word_1)
        r_1 = paragraph_2.add_run(company)
        r_1.font.bold = True  # 加粗
        r_1.font.underline = True    #下划线

        paragraph_2.add_run(greeting_word_2)

        r_2 = paragraph_2.add_run(office)
        r_2.font.bold = True  # 加粗
        r_2.font.underline = True    #下划线

        r_3 = paragraph_2.add_run(name)
        r_3.font.bold = True  # 加粗
        r_3.font.underline = True    #下划线
        paragraph_2.add_run(greeting_word_3)

        paragraph_3 = doc.add_paragraph()
        paragraph_3.add_run('现诚挚的邀请您于2021年10月27日参加DataWhale主办的享受开源2050活动,地点在北京鸟巢,希望您届时莅临参加。')
        paragraph_3.paragraph_format.first_line_indent = Cm(0.75)
        paragraph_3.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
        paragraph_3.paragraph_format.space_after = Inches(1.0)
        paragraph_3.paragraph_format.line_spacing = 1.5

        paragraph_4 = doc.add_paragraph()
        date_word_1 = '邀请时间:'
        paragraph_4.add_run(date_word_1)
        paragraph_4.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
        sign_date = "{}年{}月{}日".format(date.split('-')[0], date.split('-')[1], date.split('-')[2])
        paragraph_4.add_run(sign_date).underline = True
        paragraph_4.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
        
        #设置全文字体
        for paragraph in doc.paragraphs:
            for run in paragraph.runs:
                run.font.color.rgb = RGBColor(0, 0, 0)
                run.font.name = '楷体'
                r = run._element.rPr.rFonts
                r.set(qn('w:eastAsia'), '楷体')
        doc.save(path + "\{}-邀请函.docx".format(name))
    n = n + 1

4.总结

 Python办公自动化--Word、Excel、PDF_第4张图片

 三、Python自动化之PDF

1.批量拆分

拆分思路:

  • 读取 PDF 的整体信息、总页数等

  • 遍历每一页内容,以每个 step 为间隔将 PDF 存成每一个小的文件块

  • 将小的文件块重新保存为新的 PDF 文件

def split_pdf(filename, filepath, save_dirpath, step=5):
    """
    拆分PDF为多个小的PDF文件,
    @param filename:文件名
    @param filepath:文件路径
    @param save_dirpath:保存小的PDF的文件路径
    @param step: 每step间隔的页面生成一个文件,例如step=5,表示0-4页、5-9页...为一个文件
    @return:
    """
    if not os.path.exists(save_dirpath):
        os.mkdir(save_dirpath)
    pdf_reader = PdfFileReader(filepath)
    # 读取每一页的数据
    pages = pdf_reader.getNumPages()
    for page in range(0, pages, step):
        pdf_writer = PdfFileWriter()
        # 拆分pdf,每 step 页的拆分为一个文件
        for index in range(page, page+step):
            if index < pages:
                pdf_writer.addPage(pdf_reader.getPage(index))
        # 保存拆分后的小文件
        save_path = os.path.join(save_dirpath, filename+str(int(page/step)+1)+'.pdf')
        print(save_path)
        with open(save_path, "wb") as out:
            pdf_writer.write(out)

    print("文件已成功拆分,保存路径为:"+save_dirpath)

2.批量合并

def concat_pdf(filename, read_dirpath, save_filepath):
    """
    合并多个PDF文件
    @param filename:文件名
    @param read_dirpath:要合并的PDF目录
    @param save_filepath:合并后的PDF文件路径
    @return:
    """
    pdf_writer = PdfFileWriter()
    # 对文件名进行排序
    list_filename = os.listdir(read_dirpath)
    list_filename.sort(key=lambda x: int(x[:-4].replace(filename, "")))
    for filename in list_filename:
        print(filename)
        filepath = os.path.join(read_dirpath, filename)
        # 读取文件并获取文件的页数
        pdf_reader = PdfFileReader(filepath)
        pages = pdf_reader.getNumPages()
        # 逐页添加
        for page in range(pages):
            pdf_writer.addPage(pdf_reader.getPage(page))
    # 保存合并后的文件
    with open(save_filepath, "wb") as out:
        pdf_writer.write(out)
    print("文件已成功合并,保存路径为:"+save_filepath)

3.提取文字内容

def extract_text_info(filepath):
    """
    提取PDF中的文字
    @param filepath:文件路径
    @return:
    """
    with pdfplumber.open(filepath) as pdf:
        # 获取第2页数据
        #提取所有页则改为:page = pdf.pages
        page = pdf.pages[1]
        print(page.extract_text()) 

4.提取表格内容

def extract_table_info(filepath):
    """
    提取PDF中的图表数据
    @param filepath:
    @return:
    """
    with pdfplumber.open(filepath) as pdf:
        # 获取第18页数据
        page = pdf.pages[17]
        # 如果一页有一个表格,设置表格的第一行为表头,其余为数据
        table_info = page.extract_table()
        df_table = pd.DataFrame(table_info[1:], columns=table_info[0])
        df_table.to_csv('dmeo.csv', index=False, encoding='gbk')
         # 如果一页有多个表格,对应的数据是一个三维数组
        tables_info = page.extract_tables()
        for index in range(len(tables_info)):
            # 设置表格的第一行为表头,其余为数据
            df_table = pd.DataFrame(tables_info[index][1:], columns=tables_info[index][0])
            print(df_table)
            # df_table.to_csv('dmeo.csv', index=False, encoding='gbk')

5.提取图片内容

if not os.path.exists(pic_dirpath):
    os.makedirs(pic_dirpath)
# 使用正则表达式来查找图片
check_XObject = r"/Type(?= */XObject)"
check_Image = r"/Subtype(?= */Image)"
img_count = 0

"""1. 打开pdf,打印相关信息"""
pdf_info = fitz.open(filepath)
# 1.16.8版本用法 xref_len = doc._getXrefLength()
# 最新版本写法
xref_len = pdf_info.xref_length()
# 打印PDF的信息
print("文件名:{}, 页数: {}, 对象: {}".format(filepath, len(pdf_info), xref_len-1))

"""2. 遍历PDF中的对象,遇到是图像才进行下一步,不然就continue"""
for index in range(1, xref_len):
    # 1.16.8版本用法 text = doc._getXrefString(index)
    # 最新版本
    text = pdf_info.xref_object(index)
    
    is_XObject = re.search(check_XObject, text)
    is_Image = re.search(check_Image, text)
    # 如果不是对象也不是图片,则不操作
    if is_XObject or is_Image:
        img_count += 1
        # 根据索引生成图像
        pix = fitz.Pixmap(pdf_info, index)
        pic_filepath = os.path.join(pic_dirpath, 'img_' + str(img_count) + '.png')
        """pix.size 可以反映像素多少,简单的色素块该值较低,可以通过设置一个阈值过滤。以阈值 10000 为例过滤"""
        # if pix.size < 10000:
        #     continue
        
        """三、 将图像存为png格式"""
        if pix.n >= 5:
            # 先转换CMYK
            pix = fitz.Pixmap(fitz.csRGB, pix)
        # 存为PNG
        pix.writePNG(pic_filepath)

6.转换为图片

if not os.path.exists(pic_dirpath):
    os.makedirs(pic_dirpath)

images = convert_from_bytes(open(filepath, 'rb').read())
# images = convert_from_path(filepath, dpi=200)
for image in images:
    # 保存图片
    pic_filepath = os.path.join(pic_dirpath, 'img_'+str(images.index(image))+'.png')
    image.save(pic_filepath, 'PNG')

7.添加水印

watermark = PdfFileReader(watermark_filepath)
watermark_page = watermark.getPage(0)

pdf_reader = PdfFileReader(filepath)
pdf_writer = PdfFileWriter()

for page_index in range(pdf_reader.getNumPages()):
    current_page = pdf_reader.getPage(page_index)
    # 封面页不添加水印
    if page_index == 0:
        new_page = current_page
    else:
        new_page = copy(watermark_page)
        new_page.mergePage(current_page)
    pdf_writer.addPage(new_page)
# 保存水印后的文件
with open(save_filepath, "wb") as out:
    pdf_writer.write(out)

8.文档加密与解密

  • 加密:
pdf_reader = PdfFileReader(filepath)
pdf_writer = PdfFileWriter()

for page_index in range(pdf_reader.getNumPages()):
    pdf_writer.addPage(pdf_reader.getPage(page_index))

# 添加密码
pdf_writer.encrypt(passwd)
with open(save_filepath, "wb") as out:
    pdf_writer.write(out)
  • 解密:
pdf_reader = PdfFileReader(filepath)
# PDF文档解密
pdf_reader.decrypt('xiaoyi')

pdf_writer = PdfFileWriter()
for page_index in range(pdf_reader.getNumPages()):
    pdf_writer.addPage(pdf_reader.getPage(page_index))

with open(save_filepath, "wb") as out:
    pdf_writer.write(out)

9.总结

Python办公自动化--Word、Excel、PDF_第5张图片

本文参考: 2021年6月26期_Python办公自动化

你可能感兴趣的:(编程语言,python,办公自动化,后端)