亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python中使用pypdf2合并、分割、加密pdf文件的代碼詳解

系統(tǒng) 1736 0

朋友需要對(duì)一個(gè)pdf文件進(jìn)行分割,在網(wǎng)上查了查發(fā)現(xiàn)這個(gè)pypdf2可以完成這些操作,所以就研究了下這個(gè)庫(kù),并做一些記錄。首先pypdf2是python3版本的,在之前的2版本有一個(gè)對(duì)應(yīng)pypdf庫(kù)。

可以使用pip直接安裝:

pip install pypdf2

官方文檔: pythonhosted.org/PyPDF2/

里面主要有這幾個(gè)類:

PdfFileReader 。

該類主要提供了對(duì)pdf文件的讀操作,其構(gòu)造方法為:

            
PdfFileReader(stream, strict=True, warndest=None, overwriteWarnings=True)
          

第一個(gè)參數(shù)可以傳入一個(gè)文件流,或者一個(gè)文件路徑。后面三個(gè)參數(shù)都是用來設(shè)置警告的處理方式,直接使用默認(rèn)的即可。

得到實(shí)例之后,就可以對(duì)pdf進(jìn)行一些操作了。主要的有以下幾個(gè)操作:

  • decrypt(password):如果pdf文件加密的話,可以使用該方法對(duì)其解密。
  • getDocumentInfo():檢索pdf文件的一些信息。其返回值為一個(gè)DocumentInformation 類型,直接輸出的話會(huì)得到類似下面的信息:
            
{'/ModDate': "D:20150310202949-07'00'", '/Title': '', '/Creator': 'LaTeX with hyperref package', '/CreationDate': "D:20150310202949-07'00'", '/PTEX.Fullbanner': 'This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014/MacPorts 2014_6) kpathsea version 6.2.0', '/Producer': 'pdfTeX-1.40.15', '/Keywords': '', '/Trapped': '/False', '/Author': '', '/Subject': ''}
          

  • getNumPages():這個(gè)會(huì)pdf文件中的頁(yè)數(shù)。
  • getPage(pageNumber):會(huì)得到pdf文件中對(duì)應(yīng)的pageNumber頁(yè)數(shù)的頁(yè)面對(duì)象,返回值為PageObject實(shí)例。在得到PageObject實(shí)例之后就可以將其加添、插入等操作。
  • getPageNumber(page):與上面的方法對(duì)立,可以傳入PageObject實(shí)例,然后得到該實(shí)例是pdf文件中第幾頁(yè)的。
  • getOutlines(node=None, outlines=None):檢索文檔中出現(xiàn)的文檔大綱。
  • isEncrypted:記錄該pdf是否加密。如果文件本身加密,即使在使用解密decrypt方法之后,還是會(huì)返回true。
  • numPages:pdf總共的頁(yè)數(shù),相當(dāng)于訪問getNumPages()的只讀屬性。

PdfFileWriter 。

該類支持對(duì)pdf文件進(jìn)行寫操作,通常是使用PdfFileReader讀取一些pdf數(shù)據(jù),然后使用該類進(jìn)行一些操作。

創(chuàng)建該類的實(shí)例時(shí)不需要參數(shù)。

其主要的方法有:

  • addAttachment(fname, fdata):向pdf添加文件。
  • addBlankPage(width=None, height=None):給pdf添加一個(gè)空白頁(yè)到最后,如果沒有指定大小就使用當(dāng)前Weiter中pdf最后一頁(yè)的大小。
  • addPage(page):添加page到pdf中,通常這個(gè)page是由上面的Reader獲取的。
  • appendPagesFromReader(reader, after_page_append=None):將reader中的數(shù)據(jù)拷貝到當(dāng)前的Writer實(shí)例中,并且如果指定after_page_append的話,最后還有回掉該函數(shù)并且將writer中的數(shù)據(jù)傳入其中。
  • encrypt(user_pwd, owner_pwd=None, use_128bit=True):將pdf進(jìn)行加密,其中官方說userpwd是允許用戶使用一些限制的權(quán)限打開pdf文件,也就是使用該密碼的話可能會(huì)有一些限制,但是本人并沒有在文檔中找到設(shè)置權(quán)限的內(nèi)容。而ownerpwd則是允許用戶無(wú)限制的使用。第三個(gè)參數(shù)是是否使用128位加密。
  • getNumPages():得到pdf頁(yè)數(shù)。
  • getPage(pageNumber):得到對(duì)應(yīng)頁(yè)數(shù)的Page,是一個(gè)PageObject對(duì)象,可以使用上面的addPage方法將page進(jìn)行添加。
  • insertPage(page, index=0):將page添加到pdf中,index指定的是被插入的位置。
  • write(stream):將該Writer中的內(nèi)容寫入到文件中。

PdfFileMerger。

該類用來合并pdf文件,該類的構(gòu)造方法有一個(gè)參數(shù):PdfFileMerger(strict=True),注意這里的參數(shù)后面會(huì)介紹:

常用方法:

  • addBookmark(title, pagenum, parent=None):給pdf添加一個(gè)書簽,title是書簽的標(biāo)題,pagenum是該書簽指向的頁(yè)面。
  • append(fileobj, bookmark=None, pages=None, import_bookmarks=True):將指定的fileobj文件添加到文件的末尾,bookmark是贖前,pages可以使用(start, stop[, step])或者一個(gè) Page Range來設(shè)定將fileobj中的指定范圍的頁(yè)面進(jìn)行添加。
  • merge(position, fileobj, bookmark=None, pages=None, import_bookmarks=True):與append方法類似,不過可以使用position參數(shù)指定添加的位置。
  • write(fileobj):將數(shù)據(jù)寫入到文件中。

使用的時(shí)候可以創(chuàng)建一個(gè)PdfFileMerger實(shí)例,然后使用append或者merge將想要融合的pdf文件依次添加進(jìn)去,最后使用write保存即可。

            
def merge_pdf():
  # 創(chuàng)建一個(gè)用來合并文件的實(shí)例
  pdf_merger = PdfFileMerger()

  # 首先添加一個(gè)Week1_1.pdf文件
  pdf_merger.append('Week1_1.pdf')
  # 然后在第0頁(yè)后面添加ex1.pdf文件
  pdf_merger.merge(0, 'ex1.pdf')
  # 添加書簽
  pdf_merger.addBookmark('這是一個(gè)書簽', 1)
  # 將其寫入到文件中
  pdf_merger.write('merge_pdf.pdf')
          

下面看一下 PdfFileMerger(strict=True) 中的這個(gè)參數(shù):

官方對(duì)這個(gè)參數(shù)的解釋:

strict (bool) ?C Determines whether user should be warned of all problems and also causes some correctable problems to be fatal. Defaults to True.

確定是否應(yīng)該警告用戶所有問題,并且還會(huì)導(dǎo)致一些可糾正的問題。

剛開始感覺這個(gè)參數(shù)就是用來是否警告用戶一些錯(cuò)誤的,直接使用默認(rèn)即可,但是當(dāng)本人嘗試合并帶中文的pdf時(shí),出現(xiàn)了如下錯(cuò)誤:

            
Traceback (most recent call last):
 File "I:\python3.5\lib\site-packages\PyPDF2\generic.py", line 484, in readFromStream
  return NameObject(name.decode('utf-8'))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 10: invalid continuation byte

During handling of the above exception, another exception occurred:

PyPDF2.utils.PdfReadError: Illegal character in Name Object
          

在源碼包中使用utf解碼的時(shí)候出錯(cuò)了,嘗試修改此處源碼,讓其使用gbk,但是還出現(xiàn)了其他的錯(cuò)誤。最后發(fā)現(xiàn)當(dāng)把構(gòu)造函數(shù)中的strict設(shè)置為False時(shí),控制臺(tái)會(huì)打印下面的錯(cuò)誤:

PdfReadWarning: Illegal character in Name Object [generic.py:489]

但是兩個(gè)文件成功的合并了,并且大概看了下合并后的文件有時(shí)好又是壞,同樣的代碼運(yùn)行多次,有時(shí)候能夠正常處理中文,但有時(shí)候中文亂碼。

除了列出的方法還有一些其他的方法,比如添加書簽、添加鏈接等等,可以參考官方文檔。

對(duì)pdf進(jìn)行合并、分割、加密。

整合出來了加密、解密、合并、根據(jù)頁(yè)數(shù)進(jìn)行分割、根據(jù)份數(shù)進(jìn)行分割的樣例:

使用注意:如果時(shí)中文文件,運(yùn)行結(jié)果可能會(huì)出現(xiàn)亂碼,但是多運(yùn)行幾次,中間有正常顯示中文的問題。具體原因還不清楚,但就是這么玄學(xué)。。。

代碼傳送門

            
# @Time  : 2018/3/26 23:48
# @Author : Leafage
# @File  : handlePDF.py
# @Software: PyCharm
# @Describe: 對(duì)pdf文件執(zhí)行合并、分割、加密操作。
from PyPDF2 import PdfFileReader, PdfFileMerger, PdfFileWriter
def get_reader(filename, password):
  try:
    old_file = open(filename, 'rb')
  except IOError as err:
    print('文件打開失敗!' + str(err))
    return None
  # 創(chuàng)建讀實(shí)例
  pdf_reader = PdfFileReader(old_file, strict=False)
  # 解密操作
  if pdf_reader.isEncrypted:
    if password is None:
      print('%s文件被加密,需要密碼!' % filename)
      return None
    else:
      if pdf_reader.decrypt(password) != 1:
        print('%s密碼不正確!' % filename)
        return None
  if old_file in locals():
    old_file.close()
  return pdf_reader
def encrypt_pdf(filename, new_password, old_password=None, encrypted_filename=None):
  """
  對(duì)filename所對(duì)應(yīng)的文件進(jìn)行加密,并生成一個(gè)新的文件
  :param filename: 文件對(duì)應(yīng)的路徑
  :param new_password: 對(duì)文件加密使用的密碼
  :param old_password: 如果舊文件進(jìn)行了加密,需要密碼
  :param encrypted_filename: 加密之后的文件名,省卻時(shí)使用filename_encrypted;
  :return:
  """
  # 創(chuàng)建一個(gè)Reader實(shí)例
  pdf_reader = get_reader(filename, old_password)
  if pdf_reader is None:
    return
  # 創(chuàng)建一個(gè)寫操作的實(shí)例
  pdf_writer = PdfFileWriter()
  # 從之前Reader中將數(shù)據(jù)寫入到Writer中
  pdf_writer.appendPagesFromReader(pdf_reader)
  # 重新使用新密碼加密
  pdf_writer.encrypt(new_password)
  if encrypted_filename is None:
    # 使用舊文件名 + encrypted 作為新的文件名
    encrypted_filename = "".join(filename.split('.')[:-1]) + '_' + 'encrypted' + '.pdf'
  pdf_writer.write(open(encrypted_filename, 'wb'))
def decrypt_pdf(filename, password, decrypted_filename=None):
  """
  將加密的文件及逆行解密,并生成一個(gè)無(wú)需密碼pdf文件
  :param filename: 原先加密的pdf文件
  :param password: 對(duì)應(yīng)的密碼
  :param decrypted_filename: 解密之后的文件名
  :return:
  """
  # 生成一個(gè)Reader和Writer
  pdf_reader = get_reader(filename, password)
  if pdf_reader is None:
    return
  if not pdf_reader.isEncrypted:
    print('文件沒有被加密,無(wú)需操作!')
    return
  pdf_writer = PdfFileWriter()
  pdf_writer.appendPagesFromReader(pdf_reader)
  if decrypted_filename is None:
    decrypted_filename = "".join(filename.split('.')[:-1]) + '_' + 'decrypted' + '.pdf'
  # 寫入新文件
  pdf_writer.write(open(decrypted_filename, 'wb'))
def split_by_pages(filename, pages, password=None):
  """
  將文件按照頁(yè)數(shù)進(jìn)行平均分割
  :param filename: 所要分割的文件名
  :param pages: 分割之后每個(gè)文件對(duì)應(yīng)的頁(yè)數(shù)
  :param password: 如果文件加密,需要進(jìn)行解密操作
  :return:
  """
  # 得到Reader
  pdf_reader = get_reader(filename, password)
  if pdf_reader is None:
    return
  # 得到總的頁(yè)數(shù)
  pages_nums = pdf_reader.numPages
  if pages <= 1:
    print('每份文件必須大于1頁(yè)!')
    return
  # 得到切分之后每個(gè)pdf文件的頁(yè)數(shù)
  pdf_num = pages_nums // pages + 1 if pages_nums % pages else int(pages_nums / pages)
  print('pdf文件被分為%d份,每份有%d頁(yè)!' % (pdf_num, pages))
  # 依次生成pdf文件
  for cur_pdf_num in range(1, pdf_num + 1):
    # 創(chuàng)建一個(gè)新的寫實(shí)例
    pdf_writer = PdfFileWriter()
    # 生成對(duì)應(yīng)的文件名稱
    split_pdf_name = "".join(filename)[:-1] + '_' + str(cur_pdf_num) + '.pdf'
    # 計(jì)算出當(dāng)前開始的位置
    start = pages * (cur_pdf_num - 1)
    # 計(jì)算出結(jié)束的位置,如果是最后一份就直接返回最后的頁(yè)數(shù),否則用每份頁(yè)數(shù)*已經(jīng)分好的文件數(shù)
    end = pages * cur_pdf_num if cur_pdf_num != pdf_num else pages_nums
    # print(str(start) + ',' + str(end))
    # 依次讀取對(duì)應(yīng)的頁(yè)數(shù)
    for i in range(start, end):
      pdf_writer.addPage(pdf_reader.getPage(i))
    # 寫入文件
    pdf_writer.write(open(split_pdf_name, 'wb'))
def split_by_num(filename, nums, password=None):
  """
  將pdf文件分為nums份
  :param filename: 文件名
  :param nums: 要分成的份數(shù)
  :param password: 如果需要解密,輸入密碼
  :return:
  """
  pdf_reader = get_reader(filename, password)
  if not pdf_reader:
    return
  if nums < 2:
    print('份數(shù)不能小于2!')
    return
  # 得到pdf的總頁(yè)數(shù)
  pages = pdf_reader.numPages
  if pages < nums:
    print('份數(shù)不應(yīng)該大于pdf總頁(yè)數(shù)!')
    return
  # 計(jì)算每份應(yīng)該有多少頁(yè)
  each_pdf = pages // nums
  print('pdf共有%d頁(yè),分為%d份,每份有%d頁(yè)!' % (pages, nums, each_pdf))
  for num in range(1, nums + 1):
    pdf_writer = PdfFileWriter()
    # 生成對(duì)應(yīng)的文件名稱
    split_pdf_name = "".join(filename)[:-1] + '_' + str(num) + '.pdf'
    # 計(jì)算出當(dāng)前開始的位置
    start = each_pdf * (num - 1)
    # 計(jì)算出結(jié)束的位置,如果是最后一份就直接返回最后的頁(yè)數(shù),否則用每份頁(yè)數(shù)*已經(jīng)分好的文件數(shù)
    end = each_pdf * num if num != nums else pages
    print(str(start) + ',' + str(end))
    for i in range(start, end):
      pdf_writer.addPage(pdf_reader.getPage(i))
    pdf_writer.write(open(split_pdf_name, 'wb'))
def merger_pdf(filenames, merged_name, passwords=None):
  """
  傳進(jìn)來一個(gè)文件列表,將其依次融合起來
  :param filenames: 文件列表
  :param passwords: 對(duì)應(yīng)的密碼列表
  :return:
  """
  # 計(jì)算共有多少文件
  filenums = len(filenames)
  # 注意需要使用False 參數(shù)
  pdf_merger = PdfFileMerger(False)
  for i in range(filenums):
    # 得到密碼
    if passwords is None:
      password = None
    else:
      password = passwords[i]
    pdf_reader = get_reader(filenames[i], password)
    if not pdf_reader:
      return
    # append默認(rèn)添加到最后
    pdf_merger.append(pdf_reader)
  pdf_merger.write(open(merged_name, 'wb'))
def insert_pdf(pdf1, pdf2, insert_num, merged_name, password1=None, password2=None):
  """
  將pdf2全部文件插入到pdf1中第insert_num頁(yè)
  :param pdf1: pdf1文件名稱
  :param pdf2: pdf2文件名稱
  :param insert_num: 插入的頁(yè)數(shù)
  :param merged_name: 融合后的文件名稱
  :param password1: pdf1對(duì)應(yīng)的密碼
  :param password2: pdf2對(duì)應(yīng)的密碼
  :return:
  """
  pdf1_reader = get_reader(pdf1, password1)
  pdf2_reader = get_reader(pdf2, password2)
  # 如果有一個(gè)打不開就返回
  if not pdf1_reader or not pdf2_reader:
    return
  # 得到pdf1的總頁(yè)數(shù)
  pdf1_pages = pdf1_reader.numPages
  if insert_num < 0 or insert_num > pdf1_pages:
    print('插入位置異常,想要插入的頁(yè)數(shù)為:%d,pdf1文件共有:%d頁(yè)!' % (insert_num, pdf1_pages))
    return
  # 注意需要使用False參數(shù),可能會(huì)出現(xiàn)中文亂碼的情況
  m_pdf = PdfFileMerger(False)
  m_pdf.append(pdf1)
  m_pdf.merge(insert_num, pdf2)
  m_pdf.write(open(merged_name, 'wb'))
if __name__ == '__main__':
  # encrypt_pdf('ex1.pdf', 'leafage')
  # decrypt_pdf('ex1123_encrypted.pdf', 'leafage')
  # split_by_pages('ex1.pdf', 5)
  split_by_num('ex2.pdf', 3)
  # merger_pdf(['ex1.pdf', 'ex2.pdf'], 'merger.pdf')
  # insert_pdf('ex1.pdf', 'ex2.pdf', 10, 'pdf12.pdf')
          

總結(jié)

以上所述是小編給大家介紹的Python中使用pypdf2合并、分割、加密pdf文件的代碼詳解,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 伊人国产视频 | 国产精品欧美日韩视频一区 | 羞羞的视频在线观看 | 五月久久婷婷综合片丁香花 | 91久久精品国产91性色tv | 97狠狠操| 久久久精品国产四虎影视 | 精品综合久久久久久99 | 日韩精品一区二区三区免费视频 | 奇米激情网 | 成人国产精品视频频 | 四虎精品永久免费 | 欧美午夜视频一区二区三区 | 国产综合亚洲精品一区 | 欧美另类videosbestv | 97视频在线播放 | 草久在线观看 | 每日更新在线观看av | 免费国产视频在线观看 | 中国一级特黄高清免费的大片 | 亚洲精品一区二区乱码在线观看 | 狠狠香蕉| 日本-区二区三区免费精品 日本热久久 | 日本高清一级片 | 欧美成人在线免费观看 | 天天操夜夜欢 | 伊人天伊人天天网综合视频 | 久久亚洲影院 | 亚洲swag精品自拍一区 | 亚洲有色 | 99视频在线免费 | 国产99在线视频 | 国产精品亚洲精品 | 天天操天天舔天天射 | 欧美α片无限看在线观看免费 | 亚洲精品久久麻豆蜜桃 | 99久久精品免费看国产一区二区 | 久久综合九色综合97婷婷群聊 | 免费看欧美一级特黄a大片一 | 国产色在线视频 | 久久精品7 |