第八周

python学习笔记和做的一些习题 (python编程快速上手——让繁琐工作自动化

第十三章 处理PDF和Word文档

PDF文档

用于处理PDF的模块是PyPDF2,需要注意的是安装这个模块,就从命令行运行pip install PyPDF2。 这个模块名称是区分大小写的,所以要确保 y 是小写,其他字母都是大写。

从PDF提取文本

PyPDF2 没有办法从 PDF 文档中提取图像、图表或其他媒体,但它可以提取文 本,并将文本返回为 Python 字符串。

import PyPDF2
#以读二进制模式打开 meetingminutes.pdf,并将 它保存在 pdfFileObj 中
pdfFileObj = open('meetingminutes.pdf','rb')
#调用 PyPDF2. PdfFileReader()并向它传入pdfFileObj
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
#获取该文档的总页数
pdfReader.numPages
#调用 PdfFileReader 对象的 getPage()方法要从一页中提取文本
pageObj = pdfReader.getPage(0)
#在取得 Page 对象后,调用它的 extractText()方法,返回该页文本的字符串
pageObj.extractText()
解密PDF

某些 PDF文档有加密功能,以防止别人阅读,只有在打开文档时提供口令才能阅读。

import PyPDF2
pdfReader = PyPDF2.PdfFileReader(open('encrypted.pdf', 'rb'))
#PdfFileReader 对象都有一个 isEncrypted 属性,判断PDF是否加密,如果 PDF 是加密的,它就 是 True
pdfReader.isEncrypted
#调用 decrypt()函数,传入口令字符串
pdfReader.decrypt('rosebud')
#调用函数 来读取文件
pageObj = pdfReader.getPage(0)

注意:在文件用正确的口令解密之前,尝试调用函数 来读取文件,将会导致错误。在用正确的口令调用 decrypt()后,你会看到调用 getPage()不再导致错误。如果提供了错误的口令,decrypt()函数将返回0,并且 getPage()会继续失败。请注意,decrypt()方法只解密了 PdfFileReader 对象,而不是实际的 PDF 文件。在程序中止后,硬盘上的文件仍然是加密的。程序下次运行时,仍然需要再次调用decrypt()。

创建PDF

在 PyPDF2 中,与 PdfFileReader 对象相对的是 PdfFileWriter 对象,它可以创建 一个新的 PDF 文件。但 PyPDF2 不能将任意文本写入 PDF,就像 Python 可以写入 纯文本文件那样。PyPDF2 写入 PDF 的能力,仅限于从其他 PDF 中拷贝页面、旋转 页面、重叠页面和加密文件。

拷贝页面

可以利用 PyPDF2,从一个 PDF 文档拷贝页面到另一个 PDF 文档。这让你能够 组合多个 PDF 文件,去除不想要的页面,或调整页面的次序。``

import PyPdf2
#以读二进制的模式打开两个 PDF 文件,将得到的两个 File 对象保存在 pdf1File 和 pdf2File中
pdf1File = open('meetingminutes.pdf', 'rb')
pdf2File = open('meetingminutes2.pdf', 'rb')
#调用PyPDF2.PdfFileReader(),传入pdf1File
pdf1Reader = PyPDF2.PdfFileReader(pdf1File)
pdf2Reader = PyPDF2.PdfFileReader(pdf2File)
#然后创建一个新的 PdfFileWriter 对象,它表示一个空白的 PDF 文档
pdfWriter = PyPDF2.PdfFileWriter()
#从两个源 PDF 拷贝所有的页面,将它们添加到 PdfFileWriter 对象
for pageNum in range(pdf1Reader.numPages):
    #在 PdfFileReader 对象上调用 getPage(),取得 Page 对象
     pageObj = pdf1Reader.getPage(pageNum)
     #然后将这个 Page 对象传递 给PdfFileWriter 的addPage()方法
     pdfWriter.addPage(pageObj)

for pageNum in range(pdf2Reader.numPages):
    pageObj = pdf2Reader.getPage(pageNum)
    pdfWriter.addPage(pageObj)

pdfOutputFile = open('combinedminutes.pdf', 'wb')
pdfWriter.write(pdfOutputFile)
pdfOutputFile.close()
pdf1File.close()
pdf2File.close()
旋转页面

利用 rotateClockwise()和 rotateCounterClockwise()方法,PDF 文档的页面也可以 旋转 90 度的整数倍。向这些方法传入整数 90、180 或 270 就可以了。

import PyPDF2
minutesFile = open('meetingminutes.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(minutesFile)
#使用 getPage(0)来选择 PDF 的第一页
page = pdfReader.getPage(0)
#调用 rotateClockwise(90),使页面旋转
page.rotateClockwise(90)
pdfWriter = PyPDF2.PdfFileWriter()
pdfWriter.addPage(page)
#我们将旋转过的页面写入一个新的 PDF 文档,并保存为 rotatedPage.pdf
resultPdfFile = open('rotatedPage.pdf', 'wb')
pdfWriter.write(resultPdfFile)
resultPdfFile.close()
minutesFile.close()
叠加页面
import PyPDF2
minutesFile = open('meetingminutes.pdf', 'rb') 
#生成 meetingminutes.pdf 的 PdfFileReader 对象
pdfReader = PyPDF2.PdfFileReader(minutesFile)
#调用 getPage(0), 取得第一页的 Page对象,并将它保存在 minutesFirstPage中
minutesFirstPage = pdfReader.getPage(0)
#生成了watermark.pdf 的PdfFileReader对象
pdfWatermarkReader = PyPDF2.PdfFileReader(open('watermark.pdf', 'rb'))
#在minutesFirstPage上调用 mergePage(),传递给mergePage() 的参数,是 watermark.pdf 第一页的 Page 对象。
#minutesFirstPage 代 表加了水印的第一页
minutesFirstPage.mergePage(pdfWatermarkReader.getPage(0))
#创建一个 PdfFileWriter 对象
pdfWriter = PyPDF2.PdfFileWriter()
#加入加了水印的第一页
pdfWriter.addPage(minutesFirstPage)
#循环遍历 meetingminutes.pdf 的剩余页面,将它们添加到PdfFileWriter 对象中
for pageNum in range(1, pdfReader.numPages):
    pageObj = pdfReader.getPage(pageNum)
    pdfWriter.addPage(pageObj)
resultPdfFile = open('watermarkedCover.pdf', 'wb')
pdfWriter.write(resultPdfFile)
minutesFile.close()
resultPdfFile.close()
加密PDF
import PyPDF2
pdfFile = open('meetingminutes.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFile)
pdfWriter = PyPDF2.PdfFileWriter() 
for pageNum in range(pdfReader.numPages):
    pdfWriter.addPage(pdfReader.getPage(pageNum))
#在调用 write()方法保存文件之前,调用encrypt()方法,传入口令字符串
pdfWriter.encrypt('swordfish')
resultPdf = open('encryptedminutes.pdf', 'wb')
pdfWriter.write(resultPdf)
resultPdf.close()

PDF可 以有一个用户口令(允许查看这个 PDF)和一个拥有者口令(允许设置打印、注释、 提取文本和其他功能的许可)。用户口令和拥有者口令分别是 encrypt()的第一个和第二 个参数。如果只传入一个字符串给 encrypt(),它将作为两个口令。

项目:从多个PDF中合并选择的页面
import PyPDF2, os

#找到所有PDF文件
pdfFiles = []
for filename in os.listdir('.'):
    if filename.endswith('.pdf'):
        #代码循环遍历这个列表, 将带有.pdf 扩展名的文件添加到 pdfFiles 中
        pdfFiles.append(filename)
#列表按照字典顺序排序,调 用 sort()时带有 key/str.lower 关键字参数
pdfFiles.sort(key/str.lower)
#代码创建了一个 PdfFileWriter 对象,保存合并后的 PDF 页面
pdfWriter = PyPDF2.PdfFileWriter()

#打开每个PDF文件
for filename in pdfFiles:
    #用读二进 制的模式打开文件
    pdfFileObj = open(filename, 'rb')
    #创建针对那个 PDF 文件的 PdfFileReader 对象
    pdfReader = PyPDF2.PdfFileReader(pdfFileObj) 

    #添加每一页
    #将每个 Page 对象拷贝到 PdfFileWriter 对象,需要跳过第一页
    for pageNum in range(1, pdfReader.numPages):
        pageObj = pdfReader.getPage(pageNum)
        pdfWriter.addPage(pageObj)

#保存结果
pdfOutput = open('allminutes.pdf', 'wb')
pdfWriter.write(pdfOutput)
pdfOutput.close()
Word文档
读取Word文档
import docx
#打开了一个.docx 文件,调用 docx.Document(),传入 文件名 demo.docx
doc = docx.Document('demo.docx')
#paragraphs 属性,是 Paragraph 对象的列表
len(doc.paragraphs)
#每个 Paragraph 对象都有一个 text 属性,包含该段中文本的字符串
doc.paragraphs[0].text
doc.paragraphs[1].text
#每个 Paragraph 对象也有一个 runs 属性,它是 Run 对象的列表。
len(doc.paragraphs[1].runs)
#Run 对象也有 一个 text 属性,包含那个延续中的文本
doc.paragraphs[1].runs[0].text
从.docx文件中取得完整的文本

如果你只关心 Word 文档中的文本,不关心样式信息,就可以利用 getText()函数。它接受一个.docx 文件名,返回其中文本的字符串:

import docx 
 
def getText(filename):     
    doc = docx.Document(filename)     
    fullText = []     
    for para in doc.paragraphs:
        fullText.append(para.text)     
    return '\n'.join(fullText)
设置Paragraph和Run对象的样式

对于 Word 文档,有 3 种类型的样式:段落样式可以应用于 Paragraph 对象,字符样式可以应用于 Run 对象,链接的样式可以应用于这两种对象。可以将 Paragraph 和 Run 对象的 style 属性设置为一个字符串,从而设置样式。这个字符串应该是一种样 式的名称。如果 style 被设置为 None,就没有样式与 Paragraph 或 Run 对象关联。

默认Word样式的字符串:

python 根据左右边界提取word内容 python取文本右边_取文本


注意:在设置 style 属性时,不要在样式名称中使用空格;如果对 Run 对象应用链接的样式,需要在样式名称末尾加上’Char’。

创建带有非默认样式的Word文档

如果想要创建的Word文档使用默认样式以外的样式,就需要打开一个空白Word 文档,通过点击样式窗口底部的 New Style 按钮,自己创建样式。 然后,回到交互式环境,用 docx.Document()打开这个空白 Word 文档,利用它作为 Word 文档的基础。这种样式的名称现在就可以被 python-docx 使用了。

Run属性

通过 text 属性,Run 可以进一步设置样式。每个属性都可以被设置为 3 个值之 一:True(该属性总是启用,不论其他样式是否应用于该 Run)、 False(该属性总是 禁用)或 None(默认使用该 Run 被设置的任何属性)
Run对象的text属性:

属性

描述

bold

文本以粗体出现

italic

文本以斜体出现

underline

文本带下划线

strike

文本带删除线

double_strike

文本带双删除线

all_caps

文本以大写首字母出现

small_caps

文本以大写首字母出现,小写字母小两个点

shadow

文本带阴影

outline

文本以轮廓线出现,而不是实心

rtl

文本从右至左书写

imptint

文本以刻入页面的方式出现

emboss

文本以凸出页面的方式出现

写入Word文档
import docx
doc = docx.Document()
doc.add_paragraph('Hello world!')
doc.save('helloworld.docx')

可以用新的段落文本,再次调用 add_paragraph()方法,添加段落。或者,要在已有段落的末尾添加文``本,可以调用 Paragraph 对象的 add_run()方法,向它传入一 个字符串。

import docx
doc = docx.Document()
doc.add_paragraph('Hello world!')
#添加段落
paraObj1 = doc.add_paragraph('This is a second paragraph.')
paraObj2 = doc.add_paragraph('This is a yet another paragraph.')
#要在已有段落的末尾添加文本
paraObj1.add_run(' This text is being added to the second paragraph.') 
doc.save('helloworld.docx')
添加标题

调用 add_heading()将添加一个段落,并使用一种标题样式。add_heading()的参数,是一个标题文本的字符串,以及一个从 0 到 4 的整数。整 数 0 表示标题是 Title 样式,这用于文档的顶部。整数 1 到 4 是不同的标题层次,1是主要的标题,4 是最低层的子标题。add_heading()返回一个 Paragraph 对象,让你 不必多花一步从 Document 对象中提取它。

添加换行符和换页符

要添加换行符(而不是开始一个新的段落),可以在 Run 对象上调用 add_break()方 法,换行符将出现在它后面。如果希望添加换页符,可以将docx.text.WD_BREAK.PAGE 作为唯一的参数,传递给add_break()。

添加图像

Document 对象有一个 add_picture()方法,让你在文档末尾添加图像。第一个参数是一个字符串,表示图像的文件名。可选的 width 和 height 关键字 参数,将设置该图像在文档中的宽度和高度。