Java開發者的Python快速實戰指南:實用工具之PDF轉DOCX文件(視覺化介面)

努力的小雨發表於2023-12-12

首先,大家對Python語法的瞭解已經基本完成,現在我們需要開始進行各種練習。我為大家準備了一些練習題目,比如之前的向量資料庫等,這些題目可以參考第三方的SDK來進行操作,文件也是比較完善的。這個過程有點像我們之前使用Java對接第三方介面的方式,所以今天我想開發一個很實用的工具類,用於將PDF轉換為DOCX文件。我覺得這個工具非常實用,所以透過這個專案,我想帶領那些在Python基礎上還比較薄弱的同學們從零開始,一起完成這個專案。

首先,我也剛開始接觸這個專案,所以我並不知道如何實現。我的第一反應是去搜尋引擎上查詢是否有其他人已經實現了類似的功能,因為現在有很多優秀的開源專案可供參考。畢竟,站在巨人的肩膀上進行開發並不可恥,而是一種聰明的做法。

幸運的是,我找到了一個名為"pdf2docx"的第三方包,它提供了非常優秀的功能。令人驚訝的是,僅僅幾行程式碼就可以完成PDF轉換為DOCX的工作。而且,轉換結果也非常出色。讓我們來看一下具體的實現過程。

希望大家可以去倉庫中檢視原始碼,學習如何使用這個工具包,也歡迎大家在倉庫中留言,提出任何問題或建議。一起進步,共同學習!倉庫地址為:https://github.com/StudiousXiaoYu/pdf2docx_with_ui

PDF轉DOCX文件

第三方包:pdf2docx

from pdf2docx import Converter

def convert_pdf_to_docx(pdf_path, docx_path):
    # 建立一個轉換器物件
    converter = Converter(pdf_path)

    # 將PDF轉換為DOCX
    converter.convert(docx_path, start=0, end=None)

    # 關閉轉換器
    converter.close()

# 呼叫函式進行轉換
pdf_path = "input.pdf"
docx_path = "output.docx"
convert_pdf_to_docx(pdf_path, docx_path)

他很容易理解,只需要你定義好檔案路徑即可完成轉換操作。此外,我也不多解釋了,因為start引數用於指定轉換的起始頁碼,而end引數用於指定轉換的結束頁碼。你可以根據需要設定這兩個引數的值,如果不需要指定起始頁碼,可以將start引數設定為0;如果不需要指定結束頁碼,則可以將end引數設定為None。

官方視覺化介面

程式碼很簡單,但是如果是自己使用的話,每次都要寫一次路徑可能會很麻煩。不過你可以使用一個視覺化互動介面來簡化這個過程,這樣會更方便一些。幸運的是,pdf2docx提供了一個簡易版的介面,你可以在控制檯中直接輸入"pdf2docx gui"來啟動。在介面中,你只需要選擇要轉換的PDF檔案和一個資料夾作為儲存路徑,就可以完成轉換操作了。這樣的話,你就不需要每次都手動輸入路徑了。非常方便。

image

簡易版可互動介面

但是,如果你對pdf2docx提供的介面不滿意,並且覺得介面不夠好看,那麼可以考慮使用另一個第三方介面庫,叫做gradio。我記得你之前在向量資料庫中使用過這個庫,對後端非常友好。你可以先寫一個簡單的介面,然後逐步最佳化它,以滿足你的需求。gradio提供了很多功能和自定義選項,你可以根據自己的喜好來設計介面的外觀和互動方式。然後慢慢最佳化吧。

import gradio as gr
from pdf2docx import Converter


def convert_pdf_to_docx_with_display(pdf_file):
    tmp_file = "./output.docx"
    # Convert PDF to DOCX
    cv = Converter(pdf_file)
    cv.convert(tmp_file)
    cv.close()

    return tmp_file


def convert_and_display_pdf_to_docx(pdf_file):
    docx_file = convert_pdf_to_docx_with_display(pdf_file)
    return docx_file


iface = gr.Interface(
    fn=convert_and_display_pdf_to_docx,
    inputs=["file"],
    outputs=["file"],
    title="[努力的小雨] PDF to DOCX Converter",
    description="上傳pdf檔案,並將其轉化為docx檔案",
)

iface.launch()

image

恩恩,我看著是相當不錯的,這個小工具已經可以滿足使用者的需求了。效果圖,你可以看看:

image

最佳化版介面

好的,目前可互動的資源還相對較少。然而,如果我們能夠提前預覽解析後的文字內容,有時就能避免不必要的下載。比如,在檢視PDF檔案時,我們只需要複製貼上其中的文字,而無需下載整個檔案。為了實現這一功能,我們可以考慮在檔案底部新增一個額外的視窗,用於顯示解析後的文字內容。透過提供複製貼上功能,使用者可以輕鬆地獲取所需的文字資訊。

import gradio as gr
from pdf2docx import Converter
import docx2txt

def convert_pdf_to_docx_with_display(pdf_file):
    tmp_file = "./output.docx"
    # Convert PDF to DOCX
    cv = Converter(pdf_file)
    cv.convert(tmp_file)
    cv.close()

    # Extract text from DOCX
    docx_text = docx2txt.process(tmp_file)
    return tmp_file, docx_text


def convert_and_display_pdf_to_docx(pdf_file):
    docx_file, docx_text = convert_pdf_to_docx_with_display(pdf_file)
    return docx_file, docx_text


iface = gr.Interface(
    fn=convert_and_display_pdf_to_docx,
    inputs=["file"],
    outputs=["file", "text"],
    title="[努力的小雨] PDF to DOCX Converter",
    description="上傳pdf檔案,並將其轉化為docx檔案且在介面單獨顯示檔案的文字",
)

iface.launch()

當我們完成程式碼的修改後,執行一下,我發現效果與我預期的是一致的。

image

至強版介面

如果我們已經能夠顯示文字,那麼是否還需要顯示圖片呢?考慮到PDF中常常包含圖片,為了滿足使用者複製貼上圖片的需求,我認為單獨開發一個視窗來儲存圖片是合理的。然而,在這個過程中,我遇到了一些困難,幾乎是我的噩夢。我一直遇到報錯,而且這些錯誤幾乎是我之前從未遇到過的。就像當初學習Java的時候,總是需要上網搜尋解決方法一樣。在使用gradio時,我建立了一個畫廊視窗,但是錯誤地以為它可以直接返回影像的二進位制內容,所以沒有進行儲存,結果一直報錯。後來,我儲存了影像,問題得以解決。現在我們來修改程式碼,因為有很多重複的程式碼,我就不再一直複製貼上了。

# 此處省略部分程式碼
# Extract images from DOCX
    images = []
    image_dir = os.path.join(tmp_dir, "images")
    os.makedirs(image_dir, exist_ok=True)
    for embed, related_part in document.part.related_parts.items():
        if isinstance(related_part, ImagePart):
            image_path = os.path.join(image_dir, f'image_{embed}.png')
            with open(image_path, 'wb') as f:
                f.write(related_part.image.blob)
                images.append(image_path)

    return tmp_file, docx_text, images
# 此處省略部分程式碼    

我將圖片儲存到一個資料夾中,並返回一個包含圖片實體的列表。現在讓我們來看一下效果:可以看到圖片已經顯示出來了,但我覺得互動性還不夠,如果使用者不想要前幾頁的PDF怎麼辦呢?為了解決這個問題,我將再新增一個輸入框,讓使用者可以輸入相關資訊。讓我們繼續最佳化一下。

image

inputs=["text","file"],

為了實現傳參,我們可以修改輸入引數的型別。這個過程非常簡單。除了我之前演示的簡單樣式外,Gradio還有很多其他樣式可供選擇。我只是提供了一個最簡單的示例,剩下的最佳化工作就交給你了。你可以根據需要選擇適合的樣式進行最佳化。

image

這裡我就不演示了,因為只要我們能夠獲取引數,我們就可以實現各種功能。就pdf轉docx的視覺化介面而言,我已經基本完成了它,它符合我的要求並且基本上令我滿意。畢竟,我不需要去最佳化介面。

總結

pdf轉docx文件是一個非常實用的功能,我只是簡單地實現了一個視覺化介面供使用者操作。我這麼做的目的之一是想更多地掌握gradio的使用方法,同時也加強對Python流行第三方包的熟悉程度,因為這些第三方包是快速開發的關鍵。我也希望你能從中有所收穫,我已經公佈了本期的原始碼地址,如果你覺得還不錯,或者在自己編寫的過程中遇到問題,可以簡單地參考一下。不過,我仍然希望你能自己解決bug問題,這樣一旦熟悉了,就知道如何處理,不用總是上網尋找解決方案。

相關文章