159 lines
6.3 KiB
Markdown
159 lines
6.3 KiB
Markdown
|
## 第27课:用Python操作PDF文件
|
|||
|
|
|||
|
PDF是Portable Document Format的缩写,这类文件通常使用`.pdf`作为其扩展名。在日常开发工作中,最容易遇到的就是从PDF中读取文本内容以及用已有的内容生成PDF文档这两个任务。
|
|||
|
|
|||
|
### 从PDF中提取文本
|
|||
|
|
|||
|
在Python中,可以使用名为`PyPDF2`的三方库来读取PDF文件,可以使用下面的命令来安装它。
|
|||
|
|
|||
|
```Bash
|
|||
|
pip install PyPDF2
|
|||
|
```
|
|||
|
|
|||
|
`PyPDF2`没有办法从PDF文档中提取图像、图表或其他媒体,但它可以提取文本,并将其返回为Python字符串。
|
|||
|
|
|||
|
```Python
|
|||
|
import PyPDF2
|
|||
|
|
|||
|
reader = PyPDF2.PdfFileReader('test.pdf')
|
|||
|
page = reader.getPage(0)
|
|||
|
print(page.extractText())
|
|||
|
```
|
|||
|
|
|||
|
> **提示**:上面代码中使用的PDF文件“test.pdf”以及下面的代码中需要用到的PDF文件,都可以通过后面的百度云盘地址进行获取。链接:https://pan.baidu.com/s/1rQujl5RQn9R7PadB2Z5g_g 提取码:e7b4。
|
|||
|
|
|||
|
当然,`PyPDF2`并不是什么样的PDF文档都能提取出文字来,这个问题就我所知并没有什么特别好的解决方法,尤其是在提取中文的时候。网上也有很多讲解从PDF中提取文字的文章,推荐大家自行阅读[《三大神器助力Python提取pdf文档信息》](https://cloud.tencent.com/developer/article/1395339)一文进行了解。
|
|||
|
|
|||
|
要从PDF文件中提取文本也可以直接使用三方的命令行工具,具体的做法如下所示。
|
|||
|
|
|||
|
```Bash
|
|||
|
pip install pdfminer.six
|
|||
|
pdf2text.py test.pdf
|
|||
|
```
|
|||
|
|
|||
|
### 旋转和叠加页面
|
|||
|
|
|||
|
上面的代码中通过创建`PdfFileReader`对象的方式来读取PDF文档,该对象的`getPage`方法可以获得PDF文档的指定页并得到一个`PageObject`对象,通过`PageObject`对象的`rotateClockwise`和`rotateCounterClockwise`方法可以实现页面的顺时针和逆时针方向旋转,通过`PageObject`对象的`addBlankPage`方法可以添加一个新的空白页,代码如下所示。
|
|||
|
|
|||
|
```Python
|
|||
|
import PyPDF2
|
|||
|
|
|||
|
from PyPDF2.pdf import PageObject
|
|||
|
|
|||
|
# 创建一个读PDF文件的Reader对象
|
|||
|
reader = PyPDF2.PdfFileReader('resources/XGBoost.pdf')
|
|||
|
# 创建一个写PDF文件的Writer对象
|
|||
|
writer = PyPDF2.PdfFileWriter()
|
|||
|
# 对PDF文件所有页进行循环遍历
|
|||
|
for page_num in range(reader.numPages):
|
|||
|
# 获取指定页码的Page对象
|
|||
|
current_page = reader.getPage(page_num) # type: PageObject
|
|||
|
if page_num % 2 == 0:
|
|||
|
# 奇数页顺时针旋转90度
|
|||
|
current_page.rotateClockwise(90)
|
|||
|
else:
|
|||
|
# 偶数页反时针旋转90度
|
|||
|
current_page.rotateCounterClockwise(90)
|
|||
|
writer.addPage(current_page)
|
|||
|
# 最后添加一个空白页并旋转90度
|
|||
|
page = writer.addBlankPage() # type: PageObject
|
|||
|
page.rotateClockwise(90)
|
|||
|
# 通过Writer对象的write方法将PDF写入文件
|
|||
|
with open('resources/XGBoost-modified.pdf', 'wb') as file:
|
|||
|
writer.write(file)
|
|||
|
```
|
|||
|
|
|||
|
### 加密PDF文件
|
|||
|
|
|||
|
使用`PyPDF2`中的`PdfFileWrite`对象可以为PDF文档加密,如果需要给一系列的PDF文档设置统一的访问口令,使用Python程序来处理就会非常的方便。
|
|||
|
|
|||
|
```Python
|
|||
|
import PyPDF2
|
|||
|
|
|||
|
reader = PyPDF2.PdfFileReader('resources/XGBoost.pdf')
|
|||
|
writer = PyPDF2.PdfFileWriter()
|
|||
|
for page_num in range(reader.numPages):
|
|||
|
writer.addPage(reader.getPage(page_num))
|
|||
|
# 通过encrypt方法加密PDF文件,方法的参数就是设置的密码
|
|||
|
writer.encrypt('foobared')
|
|||
|
with open('resources/XGBoost-encrypted.pdf', 'wb') as file:
|
|||
|
writer.write(file)
|
|||
|
```
|
|||
|
|
|||
|
### 批量添加水印
|
|||
|
|
|||
|
上面提到的`PageObject`对象还有一个名为`mergePage`的方法,可以两个PDF页面进行叠加,通过这个操作,我们很容易实现给PDF文件添加水印的功能。例如要给上面的“XGBoost.pdf”文件添加一个水印,我们可以先准备好一个提供水印页面的PDF文件,然后将包含水印的`PageObject`读取出来,然后再循环遍历“XGBoost.pdf”文件的每个页,获取到`PageObject`对象,然后通过`mergePage`方法实现水印页和原始页的合并,代码如下所示。
|
|||
|
|
|||
|
```Python
|
|||
|
import PyPDF2
|
|||
|
|
|||
|
from PyPDF2.pdf import PageObject
|
|||
|
|
|||
|
reader1 = PyPDF2.PdfFileReader('resources/XGBoost.pdf')
|
|||
|
reader2 = PyPDF2.PdfFileReader('resources/watermark.pdf')
|
|||
|
writer = PyPDF2.PdfFileWriter()
|
|||
|
# 获取水印页
|
|||
|
watermark_page = reader2.getPage(0)
|
|||
|
for page_num in range(reader1.numPages):
|
|||
|
current_page = reader1.getPage(page_num) # type: PageObject
|
|||
|
current_page.mergePage(watermark_page)
|
|||
|
# 将原始页和水印页进行合并
|
|||
|
writer.addPage(current_page)
|
|||
|
# 将PDF写入文件
|
|||
|
with open('resources/XGBoost-watermarked.pdf', 'wb') as file:
|
|||
|
writer.write(file)
|
|||
|
```
|
|||
|
|
|||
|
如果愿意,还可以让奇数页和偶数页使用不同的水印,大家可以自己思考下应该怎么做。
|
|||
|
|
|||
|
### 创建PDF文件
|
|||
|
|
|||
|
创建PDF文档需要三方库`reportlab`的支持,安装的方法如下所示。
|
|||
|
|
|||
|
```Bash
|
|||
|
pip install reportlab
|
|||
|
```
|
|||
|
|
|||
|
下面通过一个例子为大家展示`reportlab`的用法。
|
|||
|
|
|||
|
```Python
|
|||
|
from reportlab.lib.pagesizes import A4
|
|||
|
from reportlab.pdfbase import pdfmetrics
|
|||
|
from reportlab.pdfbase.ttfonts import TTFont
|
|||
|
from reportlab.pdfgen import canvas
|
|||
|
|
|||
|
pdf_canvas = canvas.Canvas('resources/demo.pdf', pagesize=A4)
|
|||
|
width, height = A4
|
|||
|
|
|||
|
# 绘图
|
|||
|
image = canvas.ImageReader('resources/guido.jpg')
|
|||
|
pdf_canvas.drawImage(image, 20, height - 395, 250, 375)
|
|||
|
|
|||
|
# 显示当前页
|
|||
|
pdf_canvas.showPage()
|
|||
|
|
|||
|
# 注册字体文件
|
|||
|
pdfmetrics.registerFont(TTFont('Font1', 'resources/fonts/Vera.ttf'))
|
|||
|
pdfmetrics.registerFont(TTFont('Font2', 'resources/fonts/青呱石头体.ttf'))
|
|||
|
|
|||
|
# 写字
|
|||
|
pdf_canvas.setFont('Font2', 40)
|
|||
|
pdf_canvas.setFillColorRGB(0.9, 0.5, 0.3, 1)
|
|||
|
pdf_canvas.drawString(width // 2 - 120, height // 2, '你好,世界!')
|
|||
|
pdf_canvas.setFont('Font1', 40)
|
|||
|
pdf_canvas.setFillColorRGB(0, 1, 0, 0.5)
|
|||
|
pdf_canvas.rotate(18)
|
|||
|
pdf_canvas.drawString(250, 250, 'hello, world!')
|
|||
|
|
|||
|
# 保存
|
|||
|
pdf_canvas.save()
|
|||
|
```
|
|||
|
|
|||
|
上面的代码如果不太理解也没有关系,等真正需要用Python创建PDF文档的时候,再好好研读一下`reportlab`的[官方文档](https://www.reportlab.com/docs/reportlab-userguide.pdf)就可以了。
|
|||
|
|
|||
|
> **提示**:上面代码中用到的图片和字体,可以在后面的百度云盘链接中获取。链接:https://pan.baidu.com/s/1rQujl5RQn9R7PadB2Z5g_g 提取码:e7b4。
|
|||
|
|
|||
|
### 简单的总结
|
|||
|
|
|||
|
在学习完上面的内容之后,相信大家已经知道像合并多个PDF文件这样的工作应该如何用Python代码来处理了,赶紧自己动手试一试吧。
|