python全栈-自动化office
python自动化office
xlwt写文件
- save保存文件
- add_sheet新建工作薄
打印一个99乘法表
import xlwtwb = xlwt.Workbook()sh = wb.add_sheet('乘法表') # 左下角工作簿的名称
for i in range(1,10):for j in range(1,i+1):sh.write(i-1,j-1,f'{i}x{j}={i*j}') # 根据(行,列)坐标填写数据
wb.save('乘法表测试.xlsx') # 整个文件的名称
设置样式
字体
ft = xlwt.Font()
ft.name = '微软雅黑' ft.colour_index = 2
# 字体大小,11 为字号,20 为衡量单位
ft.height = 20*11
# 字体加粗
ft.bold = False
# 下划线
ft.underline = True
# 斜体字
ft.italic = True
设置单元格对齐方式
alignment = xlwt.Alignment()
# 0x01(左端对齐)、0x02(水平方向上居中对齐)、0x03(右端对齐)
alignment.horz = 1
# 0x00(上端对)、 0x01(垂直方向上居中对齐)、0x02(底端对齐)
alignment.vert = 2
# 设置自动换行
alignment.wrap = 1
边框
# 设置边框
borders = xlwt.Borders()
# 细实线:1,小粗实线:2,细虚线:3,中细虚线:4,大粗实线:5,双线:6,细点虚线:7
# 大粗虚线:8,细点划线:9,粗点划线:10,细双点划线:11,粗双点划线:12,斜点划线:13
borders.left = 1
borders.right = 2
borders.top = 3
borders.bottom = 4
borders.left_colour = 3
borders.right_colour = 2
borders.top_colour = 2
borders.bottom_colour = 4
背景
# 设置背景颜色
pattern = xlwt.Pattern()
# 设置背景颜色的模式
pattern.pattern = xlwt.Pattern.SOLID_PATTERN
# 背景颜色
pattern.pattern_fore_colour = 5
sy = xlwt.XFStyle()
sy.font = ft
sy.alignment= alignment
sy.borders = borders
sy.pattern = pattern
使用js的方法设置格式
sy2 = xlwt.easyxf('font: bold on,color-index 4; align: wrap on, vert centre, horiz center')
sy3 = xlwt.easyxf('font: bold on,color-index 4; border: left 1 ,right_colour 3,right 1')
xlrd读文件
import xlrdwb = xlrd.open_workbook('乘法表测试.xlsx') # 打开文件
# 核对文件信息
print(wb.nsheets) # 工作薄的数量
print(wb.sheet_names()) # 工作薄的名称
# 选中文件表数据
sh1 = wb.sheet_by_index(0) # 按工作薄序号选择
sh2 = wb.sheet_by_name('乘法表') # 按工作薄名称选择print(f'{sh1.nrows}行,{sh1.ncols}列;{sh2.nrows}行,{sh2.ncols}列') # 获取行列数for i in range(2):print(sh1.cell_value(i,0)) # 根据行列坐标获取单元格内容print(sh1.cell(i,0).value) # 根据行列坐标获取单元格内容print(sh1.row(i)[0].value) # 根据行列坐标获取单元格内容print(sh1.col(0)[i].value) # 根据行列坐标获取单元格内容print(sh1.row_values(0)) # 获取第一行所有数据
print(sh1.col_values(0)) # 获取第一列所有数据# 遍历所有单元格数据
for i in range(sh1.nrows):for j in range(sh1.ncols):if sh1.cell_value(i,j):print(f'第{i}行,第{j}列的数据是{sh1.cell_value(i,j)}')
xlutils修改文件
from xlutils.copy import copy
import xlrdget_book = xlrd.open_workbook('乘法表测试.xlsx') # 获取内容
wb = copy(get_book) # 复制数据# 检查是否存在名为'数据测试'的工作表
if '数据测试' in get_book.sheet_names():# 获取已存在的工作表sh_index = get_book.sheet_names().index('数据测试')# xlwt.Workbook对象的sheet方法获取已存在的工作表sh1 = wb.get_sheet(sh_index)
else:# 如果不存在,创建新工作表sh1=wb.add_sheet('数据测试')# 写入数据
sh1.write(0,1,1)
sh1.write(1,1,2)
sh1.write(2,1,3)
sh1.write(3,1,4)
sh1.write(4,1,5)
sh1.write(5,0,'求和')count=0
aa = get_book.sheet_by_index(1)
for i in range(aa.nrows-1):num = aa.cell_value(i, 1)print(num)count += numsh1.write(5,1,count)
wb.save('乘法表测试.xlsx') # 保存文件
1. xlrd的只读限制
xlrd.open_workbook() 返回的工作簿对象(get_book)是 只读的 ,它仅提供读取Excel内容的功能,不支持直接修改数据或添加工作表。这是xlrd库的设计决定,旨在专注于高效读取功能。
2. xlwt的创建限制
与之对应的xlwt库(用于写入Excel)只能 创建新文件 ,无法直接编辑现有文件。它需要从头构建工作簿内容,无法基于已有文件进行修改。
3. xlutils.copy的桥梁作用
xlutils.copy.copy() 的核心作用是:
- 将只读的xlrd工作簿对象转换为可写的xlwt工作簿对象
- 保留原始文件的所有内容(工作表、格式、数据)
- 创建一个内存中的可修改副本
4. 为何必须使用副本进行操作
即使看似不需要修改原始文件,也必须通过副本操作的原因是:
- 原始工作簿(get_book)没有写入接口
- 所有编辑操作(如 add_sheet 、 write )都需要调用xlwt的方法
- 最终的 save() 方法也是xlwt工作簿对象的方法
只读文件 → 复制为可写副本 → 在副本上操作 → 保存为新文件
这种设计虽然增加了步骤,但确保了读写操作的分离和数据安全性,避免意外修改原始文件。
数据汇总
import xlrdwb = xlrd.open_workbook('data01.xlsx')
sh1 = wb.sheet_by_index(0)
print(f'{sh1.nrows}行,{sh1.ncols}列')
# 存储数据
name={} # 以字典的形式存放数据,写入第二个工作薄
num = [] # 计算每一行3,4列数值之积,然后写在第5列for i in range(sh1.nrows):print(sh1.cell_value(i,0),sh1.cell_value(i,3),sh1.cell_value(i,4))nn = (sh1.cell_value(i,3)*sh1.cell_value(i,4))if str(sh1.cell_value(i, 0)) in name: # 如果公司名不在字典name里面,就新增键值对,否则就在已有的键值对里面对值进行累加name[str(sh1.cell_value(i, 0))] += nnelse:name[str(sh1.cell_value(i, 0))] = nnnum.append(nn)# 检查数据
print(f'{name}')
print(f'{num}')
# 新增数据
from xlutils.copy import copy
wc = copy(wb)
sh2 = wc.get_sheet(0)
for i in range(sh1.nrows):sh2.write(i,5,num[i])sh3 = wc.add_sheet('数据汇总')
bb = 0
for i in name.keys():print(i,name[i])sh3.write(bb,0,i)sh3.write(bb,1,name[i])bb+=1wc.save('data008.xlsx')
表格拆分
就是数据汇总的时候,把同一公司的数据,放在一个字典里面,以列表的形式,储存一行的信息。然后在新建工作薄,以公司名称位工作薄的名称,把该公司的数据放入这个工作薄
import xlrdwb = xlrd.open_workbook('data01.xlsx')
sh1 = wb.sheet_by_index(0)
print(f'{sh1.nrows}行,{sh1.ncols}列')
# 存储数据
name={}for i in range(sh1.nrows):# print(sh1.row_values(i))if str(sh1.cell_value(i, 0)) in name:name[str(sh1.cell_value(i, 0))].append(sh1.row_values(i))else:name[str(sh1.cell_value(i, 0))] = [sh1.row_values(i)]# 检查数据
print(f'{name}')
# 新增数据
from xlutils.copy import copy
wc = copy(wb)
# print(len(list(name.keys())))
for i in range(len(list(name.keys()))):sh3 = wc.add_sheet(list(name.keys())[i])bb = 0for j in name[list(name.keys())[i]]:print(j)sh3.write(bb,0,j[0])sh3.write(bb,1,j[1])sh3.write(bb,2,j[2])sh3.write(bb,3,j[3])sh3.write(bb,4,j[4])bb+=1wc.save('data008.xlsx')
储存信息的格式:{‘a’:[[1],[2]],‘b’:[[1],[2]],‘c’:[[1],[2]]}
拿信息的时候,以键为名创建工作薄,然后遍历值,写入文件
openpyxl
- 读数据
from openpyxl import load_workbookwb = load_workbook('data01.xlsx')# 定位工作薄
sh1 = wb.active
sh2 = wb['Sheet1']print(sh1)
print(sh2)# 获取文件中所有工作薄的名称
print(wb.sheetnames)for i in wb.sheetnames: # 遍历输出工作薄的名称print(i)# 获取单个单元格的值
print(sh1.cell(2,3).value) # 如果没有value方法,就是一个cell对象
print(sh1['c2'].value)# 获取部分单元格的值,任意矩形内的值
print(sh1['c2':'d3'])
for row in sh1['c2':'d3']: # 获取到的是一个元组,按行构建的元组for i in row: # 把每一行再单独按列遍历print(i.value)# 获取一行/列数据,使用遍历取值
print(sh1['2']) # 2是execl里面行的标志
print(sh1['b']) # b是execl里面列的标志print(sh1[3:5]) # 获取从第3行到第5行的数据 ,每一行数据是一个元组# 这种方式和上面那个任意矩阵的效果一样
for row in sh1.iter_rows(min_row=3,max_row=5,min_col=2,max_col=4): # 可以指出行的起始位置和列的起始位置print(row)# 获取所有数据
for row in sh1.rows: # 按行遍历for i in row:print(i)for col in sh1.columns: # 按列遍历for i in col:print(i)print(sh1.max_row) # 获取最大行数
print(sh1.max_column) # 获取最大列数
- 写数据
from datetime import datefrom openpyxl import Workbookwb = Workbook()
# sh1 = wb.create_sheet('数据测试',0) # 创建工作薄,第一个是工作薄的名称,第二个是工作薄的位置# 写数据
sh1 = wb.active
sh1['a2']='nihao'
from openpyxl.styles import Font,colors
# 设置样式
fonts=Font(name='微软雅黑',size=30,italic=True,bold=True,color=colors.BLUE)
sh1['a2'].font = fontssh1['b3']='nihao'
fonts1=Font(name='微软雅黑',size=30,italic=True,bold=True,color='FFFF00') # 颜色可以去网上找颜色表
sh1['b3'].font = fonts1# 设置行高和列宽
sh1.row_dimensions[2].height = 100
sh1.column_dimensions['a'].width = 30# 设置单元格内容的位置,水平居中,垂直居中等等
from openpyxl.styles import Alignment
sh1.cell(2,1).alignment = Alignment(horizontal='right',vertical='top')# 单元格合并 只能在合并单元格的左上角那个坐标写内容,其他被合并的坐标无效
sh1.merge_cells('b1:e2') # 给出要合并的单元格坐标,只能是“左上角:右下角”坐标# 图表的数据
rows = [['Date', 'Batch 1', 'Batch 2', 'Batch 3'],[date(2020,12, 1), 40, 30, 25],[date(2020,12, 2), 40, 25, 30],[date(2020,12, 3), 50, 30, 45],[date(2020,12, 4), 30, 25, 40],[date(2020,12, 5), 25, 35, 30],[date(2020,12, 6), 20, 40, 35],
]# 一次插入一行数据
for i in rows:sh1.append(i)# 绘制图表
from openpyxl.chart import LineChart,PieChart
cc = LineChart()
cc.title = '折线图'
cc.x_axis.title = 'x轴名称'
cc.y_axis.title = 'y轴名称'# 给图表导入数据
from openpyxl.chart import Reference
data = Reference(sh1,min_col=2,min_row=1,max_col=4,max_row=7) # 第一行数据是图注
cc.add_data(data,titles_from_data=True) # 第二个参数是使用标题
sh1.add_chart(cc,'A9')cc1 = PieChart()
cc1.title = '饼图示例'# 饼图的数据引用有问题,修改如下:
# 1. 饼图通常只需要一列数据(一个数据系列)
# 2. 需要对应的标签数据
# 3. 避免引用不存在的列(原代码中引用了第5列,但实际只有4列数据)# 根据用户需求:使用第一行作为图注,第二列是数据
# 获取第二列的数据(Batch 1列)
data = Reference(sh1, min_col=2, max_col=2, min_row=2, max_row=7) # 选择第二列从第二行到第七行的数据
cc1.add_data(data, titles_from_data=False) # 不使用数据中的标题# 设置饼图的类别标签(使用第一行的标题)
labels = Reference(sh1, min_col=1, max_col=1, min_row=2, max_row=7) # 使用第一列(Date列)作为标签
cc1.set_categories(labels)# 添加到工作表
sh1.add_chart(cc1, 'j9')wb.save('data001.xlsx')
多文件操作
使用os库,定位一个目录,也就是文件夹,然后可以把想要操作的文件路径获取出来。就不用一个个输入文件路径/文件名了。
可以使用生产者消费者模式,一边读文件,一边写入新文件
在写入新文件的时候,可以让不同的文件,在这个新文件的不同工作薄,也可以放在同一个工作薄
-
隔行变色
- 可以使用if判断方式,使用随机数获取颜色的十六进制数。也可以控制循环的步长=2,就可以省略if判断,显的b格更高
-
生成工资条
- 就是一个文件中有所有人的工资详情,需要根据员工的名称生成每个员工独有的工资excel ,就是把工资详情的第一行和这个员工的信息合并,两行信息作为一个文件
-
使用公式
-
就是在excel里面有的时候,会用到计算公式,什么第几列加减第几列,我们使用openpyxl的时候获取单元格的值,是可以获取到这个公式的,但是我们不能直接把这个公式复制到新文件,必须让他计算出来
-
from openpyxl import load_workbook,Workbook # 第二个是需要导入的库wb = load_workbook('工资数据.xlsx',data_only=True) # 需要在读文件的时候加一个参数,就可以自动计算公式的值
-
python-docx 操作word
from docx import Document 在引入的时候,可以省略python关键字
和操作excel大同小异
# 导入库
from docx import Document
# 新建空白文档
doc1 = Document()
# 新增文档标题
doc1.add_heading('如何使用 Python 创建和操作 Word',level = 1)
# 保存文件
doc1.save('word1.docx')
-
add_heading第一个参数是标题的内容,第二个参数是标题的级别
-
add_paragraph 是添加段落,第一个参数是段落内容,第二个参数是段落等级
- 还可以使用style=‘List Bullet’,创建列表,List Bullet是无序列表,List Number是有序列表
doc1.add_paragraph('苹果', style='List Bullet')
- style=‘Intense Quote’ 是引用类型
-
add_run 给段落继续添加内容
-
add_picture 添加图片,默认情况下,添加的图像以原始大小显示
- 通过计算可以获取word里面纯文本的宽度
sc = (doc1.sections[0].page_width/10-doc1.sections[0].left_margin/10*2)/(width/10)
-
创建表格
-
table = doc1.add_table(rows=1, cols=3) hdr_cells = table.rows[0].cells hdr_cells[0].text = '编号' hdr_cells[1].text = '姓名' hdr_cells[2].text = '职业'
-
-
设置样式
-
p1.add_run('''这是内容!!1\n''').bold = True # 加粗 p1.add_run('''这是内容!!2\n''').italic = True # 斜体 p1.add_run('''这是内容!!3\n''').font.size = Pt(26) # 设置字号,需要导入Pt模块,参数就是字号 p1.add_run('''这是内容!!4\n''').font.strike = True # 删除线效果 p1.add_run('''这是内容!!5\n''').font.color.rgb = RGBColor(255,0,0) # 设置颜色,需要导入RGBColor模块 p1.add_run('''这是内容!!3\n''').font.name = '微软雅黑' # 设置字体# 设置对齐方式 from docx.enum.text import WD_ALIGN_PARAGRAPH doc1.add_paragraph('这是段落3:居中\n').paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # 居中 靠最后面那个center控制,left就是靠左.paragraph_format.left_indent=Inches(0.5)# 整段缩进 .paragraph_format.first_line_indent =Inches(0.5) # 首行缩进# 段落距离 paragraph_format.space_after = Pt(10) # 段后多少像素 paragraph_format.space_before = Pt(10) # 段前多少像素p2.paragraph_format.line_spacing = 1.5 # 设置行间距
-
-
读取文件
import docxdoc = docx.Document('word2.docx')for p in doc.paragraphs: # 只能获取非表格的内容print(p.text)for t in doc.tables: # 获取表格的内容for r in t.rows:for c in r.cells:print(c.text)
- 使用word模板+python 批量生成文件
- 把模板对应的位置进行替换
doc = docx.Document('word_模板.docx')
for p in doc.paragraphs: # 不可以直接对文本进行替换,因为会修改文本的样式for run in p.runs: # 对里面的runs进行替换,就可以保留样式了run.text = run.text.replace('{0}',info[0])run.text = run.text.replace('{1}',str(info[1]))run.text = run.text.replace('{2}',str(info[2]))run.text = run.text.replace('{3}',str(info[3]))run.text = run.text.replace('{4}',str(info[4]))run.text = run.text.replace('{5}',str(info[5]))run.text = run.text.replace('{6}',info[6])run.text = run.text.replace('{7}',str(info[7]))if not os.path.exists('./生成 word'):os.makedirs('./生成 word')
doc.save(f'./生成 word/车辆_{info[0]}.docx')
word-pdf
这是office自带的功能,但是一个个文件操作太麻烦,用python也可以实现这个过程
代码不需要去记,直接用
需要提前引入pywin32模块
文件的路径要使用绝对路径
from win32com.client import gencache
from win32com.client import constants, gencache
def createPdf(wordPath, pdfPath):""" word 转 pdf:param wordPath: word 文件路径:param pdfPath: 生成 pdf 文件路径""" word = gencache.EnsureDispatch('Word.Application')doc = word.Documents.Open(wordPath, ReadOnly=1)doc.ExportAsFixedFormat(pdfPath, constants.wdExportFormatPDF, Item=constants.wdExportDocumentWithMarkup,CreateBookmarks=constants.wdExportCreateHeadingBookmarks)word.Quit(constants.wdDoNotSaveChanges)
if __name__ == "__main__":createPdf('word2.docx','pdf1.pdf')
读pdf
有pypdf2模块,这个对中文不友好,不能识别
使用 pdfplumber模块,可以识别中文,有较大概率出错,最好的pdf识别方法是使用图像识别,文字识别的知识
import pdfplumber
with pdfplumber.open(path) as pdf: for i in range(len(pdf.pages)): #len(pdf.pages)为 PDF 文档页数page = pdf.pages[i] #pdf.pages[i] 是读取 PDF 文档第 i+1 页print(page.extract_text()) #page.extract_text()函数即读取文本内容,下面这步是去掉文档最下面的页码for page in pdf.pages: # 简化之后的,和上面的效果一样print(page.extract_text())
- 合并pdf 可以使用pypdf2 读文件,然后写入
- 加密pdf 就是把pdf重新写一遍,使用writer.encrypt设置密码 writer.decrypt是读文件的时候写密码
from PyPDF2 import PdfFileReader, PdfFileWriter
p = PdfFileReader(open(path,'rb'))
# writer.decrypt('123') # 解除密码
writer = PdfFileWriter()
writer.encrypt('123') # 设置密码
for page in range(p.getNumPages()):writer.addPage(p.getPage(page))
python-pptx 操作PPT
涉及面太浅了,局限性很大,跳过
可操作空间小
评价是不学
Python 暴力破解压缩密码
def passwd(path):# with as target:type = os.path.splitext(path)[-1][1:]if type == "zip":with zipfile.ZipFile(path,'r') as z:for l in z.infolist():# print(l.flag_bits)is_encrypted = 1if is_encrypted:for i in range(9999):try:z.extractall('./yasuo',pwd=str(i).encode('utf-8')) #pwd=str(i)是输入密码的地方print(f'密码是:{i}')breakexcept Exception as e:passelse:z.extractall('./yasuo')print('解压成功!')
def create_mi():import itertools as itswords = "abc" # 给出密码组合r =its.product(words,repeat=2) # repeat意思是构成两位数aa,ab等等for i in r:print(''.join(i))
破解密码最重要的就两个,一个是使用itertools模块,枚举所有密码组合,然后给zipfile模块里面的pwd参数不断尝试。