3

I am trying to convert PDF to text in Python. But it is giving me an error:

PDFTextExtractionNotAllowed: Text extraction is not allowed: <_io.BufferedReader name='C:\Users\Downloads\Facts_for_2017.pdf'>

Code which I am using is:

import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io    


def pdfparser(data):
    fp = open(data, 'rb')      
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data = retstr.getvalue()

    return data


if __name__ == '__main__':
    text = pdfparser(Input_path)

Can anyone help me?

File path is:

https://drive.google.com/file/d/1RyR-J-EwMywL6BqsYbl4Ocm96VzCYrM7/view?usp=sharing

Craicerjack
  • 6,203
  • 2
  • 31
  • 39

2 Answers2

4

The problem is that PDFPage.get_pages() checks if text is extractable by convention. You have to set the flag to check_extractable=False to make it work. Also, if the PDF you are trying to convert to txt is password-protected, you can change it there, too. Unfortunately, PDFPage's documentation is not very clear about it.

password = ""
for page in PDFPage.get_pages(fp, check_extractable=False, password=password):
    interpreter.process_page(page)
data = retstr.getvalue()

Your whole code would look like the following:

import io

from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage

def pdfparser(data):
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)

    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos = set()

    with open(data, 'rb') as fp:
        for page in PDFPage.get_pages(fp,
                                      pagenos, 
                                      maxpages=maxpages,
                                      password=password,
                                      caching=caching,
                                      check_extractable=False):
            interpreter.process_page(page)

    # As pointed out in another answer, this goes outside the loop
    text = retstr.getvalue()

    device.close()
    retstr.close()
    return text

NOTE: Python's with open ...: pattern implementation is useful to properly handle file objects.

mmunoz
  • 61
  • 6
0

You are getting the error because, the indentation is wrong in the line with data = retstr.getvalue(), it should be outside of the for loop.

However, after fixing that, I came across some other issues , so I am providing the full code below:

import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io    


def pdfparser(data):
    fp = open(data, 'rb')      
    rsrcmgr = PDFResourceManager()
    # retstr = io.StringIO() #This will cause -- `TypeError: unicode argument expected, got 'str'`
    retstr = io.BytesIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)

    data = retstr.getvalue() #Indentation was worng here
    fp.close()
    #print(data)
    return data


if __name__ == '__main__':
    #PDF file you provied is encrypted with blank password, we need to decrypt it
    path = sys.argv[1]
    from subprocess import call
    import os
    pdf_filename = os.path.basename(path)
    file_name, extension = os.path.splitext(pdf_filename)
    pdf_filename_decr = str(file_name) + "_decr" + extension
    call('qpdf --password=%s --decrypt %s %s' %('', path, pdf_filename_decr), shell=True)

    text = pdfparser(pdf_filename_decr)
realsdx
  • 28
  • 2
  • 7