Python文件操作与PDF处理

1 文件基础操作

文件包括 文本文件和二进制文件(声音,图像,视频)。 从存储方式来说,文件在磁盘上的存储方式都是二进制形式,所以,文本文件其实也应该算二进制文件。先从他们的区别来说,虽然都是二进制文件,但是二进制代表的意思不一样。打个比方,一个人,我们可以叫他的大名,也叫他的小名,但其实都是代表这个人。二进制读写是将内存里面的数据直接读写入文本中,而文本呢,则是将数据先转换成了字符串,再写入到文本中。

1.1 读取文件

要以读取文件的模式打开一个文件对象,使用Python内置的 open() 函数,传入文件名和标示符:

f = open('/Users/michael/test.txt', 'r')

标示符’r’表示读,这样,我们就成功地打开了一个文件。
如果文件不存在,open() 函数就会抛出一个 IOError 的错误,并且给出错误码和详细的信息告诉你文件不存在:

f=open('/Users/michael/notfound.txt', 'r')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory:
'/Users/michael/notfound.txt'

如果文件打开成功,接下来,调用 read() 方法可以一次读取文件的全部内容,Python把内容读到内存,用一个 str 对象表示:

f.read()
'Hello, world!'

最后一步是调用 close() 方法关闭文件。文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的:

f.close()

由于文件读写时都有可能产生 IOError,一旦出错,后面的 f.close() 就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用 try … finally 来实现:

try:
   f = open('/path/to/file', 'r')
   print(f.read())
finally:
   if f:
       f.close()

但是每次都这么写实在太繁琐,所以,Python引入了 with 语句来自动帮我们调用 close() 方法:

with open('/path/to/file', 'r') as f:
   print(f.read())

这和前面的 try … finally 是一样的,但是代码更佳简洁,并且不必调用 f.close() 方法。调用 read() 会一次性读取文件的全部内容,如果文件有10G,内存就爆了,所以,要保险起见,可以反复调用 read(size) 方法,每次最多读取size个字节的内容。另外,调用 readline() 可以每次读取一行内容,调用 readlines() 一次读取所有内容并按行返回 list 。因此,要根据需要决定怎么调用。如果文件很小,read() 一次性读取最方便;如果不能确定文件大小,反复调用 read(size) 比较保险;如果是配置文件,调用 readlines() 最方便:

for line in f.readlines():
   print(line.strip()) # 把末尾的'\n'删掉

1.2 文件打开方式

模式 描述
r 以只读方式打开文件,文件的指针将会放在文件的开头,这是默认模式。
rb 以二进制格式打开一个文件用于只读,文件指针将会放在文件的开头。
r+ 打开一个文件用于读写,文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写,文件指针将会放在文件的开头。
w 打开一个文件只用于写入,如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

1.3 字符编码

要读取非UTF-8编码的文本文件,需要给 open() 函数传入 encoding 参数,例如,读取GBK编码的文件:

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
'测试'
f.read()

遇到有些编码不规范的文件,你可能会遇到 UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open() 函数还接收一个 errors 参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略:

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')

1.4 写文件

写文件和读文件是一样的,唯一区别是调用 open() 函数时,传入标识符 ‘w’ 或者 ‘wb’ 表示写文本文件或写二进制文件:

f = open('/Users/michael/test.txt', 'w')
f.write('Hello, world!')
f.close()

你可以反复调用 write() 来写入文件,但是务必要调用 f.close() 来关闭文件。当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close() 方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用 close() 的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用 with 语句来得保险:

with open('/Users/michael/test.txt', 'w') as f:
   f.write('Hello, world!')

要写入特定编码的文本文件,请给 open() 函数传入 encoding 参数,将字符串自动转换成指定编码。
注意:以 ‘w’ 模式写入文件时,如果文件已存在,会直接覆盖(相当于删掉后新写入一个文件)。如果我们希望追加到文件末尾怎么办?可以传入 ‘a’ 以追加(append)模式写入。

2 PDF基础操作

安装pdfplumber,PyPDF2,pypiwin32

pip install pdfplumber
pip install PyPDF2
pip install pypiwin32      # 该模块只能win系统使用
如果安装速度特别慢 或者安装最后出现time out的错误 可以使用国内镜像进行安装
pip install xxx -i 国内镜像
常用国内镜像如下
(1)阿里云 http://mirrors.aliyun.com/pypi/simple/
(2)豆瓣   http://pypi.douban.com/simple/
(3)清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
(4)中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
(5)华中科技大学  http://pypi.hustunique.com/

导入本次课所需的框架

from PyPDF2 import PdfFileReader, PdfFileWriter
import pdfplumber
import pandas as pd
import os

定义所需合并的PDF的路径和合并后文件的名称以及存放路径

dir_path = 'C:/Users/Administrator/Desktop/files'
# 此处路径一定要写绝对路径,相对路径会出现问题
new_name = 'all_pdf.pdf'
new_pdf_path = 'C:/Users/Administrator/Desktop/new_files'
pdf_path = os.path.join(dir_path, 'first.pdf')

2.1 读取PDF

2.1.1 读取PDF文字内容

# 创建pdf文件对象
pdf = pdfplumber.open(pdf_path)
# 获得所有的页数
pdf_pages = len(pdf.pages)
pdf_pages
# 获取指定第1页的文字内容
first_page = pdf.pages[0]
first_page
# extract_text()获取当前页面的文本值
first_page.extract_text()
for i in range(0, pdf_pages):
   # 遍历当前所有的页面, 输出全部的文本值
   print(pdf.pages[i].extract_text())

2.1.2 读取PDF表格内容

# 获取第1页的表格
pdf.pages[0].extract_table()
# 定义一个列表 存储该pdf种所有的表格
all_content = []
# 获取该PDF种的所有表格
for i in range(0, pdf_pages):
   # 此处不使用extract_table(),因为如果当前页面没有表格extract_table()会报错
   # extract_tables()返回的是[[每一行内容]]这种嵌套格式
   # 如果直接添加会把每一个页面的内容作为一个元素添加到all_content,写入Excel时就会出现错乱的问题
   # pdf.pages[i].extract_tables()
   for j in pdf.pages[i].extract_tables():
       # 在读取没有表格的页时,extract_tables()会返回一个带有空字符串的列表,所以我们要判断一下
       for k in j:
           if '' not in k:
               all_content.append(k)
               print(k)
# 转换为DataFrame, 方便存到Excel中
data = pd.DataFrame(all_content )
print(data)
data.to_excel('pdf_table.xlsx', index=False, header=None)

2.3 合并PDF

该功能需要使用到os模块获取文件路径以及pypdf2模块中的PdfFileWriter进行生成一个新的PDF和PdfFileReader读取需要合并的PDF

pdf_paths = []
# 定义一个列表来存储所有的pdf路径
for file_name in os.listdir(dir_path):
# 使用os模块获得dir_path路径下的所有文件
if '.pdf' in file_name:
      # 判断是否是pdf文件,如果是就加到列表中
      pdf_paths.append(os.path.join(dir_path, file_name))
new_pdf = PdfFileWriter()
# 记录pdf的总页数
numPages = 0    
for pdfpath in pdf_paths:
  # PdfFileReader()参数为文件路径/文件对象
  # 如果该步骤出问题   多半是PDF文件有问题
  old_pdf = PdfFileReader(open(pdfpath, 'rb'))
  # 获取当前pdf的页数
  pdfPages = old_pdf.getNumPages()
  numPages += pdfPages
  for i in range(old_pdf.getNumPages()): 
    # 根据当前页数一次添加到合并的PDF对象中
    new_pdf.addPage(old_pdf.getPage(i))
with open(os.path.join(new_pdf_path, new_name), 'wb') as p:
new_pdf.write(p)

2.4 Word转PDF

# 本方法是直接使用win32com调用word中的接口进行转换为PDF,相当于用代码点击word中的转换为PDF
# 此种方式只适合win电脑, mac没有提供该模块的安装
from win32com.client import gencache
from win32com.client import constants, gencache
def word_Pdf(word_Path, pdf_Path):
   # 调用word程序 并返回一个可执行的对象
   word = gencache.EnsureDispatch('Word.Application')
   
   docx = word.Documents.Open(word_Path, ReadOnly=1)
   docx.ExportAsFixedFormat(pdf_Path,constants.wdExportFormatPDF,
Item=constants.wdExportDocumentWithMarkup,CreateBookmarks=constants.wdExportCrea
teHeadingBookmarks)
   word.Quit(constants.wdDoNotSaveChanges)
   
word_Pdf("C:/Users/Administrator/Desktop/happy.docx"
,"C:/Users/Administrator/Desktop/res.pdf")

2.5 PDF添加水印

from PyPDF2 import PdfFileReader, PdfFileWriter
'''
PDF加水印就是将水印PDF和要加水印的PDF进行合并
'''
# 页的合并
pdf = PdfFileReader('C:/Users/Administrator/Desktop/files/first.pdf')
water_pdf = PdfFileReader('C:/Users/Administrator/Desktop/files/water.pdf')
# 准备要合并的两个页面
water = water_pdf.getPage(0)
for i in range(pdf.getNumPages()):
writer = PdfFileWriter()
   # 使用页对象中的方法mergePage进行合并
   pdf.getPage(i).mergePage(water)
   #添加到新的PDF中
   writer.addPage(pdf.getPage(i))
# 此处参数必须写文件对象
writer.write(open('newres.pdf', 'wb'))

猜你喜欢

转载自blog.csdn.net/qq_36783816/article/details/111315516