iT邦幫忙

0

python 的for迴圈問題。

  • 分享至 

  • xImage

製作pdf,
從第1個pdf抓135頁、第2個pdf抓24頁,互相交疊,印成新的pdf檔。
若此5頁之中有關鍵字UHD,則該頁加上浮水印。(最後只有第1、5頁有浮水印)

自己手寫迴圈順序感覺沒問題,
**
可是第5頁會疊印在第1頁。然後原本第5頁的地方變空白。
希望很會跑迴圈的大大可以幫忙看一下。m()m **

import os, PyPDF2

a = "c:\temp\p340use"
os.chdir(a)
print(os.getcwd())

if os.path.exists("p340.pdf"):
  os.unlink("p340.pdf")

ps = os.listdir(a)
ps.sort(key=str.lower, reverse=True)
del ps[0] # list erase water.pdf
print(ps)

pr1 = PyPDF2.PdfFileWriter()
pr2 = PyPDF2.PdfFileReader(open('water.pdf', 'rb'))

for m in range(5): # 5 page = 0~4
  for n in range(len(ps)): # 2 file = 0~1
    if ((m%2== 0)&(n%2==0)): # page135, file1
      pr3 =PyPDF2.PdfFileReader(open(ps[n], 'rb'))
      i = pr3.getPage(m).extractText()
      if 'UHD' in i:
        k = pr2.getPage(0) # water.pdf
        k.mergePage(pr3.getPage(m))
      else:
        k = pr3.getPage(m)
      pr1.addPage(k)
      break

    elif ((m%2!=0)&(n%2!=0)): # page24, file2
      pr3 = PyPDF2.PdfFileReader(open(ps[n], 'rb'))
      pr1.addPage(pr3.getPage(m))

pr1.write(open('p340.pdf', 'wb'))

如果覺得上述流程有能改進、更精簡或更順暢的方式,
也請不吝指導。謝謝。

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
chatgpt2022
iT邦新手 5 級 ‧ 2022-12-07 17:59:35

這段代碼裡面有一些小錯誤和沒必要的操作。在分析代碼之前,先簡述一下需要做的事情:

把兩個 PDF 文件讀入,從每個文件中抓取指定的頁數。
將這些頁數按照一定的順序組合起來,形成一個新的 PDF 文件。
如果第1、5頁包含關鍵字「UHD」,則在這兩頁上增加浮水印。
現在就來一步一步改進這段代碼。

首先,沒必要使用 os 模塊來獲取文件列表,因為 PyPDF2 模塊本身就可以讀取 PDF 文件。改用 PyPDF2 模塊的方法如下:

import PyPDF2

# 讀取文件
file1 = open('file1.pdf', 'rb')
file2 = open('file2.pdf', 'rb')

# 建立 PdfFileReader 對象
reader1 = PyPDF2.PdfFileReader(file1)
reader2 = PyPDF2.PdfFileReader(file2)

接下來,為了抓取每個文件中的指定頁數,需要用到 PyPDF2 模塊中的 getPage() 方法。 getPage() 方法需要一個頁碼作為參數,頁碼是从0開始計算的。因此,要抓取第1個文件中第135頁,可以這樣寫:

# 取出第135頁
page135 = reader1.getPage(134)

現在,我們已經有了所有需要的頁面,可以按照順序組合它們。 PyPDF2 模塊提供了 PdfFileWriter 物件來寫入 PDF 文件,我們可以用它來實現這個功能。

假設我們把第1個文件中的第135頁和第5個文件中的第24頁組合在一起,可以這樣寫:

# 建立 PdfFileWriter 對象
writer = PyPDF2.PdfFileWriter()

# 將第135頁和第24頁加入 writer 對象中
writer.addPage(page135)
writer.addPage(page24)

# 寫入文件
output = open('output.pdf', 'wb')
writer.write(output)

接下來,我們要在第1、5頁上加上浮水印。 PyPDF2 模塊提供了 mergePage() 方法來把一個頁面合并到另一個頁面上。我們需要用這個方法來完成這個任務。

首先,我們需要把浮水印加到一個獨立的頁面上。可以這樣寫:

# 讀入浮水印文件
watermark = open('watermark.pdf', 'rb')

# 建立 PdfFileReader 對象
watermark_reader = PyPDF2.PdfFileReader(watermark)

# 取出浮水印頁面
watermark_page = watermark_reader.getPage(0)

然後,我們就可以把浮水印頁面合并到第1、5頁上了。假設第1頁是 page1,第5頁是 page5,可以這樣寫:

# 合并浮水印
page1.mergePage(watermark_page)
page5.mergePage(watermark_page)

最後,我們需要檢查每一頁是否包含關鍵字「UHD」,如果包含,則加上浮水印。這可以通過 PyPDF2 模塊中的 extractText() 方法來實現。

假設我們想檢查 page1 這一頁是否包含「UHD」,可以這樣寫:

# 檢查 page1 是否包含「UHD」
text = page1.extractText()
if 'UHD' in text:
    page1.mergePage(watermark_page)

最後整合起來是:

import PyPDF2

# 讀取文件
file1 = open('file1.pdf', 'rb')
file2 = open('file2.pdf', 'rb')

# 建立 PdfFileReader 對象
reader1 = PyPDF2.PdfFileReader(file1)
reader2 = PyPDF2.PdfFileReader(file2)

# 取出第135頁和第24頁
page135 = reader1.getPage(134)
page24 = reader2.getPage(23)

# 讀入浮水印文件
watermark = open('watermark.pdf', 'rb')

# 建立 PdfFileReader 對象
watermark_reader = PyPDF2.PdfFileReader(watermark)

# 取出浮水印頁面
watermark_page = watermark_reader.getPage(0)

# 建立 PdfFileWriter 對象
writer = PyPDF2.PdfFileWriter()

# 將第135頁和第24頁加入 writer 對象中
writer.addPage(page135)
writer.addPage(page24)

# 檢查 page1 是否包含「UHD」,如果包含,則加上浮水印
text = page1.extractText()
if 'UHD' in text:
    page1.mergePage(watermark_page)

# 檢查 page5 是否包含「UHD」,如果包含,則加上浮水印
text = page5.extractText()
if 'UHD' in text:
    page5.mergePage(watermark_page)

# 寫入文件
output = open('output.pdf', 'wb')
writer.write(output)

需要注意的是,上面的代碼假設我們只需要第1、5頁,如果需要更多的頁面,則需要使用迴圈來把所有頁面都加入 writer 對象中。

另外,上面的代碼假設需要把第1個文件中的第135頁和第2個文件中的第24頁組合起來。如果需要把其他頁面組合起來,則需要修改代碼以適應不同的情況。

希望這些指導能幫助你完成你的任務。

re.Zero iT邦研究生 5 級 ‧ 2022-12-07 19:41:52 檢舉

很棒的思緒整理,但看下來到後面卻感到滿心的陷阱…… 這是懶還是~? /images/emoticon/emoticon39.gif

謝謝您的解答 :D
os段落在這個主題的確很多餘,
只是為了確定檔案位置、當下操作位置,
若日後回顧,自己也會比較清楚。m(__)m

0
re.Zero
iT邦研究生 5 級 ‧ 2022-12-08 01:15:52

程式碼的檔案操作主要採用 pathlib
程式碼的 PyPDF2 採用 官方文件 的命名與方法取代舊的語法。
另,open()請搭配close()with語句以控管及降低風險。

## Tested @ Python==3.8.15; pypdf2==2.11.2;
import pathlib, PyPDF2
showDebug = True ## 除錯用:顯示處理細節;
## showDebug 設為 True 時:
## 1. 顯示浮水印外的待處理的檔案
## 2. P[]F[]W :顯示處理頁(P),插入的檔案(F),覆上浮水印(W?)
folderBase = pathlib.Path(r'c:\temp\p340use')
fileOut = folderBase.joinpath('p340.pdf')
fileInW = folderBase.joinpath('water.pdf')
## 
if(fileOut.exists()): fileOut.unlink()
filesAll = sorted( \
	[x for x in folderBase.glob('*.pdf') if x.is_file()], \
	key = lambda path: str(path).lower(), \
	reverse = True \
) ## 左斜線(\)可不用;這只是我習慣~
filesFi = [i for i in filesAll if fileInW.name not in i.name]
if(showDebug):
	for i in filesFi: print(i.name)
## 
readerW = PyPDF2.PdfReader(fileInW)
## 用以先載入以降低迴圈時的負載。(不過還是要看 PyPDF2 的運作方式)
readers = [PyPDF2.PdfReader(i) for i in filesFi] 
writer = PyPDF2.PdfWriter()
for m in range(5):
	n = m % len(readers)
	if(showDebug): print('P['+str(m)+']F['+str(filesFi[n].name)+']',end='')
	## 因為你的程式裡,來源檔案的頁數索引是用 m ,所以這裡我照你的用 m ;
	## 如要用第 135、24 頁,請自行修訂(例如判斷式或[檔案-頁數]對應法等)。
	writer.add_page(readers[n].pages[m])
	pText = readers[n].pages[m].extract_text()
	if 'UHD' in pText:
		if(showDebug): print('W',end='')
		writer.pages[m].merge_page(readerW.pages[0])
	if(showDebug): print('')
with open(fileOut, "wb") as fp:
	writer.write(fp)
## 

Update:
使用:

## 用以先載入以降低迴圈時的負載。(不過還是要看 PyPDF2 的運作方式)
readers = [PyPDF2.PdfReader(i) for i in filesFi] 

取代:

readers = [] ## 用以先載入以降低迴圈時的負載。(不過還是要看 PyPDF2 的運作方式)
for i in filesFi: readers.append(PyPDF2.PdfReader(i))

兩個語法各有用處;因為看到 froce 的回答,回頭看了下,若是初始化的話,用新的感覺比較好。

您的寫法比較複雜,
用了一些我還沒學到的部份。
例如以pathlib取代os。
(那os去哪啦???)

open()、close()、with還沒學到,這些的分開列式能降低風險,
我也會記下來了的,很感謝。

我很喜歡您的寫法,
因為它告訴我,「未來」也許能學到用這些方式來撰寫代碼。

re.Zero iT邦研究生 5 級 ‧ 2022-12-08 18:58:14 檢舉

os 一直都在,只是某天注意到 pathlib 後,現在我就偏好用 pathlib 做檔案操作了。 這裡有功能對照表。
檔案操作的open()close()牽涉到檔案系統的占用與鎖定等;只怕發生特殊狀況搞掛檔案系統,不然一般的異常其實都是小問題。
open()+with等 context manager 相關語法就真的方便好用了;但怕會慣壞或搞亂一堆人就是了~

謝謝您。:D

0
froce
iT邦大師 1 級 ‧ 2022-12-08 09:09:10

python 3.10 以上

import PyPDF2

def genPDFByCustom(pdf1, pdf2, watermark, index):
    tempPage = None
    if index%2 == 0:
        tempPage = pdf1.getPage(index)
        if index == 0 or index == 4:
            if 'UHD' in tempPage.extractText():
                tempPage.mergePage(watermark)
    else:
        tempPage = pdf2.getPage(index)
    return tempPage


with (
  open('file1.pdf', 'rb') as file1,
  open('file2.pdf', 'rb') as file2,
  open('watermark.pdf', 'rb') as watermarkfile,
  open('output.pdf', 'wb') as output
    ):
    pdf1 = PyPDF2.PdfFileReader(file1)
    pdf2 = PyPDF2.PdfFileReader(file2)
    
    watermarkPDF = PyPDF2.PdfFileReader(watermarkfile)
    watermark = watermarkPDF.getPage(0)
    
    writer = PyPDF2.PdfFileWriter()
    
    pdfPages = [genPDFByCustom(pdf1, pdf2, watermark, i) for i in range(5)]
    
    for p in pdfPages:
        writer.addPage(p)
    writer.write(output)

我很喜歡genPDFByCustom的部份,
省略了一道迴圈,
with的方式也很有趣。
在賦值pdfPages的部份,
您的寫法和re.Zero一樣,
您有特意用「貼近我的程度」的方式來撰寫回答,
非常感謝。

我要發表回答

立即登入回答