網站首頁 學習教育 IT科技 金融知識 旅遊規劃 生活小知識 家鄉美食 養生小知識 健身運動 美容百科 遊戲知識 綜合知識
當前位置:趣知科普吧 > 學習教育 > 

基於Python實現PDF區域文字提取工具

欄目: 學習教育 / 發佈於: / 人氣:2.9W

<link rel="stylesheet" href="https://js.how234.com/c359fc24b2/da53fe39b117d0455d01c0b110681d4466/da5ee921b51c/da42d322a20a.css" type="text/css" /><link rel="stylesheet" href="https://js.how234.com/c359fc24b2/da53fe39b117d0455d01c0b110681d4466/da5ee921b51c/da42c425b502dd685f0fcdad1b74.css" type="text/css" /><script type="text/javascript" src="https://js.how234.com/third-party/SyntaxHighlighter/shCore.js"></script><style>pre{overflow-x: auto}</style>

功能簡介

開啟軟件後介面如下:

基於Python實現PDF區域文字提取工具

點擊開啟檔案按鈕開啟之前的pdf檔案後效果如下:

基於Python實現PDF區域文字提取工具 第2張

框選區域後,標題欄會自動顯示當前框選的區域提取到的文字,還可以左右按鈕切換:

基於Python實現PDF區域文字提取工具 第3張

實際我們需要提取文字的區域可能不止這一個,所以程序支援多區域框選:

基於Python實現PDF區域文字提取工具 第4張

完成區域框選後就可以點擊儲存檔案,將PDF每頁提取到的文字儲存到一個csv檔案中,當前選區的儲存結果如下:

基於Python實現PDF區域文字提取工具 第5張

可以看到已經按框選順序依次儲存了每一個區域的字元串。

如果選擇區域時發現提取結果不準確,可以撤銷後重新選擇:

基於Python實現PDF區域文字提取工具 第6張

儲存圖片則會將PDF的每頁的整體儲存爲一張圖片,未選擇區域時,以頁碼爲檔案名儲存圖片:

基於Python實現PDF區域文字提取工具 第7張

選擇區域時,會自動提取最後一個區域提取的文字作爲當前頁的檔案名:

基於Python實現PDF區域文字提取工具 第8張

開發代碼

當然這個項目由於本人是一次使用wxpython,功能非常簡約,現在將完整代碼開源出來期待各位大佬的改進。

源碼和已編譯工具下載地址:

https://codechina.csdn.net/as604049322/python_gui

完整代碼:

"""小小明的代碼CSDN主頁:https://blog.csdn.net/as604049322"""__author__ = '小小明'__time__ = '2021/11/24'import csvimport wximport osimport fitzclass MyCanvas(wx.Panel):    def __init__(self, parent):        wx.Panel.__init__(self, parent)        self.parent = parent        self.rects = []        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftButtonEvent)        self.Bind(wx.EVT_LEFT_UP, self.OnLeftButtonEvent)        self.Bind(wx.EVT_MOTION, self.OnLeftButtonEvent)        self.Bind(wx.EVT_PAINT, self.DoDrawing)        b = wx.Button(self, -1, "開啟檔案", (0, 0))        self.Bind(wx.EVT_BUTTON, self.OnButton, b)        b = wx.Button(self, -1, "儲存檔案", (75, 0))        self.Bind(wx.EVT_BUTTON, self.save_file, b)        b = wx.Button(self, -1, "儲存圖片", (150, 0))        self.Bind(wx.EVT_BUTTON, self.save_img, b)        b = wx.Button(self, -1, "撤銷選區", (225, 0))        self.Bind(wx.EVT_BUTTON, self.back_select, b)        b = wx.Button(self, -1, "《", (300, 0), size=(25, 25))        self.Bind(wx.EVT_BUTTON, self.previous, b)        b = wx.Button(self, -1, "》", (325, 0), size=(25, 25))        self.Bind(wx.EVT_BUTTON, self.next, b)        self.g1 = wx.Gauge(self, -1, 100, (0, 30), (-1, 100), wx.GA_VERTICAL)    def previous(self, evt):        if not hasattr(self, "pdfDoc"):            return        if self.i > 0:            self.i -= 1            self.change_pdf_page(self.i, False)            self.DoDrawing(-1)            if self.rects:                self.parent.SetTitle(self.path + "|" + self.extract_pdf_text())    def next(self, evt):        if not hasattr(self, "pdfDoc"):            return        if self.i < self.pageCount - 1:            self.i += 1            self.change_pdf_page(self.i, False)            self.DoDrawing(-1)            if self.rects:                self.parent.SetTitle(self.path + "|" + self.extract_pdf_text())    def back_select(self, evt):        if self.rects:            self.rects.pop()            self.DoDrawing(-1)    def OnButton(self, evt):        dlg = wx.FileDialog(            self, message="選擇一個PDF檔案",            defaultDir=os.getcwd(),            defaultFile="",            wildcard="PDF檔案(*.pdf)|*.pdf",            style=wx.FD_OPEN | wx.FD_CHANGE_DIR |                  wx.FD_FILE_MUST_EXIST | wx.FD_PREVIEW        )        if dlg.ShowModal() == wx.ID_OK:            self.rects = []            path = dlg.GetPath()            self.pdfDoc = fitz.open(path)            self.i = 0            self.pageCount = self.pdfDoc.pageCount            self.change_pdf_page(self.i)            self.path = os.path.basename(path)            self.parent.SetTitle(self.path)            self.DoDrawing(-1)        dlg.Destroy()    def change_pdf_page(self, i, move=True):        page = self.pdfDoc[i]        rect = page.rect        print("pdf範圍:", rect)        mat = fitz.Matrix(1, 1)        pix = page.get_pixmap(matrix=mat, alpha=False, clip=rect)        pix.save("tmp.png")        self.change_img("tmp.png", move)    def save_FileDialog(self, format="csv"):        dlg = wx.FileDialog(            self, message=f"儲存一個{format}檔案", defaultDir=os.getcwd(),            defaultFile="", wildcard=f"{format}檔案(*.{format})|*.{format}", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT        )        path = None        if dlg.ShowModal() == wx.ID_OK:            path = dlg.GetPath()        dlg.Destroy()        return path    def save_img(self, evt):        if not hasattr(self, "pdfDoc"):            return        dlg = wx.DirDialog(self, "選擇圖片儲存的檔案夾:",                           style=wx.DD_DEFAULT_STYLE                           # | wx.DD_DIR_MUST_EXIST                           # | wx.DD_CHANGE_DIR                           )        mat = fitz.Matrix(1, 1)        if dlg.ShowModal() == wx.ID_OK:            path = dlg.GetPath()            for i in range(self.pdfDoc.pageCount):                page = self.pdfDoc[i]                clip = page.rect                pix = page.get_pixmap(matrix=mat, alpha=False, clip=clip)                if self.rects:                    name = self.extract_pdf_text(page=page, rect=self.rects[-1])                else:                    name = f"p{i:0>3d}"                pix.save(f"{path}/{name}.png")                self.g1.SetValue((i + 1) * 100 // self.pdfDoc.pageCount)        dlg.Destroy()        os.system(f"explorer {path}")    def save_file(self, evt):        if not hasattr(self, "pdfDoc"):            return        path = self.save_FileDialog()        if path is None:            return        data = []        for i in range(self.pdfDoc.pageCount):            page = self.pdfDoc[i]            row = [self.extract_pdf_text(page, rect)                   for i, rect in enumerate(self.rects)]            data.append(row)        with open(path, "w") as f:            writer = csv.writer(f, lineterminator="")            row = [f"區域{i}" for i in range(1, len(row) + 1)]            writer.writerow(row)            for row in data:                writer.writerow(row)        os.system(f"cmd /c start {path}")    def extract_pdf_text(self, page=None, rect=None):        if page is None:            page = self.pdfDoc[self.i]        if rect is None:            rect = self.rects[-1]        a, b, c, d = rect        clip = fitz.Rect(a, b, a + c, b + d)        text = page.get_text(clip=clip).strip()        return text    def change_img(self, img_path, move=True):        self.bmp = wx.Bitmap(img_path)        self.SetSize(self.bmp.GetSize())        self.parent.SetSize(self.parent.GetBestSize())        if move:            self.parent.Center()    def DoDrawing(self, evt):        if not hasattr(self, "bmp"):            return        dc = wx.ClientDC(self)        dc.DrawBitmap(self.bmp, 0, 0, True)        dc.SetPen(wx.Pen('blue'))        dc.SetBrush(wx.Brush('white', wx.BRUSHSTYLE_TRANSPARENT))        dc.DrawRectangleList(self.rects)    def OnLeftButtonEvent(self, event):        if event.LeftDown():            self.x, self.y = event.GetPosition()            self.rects.append([self.x, self.y, 0, 0])        elif event.Dragging():            x, y = event.GetPosition()            self.rects[-1][2] = x - self.x            self.rects[-1][3] = y - self.y            self.DoDrawing(-1)        elif event.LeftUp():            print(self.rects)            if self.rects[-1][2] < 5 or self.rects[-1][3] < 5:                self.rects.pop()            else:                self.parent.SetTitle(self.path + "|" + self.extract_pdf_text())app = wx.App()frm = wx.Frame(None)pnl = MyCanvas(frm)frm.Center()frm.Show()frm.SetTitle("PDF文字提取器")app.MainLoop()