1. 程式人生 > >python使用textract解析pdf時遇到UnboundLocalError: local variable 'pipe' referenced before assignment

python使用textract解析pdf時遇到UnboundLocalError: local variable 'pipe' referenced before assignment

工作需要要用python解析各種文件,我敬愛的manager AKA Byrd推薦給了我textract。

“Textract is the most ridiculous library that I've ever used before”,其實它還是挺強大的,只是對於pdf不太友好。

-----------------------------------------------------------------------------------------------------------------

第一個坑:

用 pip install textract 安裝好這個庫之後 

import textract
textract.process('a.pdf', method='pdfminer')

Google了一會才知道原來安裝textract的時候並不會自動幫你安裝pdfminer,需要手動安裝pdfminer。"Install Python 2.6 or newer. (For Python 3 support have a look at pdfminer.six)."
原來是因為我用的是python3.x,所以得用pdfminer.six

所以 pip install pdfminer.six

第一個坑到這裡就踩完了。

第二個坑:

再次執行程式碼,這次出現了這樣的報錯資訊

UnboundLocalError: local variable 'pipe' referenced before assignment


檢視原始碼utils.py

def run(self, args):
    """Run ``command`` and return the subsequent ``stdout`` and ``stderr``
    as a tuple. If the command is not successful, this raises a
    :exc:`textract.exceptions.ShellError`.
    """

    # run a subprocess and put the stdout and stderr on the pipe object
    try:
        pipe = subprocess.Popen(
            args,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
        )
    except OSError as e:
        if e.errno == errno.ENOENT:
            # File not found.
            # This is equivalent to getting exitcode 127 from sh
            raise exceptions.ShellError(
                ' '.join(args), 127, '', '',
            )

    # pipe.wait() ends up hanging on large files. using
    # pipe.communicate appears to avoid this issue
    stdout, stderr = pipe.communicate()
# if pipe is busted, raise an error (unlike Fabric) if pipe.returncode != 0: raise exceptions.ShellError( ' '.join(args), pipe.returncode, stdout, stderr, ) return stdout, stderr

發現是紅字部分出錯,心裡"WaduHek ?!" 我就寫了一句程式碼,這報錯算是怎麼回事呀?

在原始碼pdf_parser.py中

def extract_pdfminer(self, filename, **kwargs):
    """Extract text from pdfs using pdfminer."""
    stdout, _ = self.run(['pdf2txt.py', filename])
    return stdout

這個 pdf2txt.py 無法被找到

以下是兩種解決方法:

第1種方法

修改原始碼,使其為:

def extract_pdfminer(self, filename, **kwargs):
    """Extract text from pdfs using pdfminer."""
    stdout, _ = self.run(['python','path/to/pdf2txt.py', filename])
    return stdout

run的第二個引數 'path/to/pdf2txt.py' ,要改成你係統上的pdf2.txt.py的絕對路徑(相對路徑我沒試過,不知道可不可行)。

比如我是在virtualenv下開發的,所以我的路徑就是 c:\Users\....\venv\Scripts\pdf2.txt.py

這樣的話就可運行了。

(後話:當我用這種方法時,如果我將我的程式碼修改成這樣:

import textract
textract.process('a.pdf')

即去掉了method='pdfminer'。 

根據原始碼pdf_parser.py :

def extract(self, filename, method='', **kwargs):
    if method == '' or method == 'pdftotext':
        try:
            return self.extract_pdftotext(filename, **kwargs)
        except ShellError as ex:
            # If pdftotext isn't installed and the pdftotext method
            # wasn't specified, then gracefully fallback to using
            # pdfminer instead.
            if method == '' and ex.is_not_installed():
                return self.extract_pdfminer(filename, **kwargs)
            else:
                raise ex

    elif method == 'pdfminer':
        return self.extract_pdfminer(filename, **kwargs)
    elif method == 'tesseract':
        return self.extract_tesseract(filename, **kwargs)
    else:
        raise UnknownMethod(method)

def extract_pdftotext(self, filename, **kwargs):
    """Extract text from pdfs using the pdftotext command line utility."""
    if 'layout' in kwargs:
        args = ['pdftotext', '-layout', filename, '-']
    else:
        args = ['pdftotext', filename, '-']
    stdout, _ = self.run(args)
    return stdout

def extract_pdfminer(self, filename, **kwargs):
    """Extract text from pdfs using pdfminer."""
    stdout, _ = self.run(['python','path/to/pdf2txt.py', filename])
    return stdout

當我的 method =='' 時,它應該先進入

try:
     return self.extract_pdftotext(filename, **kwargs)

然後意識到我並沒有安裝pdftotxt,再進入到

except ShellError as ex:
            # If pdftotext isn't installed and the pdftotext method
            # wasn't specified, then gracefully fallback to using
            # pdfminer instead.
            if method == '' and ex.is_not_installed():
                return self.extract_pdfminer(filename, **kwargs)

最終應該還是會去執行

def extract_pdfminer(self, filename, **kwargs):
    """Extract text from pdfs using pdfminer."""
    stdout, _ = self.run(['python','path/to/pdf2txt.py', filename])
    return stdout

這麼來說,我修改自己的程式碼後應該還是能執行的。然而它又報錯了

.............................

.............................

textract.exceptions.ShellError: The command `pdftotext a.pdf -` failed with exit code 127

------------- stdout -------------

------------- stderr -------------

時間原因沒去深究,有想法的同學希望可以教教我為什麼,萬分感謝。

最後因為這個方法要修改原始碼,那我以後用 pip freeze > requirements.txt     +      pip  install -r requirements.txt  安裝的textract庫會有問題,所以我沒有選擇這種方法  ......   會不會有同學讀了這麼久讀到這了發現這方法居然還不好用然後就把網頁關了hh

第二種方法 :

根據帖子中的Irq3000:

".... so unfortunately I will have to package a copy of pdf2txt.py within my own package, as there is no reliable way to know where the "Scripts" is and add it dynamically to the path that is both crossplatform ...."

將 pdf2txt.py 檔案複製到你的專案資料夾下,然後通過繼承,在你的程式下新增自己(不是'自己',是Irq3000)一個pdfminer類:

class MyPdfMinerParser(ShellParser):
    """Extract text from pdf files using the native python PdfMiner library"""

    def extract(self, filename, **kwargs):
        """Extract text from pdfs using pdfminer and pdf2txt.py wrapper."""
        # Create a temporary output file
        tempfilefh, tempfilepath = mkstemp(suffix='.txt')
        os.close(tempfilefh)  # close to allow writing to tesseract
        # Extract text from pdf using the entry script pdf2txt (part of PdfMiner)
        pdf2txt.main(['', '-o', tempfilepath, filename])
        # Read the results of extraction
        with open(tempfilepath, 'rb') as f:
            res = f.read()
        # Remove temporary output file
        os.remove(tempfilepath)
        return res

pdfminerparser = MyPdfMinerParser()
result = pdfminerparser.process('a.pdf', 'utf8')

第三個坑:

當我以為終於完事了的時候,執行程式碼,結果出現這樣的報錯 :

usage: dpMain.py [-h] [-d] [-p PAGENOS]
                 [--page-numbers PAGE_NUMBERS [PAGE_NUMBERS ...]]
                 [-m MAXPAGES] [-P PASSWORD] [-o OUTFILE] [-t OUTPUT_TYPE]
                 [-c CODEC] [-s SCALE] [-A] [-V] [-W WORD_MARGIN]
                 [-M CHAR_MARGIN] [-L LINE_MARGIN] [-F BOXES_FLOW]
                 [-Y LAYOUTMODE] [-n] [-R ROTATION] [-O OUTPUT_DIR] [-C] [-S]
                 files [files ...]

dpMain.py: error: unrecognized arguments: a.pdf

........  行吧

看了一下原始碼,分析了一下,發現

 pdf2txt.main(['', '-o', tempfilepath, filename])
這行程式碼的第一個引數是多餘的(或者說我水平還低,實在沒發現它有什麼用),將其去除,得:
 pdf2txt.main(['-o', tempfilepath, filename])

大功告成 !

相關推薦

python使用textract解析pdf遇到UnboundLocalError: local variable 'pipe' referenced before assignment

工作需要要用python解析各種文件,我敬愛的manager AKA Byrd推薦給了我textract。“Textract is the most ridiculous library that I've ever used before”,其實它還是挺強大的,只是對於pd

全域性變數報錯:UnboundLocalError: local variable 'l' referenced before assignment

全域性變數報錯:UnboundLocalError: local variable ‘j’ referenced before assignment 最近在自學python,遇見以下問題:

UnboundLocalError: local variable 'XXX' referenced before assignment

這個問題很囧,在外面定義了一個變數 xxx ,然後在python的一個函式裡面引用這個變數,並改變它的值,結果報錯local variable 'xxx' referenced before assignment,程式碼如下: xxx = 23 def Print

常見的local variable 'x' referenced before assignment問題

def fun1(): x = 5 def fun2(): x *= 2 return x return fun2()如上程式碼,呼叫fun1() 執行會出錯:UnboundLocalError: local vari

關於 local variable 'has' referenced before assignment 問題

  今天在django開發時,訪問頁面總是出現錯誤提示“local variable 'has' referenced before assignment”,查了一下資料,好像是說無法訪問這個變數,檢查一下程式碼我的檢視是這樣寫的:def MusicTable(request

全局變量報錯:UnboundLocalError: local variable 'l' referenced before assignment

使用 sign oot .net sam 單獨 規則 spa 兩個 總結: 內部函數,不修改全局變量可以訪問全局變量 內部函數,修改同名全局變量,則python會認為它是一個局部變量 在內部函數修改同名全局變量之前調用變量名稱(如print sum),則引發Unb

python UnboundLocalError: local variable 'xxx' referenced before assignment

大意就是在變數定義前就引用了變數。 錯誤程式碼如下: def f(): print(n) n = 10 f() 這裡還是很清楚,很明白。 然而下面的程式碼就令人有些頭疼: n = 100 def f(): print(n) n = 10 f()

Python-local variable 'raw_password' referenced before assignment

str 分支 true 解決 OS 得到 __name__ -s 作用 where?   執行Python程序的時候,報這個錯 why?   變量作用域問題,在分支中定義的變量,當滿足條件的時候則可以正確得到變量,當不滿足條件的時候則報這個錯 way?   把變量從分支中抽

關於local variable 'i' referenced before assignment

如題,執行程式碼如下: def createCounter(): i = 0 def counter(): i+=1 j = i return j return counter 程式碼執行後出錯,錯誤資訊為:lo

JSP 使用<%@include%>報Duplicate local variable path 錯誤 解決方法

錯誤提示 cat not 情況 cal quest epon bsp multi 錯誤提示:Multiple annotations found at this line:- Duplicate local variable path- Duplicate local va

Python3.x:pdf2htmlEX(解析pdf)安裝和使用

targe drm oom height pbo gin mage output javascrip Python3.x:pdf2htmlEX(解析pdf)安裝和使用 簡介 pdf2htmlEX是一款優秀的pdf轉換成html的工具; 下載 windows下載地址:http

Python3.x:PDFMiner3k在線、本地解析pdf

reg 忽略 quest raise 模式 www agg attr 本地 Python3.x:PDFMiner3k在線、本地解析pdf 安裝 pip install pdfminer3k 示例:在線解析pdf ‘‘‘ Demo:pdf2htmlex解析pdf

java9 Local-variable type inference

ont java white b- lis var span ray pac var ls = Arrays.asList("1","2"); System.out.println(ls);java9 Local-variable type inference

【Java】解決Gson解析資料int自動轉化為double問題

Gson可以將json字串轉換時, 原json字串中的int , long型的數字會預設被轉換成double型別 , 導致數字會多一個小數點 , 如 1 會轉成 1.0。 解決方法: 只需將Gson gson = new Gson();換成下面這個  Gson gson = n

java Error---Lambda expression's local variable e cannot re-declare another local variable defined e

在使用lambda表示式時,為控制元件新增事件響應函式時,出現: Lambda expression's local variable e cannot re-declare another local variable defined e 出錯的程式碼段如下: stage

Jupyter notebook 轉pdf出現的一個錯誤(只出現前4頁)及原因分析

文章目錄 問題描述 原因分析 解決方案 問題描述 最近迷上了利用Jupyter notebook 為工具學習有關Python語言方面的知識。遇到該錯誤純粹是個偶然,這應該算是Jupyter notebook的一個bug。 問題的

wkhtmltopdf 轉pdf元素被頁面切割開

1. <style> * { page-break-inside: avoid; page-break-after: avoid; page-break-before: avoid; } </s

用python解析pdf中的文字與表格【pdfplumber的安裝與使用】

我們接觸到的很多文件資料都是以pdf格式存在的,比如:論文,技術文件,標準檔案,書籍等。pdf格式使得用機器從中提取資訊格外困難。 為了解決這個問題,我找到了幾種解決方案,最後選擇了python上的pdfplumber庫,安裝和使用都相對比較方便,效果也還不錯,所以下面介紹這個庫的安裝與使用。 安裝我的電

關於Mac在配置反向代理伺服器出現/usr/local/nginx/logs/access.log" failed

如上面的access_log  因為下載的 nginx 沒有logs 資料夾 和 access.log檔案  ,所以我根據網上搜尋的答案 自己根據以上建立檔案 但是執行時候發現 報 8080埠 被佔用 sudo lsof -n -P | gr

aspose將word轉pdf亂碼,或者出現小方框問題

通常來講,出現這種問題一般是因為Linux伺服器沒有安裝中文字型   檢視Linux目前的所有字型 fc-list   檢視Linux目前的所有中文字型 fc-list :lang=zh   將windows的字型上傳到Linux