python操作excel主要用到openpyxl库。其主要针对xlsx格式的excel进行读取和编辑。下面简单介绍其使用方法及命令。除openpyxl库外,还有xlwt及xlwd也可以对excel表格实现同样操作。
python读excel——xlrd,比如读取日期、读合并单元格内容。
python写excel——xlwt
学习Python处理Excel首先要知道excel各个名词含义,其结构如下图:
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')
新建空白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')
Word文档的页面结构:
不放代码和运行结果,字体设置代码段(以宋体为例):
#设置字体
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,'宋体')
#导入库
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')
在 python-docx 包中则要使用节(section)中的页眉(header)和页脚(footer)对象来具体设置。
对齐设置
设置段落行距
设置字体属性
# 导入库
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
拆分思路:
读取 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)
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)
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())
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')
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)
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')
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)
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)
本文参考: 2021年6月26期_Python办公自动化