textract scraping read python pdf

python - scraping - ¿Cómo extraer texto de un archivo PDF?



python search text in pdf (17)

Aquí está el código más simple para extraer texto

código:

from py4j.java_gateway import JavaGateway gw = JavaGateway() result = gw.entry_point.strip(''samples/bus.pdf'') # result is a dict of { # ''success'': ''true'' or ''false'', # ''payload'': pdf file content if ''success'' is ''true'' # ''error'': error message if ''success'' is ''false'' # } print result[''payload'']

Estoy tratando de extraer el texto incluido en this archivo PDF usando Python .

Estoy usando el módulo PyPDF2 y tengo el siguiente script:

import PyPDF2 pdf_file = open(''sample.pdf'') read_pdf = PyPDF2.PdfFileReader(pdf_file) number_of_pages = read_pdf.getNumPages() page = read_pdf.getPage(0) page_content = page.extractText() print page_content

Cuando ejecuto el código, obtengo el siguiente resultado que es diferente del incluido en el documento PDF:

!"#$%#$%&%$&''()*%+,-%./01''*23%4 5''%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&) %

¿Cómo puedo extraer el texto tal como está en el documento PDF?


Después de probar textract (que parecía tener demasiadas dependencias) y pypdf2 (que no podía extraer texto de los archivos PDF que probé) y tika (que era demasiado lento) terminé usando pdftotext de pdftotext (como ya se sugirió en otra respuesta) y solo llamé al binario desde python directamente (puede que necesite adaptar la ruta a pdftotext):

import os, subprocess SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) args = ["/usr/local/bin/pdftotext", ''-enc'', ''UTF-8'', "{}/my-pdf.pdf".format(SCRIPT_DIR), ''-''] res = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = res.stdout.decode(''utf-8'')

Hay pdftotext que hace básicamente lo mismo, pero esto supone pdftotext en / usr / local / bin, mientras que estoy usando esto en AWS lambda y quería usarlo desde el directorio actual.

Por cierto: para usar esto en lambda necesita poner el binario y la dependencia de libstdc++.so en su función lambda. Yo personalmente necesitaba compilar xpdf. Como las instrucciones para esto explotarían esta respuesta, las puse en mi blog personal .


El PDF de varias páginas se puede extraer como texto en una sola extensión en lugar de proporcionar un número de página individual como argumento usando el código siguiente

import PyPDF2 import collections pdf_file = open(''samples.pdf'', ''rb'') read_pdf = PyPDF2.PdfFileReader(pdf_file) number_of_pages = read_pdf.getNumPages() c = collections.Counter(range(number_of_pages)) for i in c: page = read_pdf.getPage(i) page_content = page.extractText() print page_content.encode(''utf-8'')


El siguiente código es una solución a la pregunta en Python 3 . Antes de ejecutar el código, asegúrese de haber instalado la biblioteca PyPDF2 en su entorno. Si no está instalado, abra el símbolo del sistema y ejecute el siguiente comando:

pip3 install PyPDF2

Código de solución:

import PyPDF2 pdfFileObject = open(''sample.pdf'', ''rb'') pdfReader = PyPDF2.PdfFileReader(pdfFileObject) count = pdfReader.numPages for i in range(count): page = pdfReader.getPage(i) print(page.extractText())


Encontré una solución aquí PDFLayoutTextStripper

Es bueno porque puede mantener el diseño del PDF original .

Está escrito en Java, pero he agregado una puerta de enlace para admitir Python.

Código de muestra:

from tika import parser raw = parser.from_file("///Users/Documents/Textos/Texto1.pdf") raw = str(raw) safe_text = raw.encode(''utf-8'', errors=''ignore'') safe_text = str(safe_text).replace("/n", "").replace("//", "") print(''--- safe text ---'' ) print( safe_text )

Salida de muestra de PDFLayoutTextStripper :

Puedes ver más detalles aquí Stripper con Python


Es posible que desee utilizar xPDF probado con el tiempo y herramientas derivadas para extraer texto, ya que pyPDF2 parece tener varios problemas con la extracción de texto todavía.

La respuesta larga es que hay muchas variaciones sobre cómo se codifica un texto dentro de PDF y que puede requerir decodificar la cadena de PDF, luego puede necesitar mapear con CMAP, luego puede necesitar analizar la distancia entre palabras y letras, etc.

En caso de que el PDF esté dañado (es decir, que muestre el texto correcto pero al copiarlo da basura) y realmente necesite extraer texto, puede considerar convertir el PDF a imagen (usando ImageMagik ) y luego usar Tesseract para obtener texto de la imagen usando OCR.


Estaba buscando una solución simple para Python 3.xy Windows. Parece que no hay soporte de textract , lo cual es desafortunado, pero si está buscando una solución simple para Windows / Python 3, consulte el paquete tika , realmente sencillo para leer archivos PDF

from tika import parser raw = parser.from_file(''sample.pdf'') print(raw[''content''])


Estoy agregando código para lograr esto: está funcionando bien para mí:

# This works in python 3 # required python packages # tabula-py==1.0.0 # PyPDF2==1.26.0 # Pillow==4.0.0 # pdfminer.six==20170720 import os import shutil import warnings from io import StringIO import requests import tabula from PIL import Image from PyPDF2 import PdfFileWriter, PdfFileReader from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.pdfpage import PDFPage warnings.filterwarnings("ignore") def download_file(url): local_filename = url.split(''/'')[-1] local_filename = local_filename.replace("%20", "_") r = requests.get(url, stream=True) print(r) with open(local_filename, ''wb'') as f: shutil.copyfileobj(r.raw, f) return local_filename class PDFExtractor(): def __init__(self, url): self.url = url # Downloading File in local def break_pdf(self, filename, start_page=-1, end_page=-1): pdf_reader = PdfFileReader(open(filename, "rb")) # Reading each pdf one by one total_pages = pdf_reader.numPages if start_page == -1: start_page = 0 elif start_page < 1 or start_page > total_pages: return "Start Page Selection Is Wrong" else: start_page = start_page - 1 if end_page == -1: end_page = total_pages elif end_page < 1 or end_page > total_pages - 1: return "End Page Selection Is Wrong" else: end_page = end_page for i in range(start_page, end_page): output = PdfFileWriter() output.addPage(pdf_reader.getPage(i)) with open(str(i + 1) + "_" + filename, "wb") as outputStream: output.write(outputStream) def extract_text_algo_1(self, file): pdf_reader = PdfFileReader(open(file, ''rb'')) # creating a page object pageObj = pdf_reader.getPage(0) # extracting extract_text from page text = pageObj.extractText() text = text.replace("/n", "").replace("/t", "") return text def extract_text_algo_2(self, file): pdfResourceManager = PDFResourceManager() retstr = StringIO() la_params = LAParams() device = TextConverter(pdfResourceManager, retstr, codec=''utf-8'', laparams=la_params) fp = open(file, ''rb'') interpreter = PDFPageInterpreter(pdfResourceManager, device) password = "" max_pages = 0 caching = True page_num = set() for page in PDFPage.get_pages(fp, page_num, maxpages=max_pages, password=password, caching=caching, check_extractable=True): interpreter.process_page(page) text = retstr.getvalue() text = text.replace("/t", "").replace("/n", "") fp.close() device.close() retstr.close() return text def extract_text(self, file): text1 = self.extract_text_algo_1(file) text2 = self.extract_text_algo_2(file) if len(text2) > len(str(text1)): return text2 else: return text1 def extarct_table(self, file): # Read pdf into DataFrame try: df = tabula.read_pdf(file, output_format="csv") except: print("Error Reading Table") return print("/nPrinting Table Content: /n", df) print("/nDone Printing Table Content/n") def tiff_header_for_CCITT(self, width, height, img_size, CCITT_group=4): tiff_header_struct = ''<'' + ''2s'' + ''h'' + ''l'' + ''h'' + ''hhll'' * 8 + ''h'' return struct.pack(tiff_header_struct, b''II'', # Byte order indication: Little indian 42, # Version number (always 42) 8, # Offset to first IFD 8, # Number of tags in IFD 256, 4, 1, width, # ImageWidth, LONG, 1, width 257, 4, 1, height, # ImageLength, LONG, 1, lenght 258, 3, 1, 1, # BitsPerSample, SHORT, 1, 1 259, 3, 1, CCITT_group, # Compression, SHORT, 1, 4 = CCITT Group 4 fax encoding 262, 3, 1, 0, # Threshholding, SHORT, 1, 0 = WhiteIsZero 273, 4, 1, struct.calcsize(tiff_header_struct), # StripOffsets, LONG, 1, len of header 278, 4, 1, height, # RowsPerStrip, LONG, 1, lenght 279, 4, 1, img_size, # StripByteCounts, LONG, 1, size of extract_image 0 # last IFD ) def extract_image(self, filename): number = 1 pdf_reader = PdfFileReader(open(filename, ''rb'')) for i in range(0, pdf_reader.numPages): page = pdf_reader.getPage(i) try: xObject = page[''/Resources''][''/XObject''].getObject() except: print("No XObject Found") return for obj in xObject: try: if xObject[obj][''/Subtype''] == ''/Image'': size = (xObject[obj][''/Width''], xObject[obj][''/Height'']) data = xObject[obj]._data if xObject[obj][''/ColorSpace''] == ''/DeviceRGB'': mode = "RGB" else: mode = "P" image_name = filename.split(".")[0] + str(number) print(xObject[obj][''/Filter'']) if xObject[obj][''/Filter''] == ''/FlateDecode'': data = xObject[obj].getData() img = Image.frombytes(mode, size, data) img.save(image_name + "_Flate.png") # save_to_s3(imagename + "_Flate.png") print("Image_Saved") number += 1 elif xObject[obj][''/Filter''] == ''/DCTDecode'': img = open(image_name + "_DCT.jpg", "wb") img.write(data) # save_to_s3(imagename + "_DCT.jpg") img.close() number += 1 elif xObject[obj][''/Filter''] == ''/JPXDecode'': img = open(image_name + "_JPX.jp2", "wb") img.write(data) # save_to_s3(imagename + "_JPX.jp2") img.close() number += 1 elif xObject[obj][''/Filter''] == ''/CCITTFaxDecode'': if xObject[obj][''/DecodeParms''][''/K''] == -1: CCITT_group = 4 else: CCITT_group = 3 width = xObject[obj][''/Width''] height = xObject[obj][''/Height''] data = xObject[obj]._data # sorry, getData() does not work for CCITTFaxDecode img_size = len(data) tiff_header = self.tiff_header_for_CCITT(width, height, img_size, CCITT_group) img_name = image_name + ''_CCITT.tiff'' with open(img_name, ''wb'') as img_file: img_file.write(tiff_header + data) # save_to_s3(img_name) number += 1 except: continue return number def read_pages(self, start_page=-1, end_page=-1): # Downloading file locally downloaded_file = download_file(self.url) print(downloaded_file) # breaking PDF into number of pages in diff pdf files self.break_pdf(downloaded_file, start_page, end_page) # creating a pdf reader object pdf_reader = PdfFileReader(open(downloaded_file, ''rb'')) # Reading each pdf one by one total_pages = pdf_reader.numPages if start_page == -1: start_page = 0 elif start_page < 1 or start_page > total_pages: return "Start Page Selection Is Wrong" else: start_page = start_page - 1 if end_page == -1: end_page = total_pages elif end_page < 1 or end_page > total_pages - 1: return "End Page Selection Is Wrong" else: end_page = end_page for i in range(start_page, end_page): # creating a page based filename file = str(i + 1) + "_" + downloaded_file print("/nStarting to Read Page: ", i + 1, "/n -----------===-------------") file_text = self.extract_text(file) print(file_text) self.extract_image(file) self.extarct_table(file) os.remove(file) print("Stopped Reading Page: ", i + 1, "/n -----------===-------------") os.remove(downloaded_file) # I have tested on these 3 pdf files # url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Healthcare-January-2017.pdf" url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Sample_Test.pdf" # url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Sazerac_FS_2017_06_30%20Annual.pdf" # creating the instance of class pdf_extractor = PDFExtractor(url) # Getting desired data out pdf_extractor.read_pages(15, 23)


He probado muchos convertidores PDF de Python, Tika es el mejor.

# importing required modules import PyPDF2 # creating a pdf file object pdfFileObj = open(''filename.pdf'', ''rb'') # creating a pdf reader object pdfReader = PyPDF2.PdfFileReader(pdfFileObj) # printing number of pages in pdf file print(pdfReader.numPages) # creating a page object pageObj = pdfReader.getPage(5) # extracting text from page print(pageObj.extractText()) # closing the pdf file object pdfFileObj.close()


Mira este código:

import PyPDF2 pdf_file = open(''sample.pdf'', ''rb'') read_pdf = PyPDF2.PdfFileReader(pdf_file) number_of_pages = read_pdf.getNumPages() page = read_pdf.getPage(0) page_content = page.extractText() print page_content.encode(''utf-8'')

El resultado es:

!"#$%#$%&%$&''()*%+,-%./01''*23%4 5''%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&) %

Usando el mismo código para leer un pdf de 201308FCR.pdf . La salida es normal.

Su documentation explica por qué:

def extractText(self): """ Locate all text drawing commands, in the order they are provided in the content stream, and extract the text. This works well for some PDF files, but poorly for others, depending on the generator used. This will be refined in the future. Do not rely on the order of text coming out of this function, as it will change if this function is made more sophisticated. :return: a unicode string object. """


Puede descargar tika-app-xxx.jar (más reciente) desde Here .

Luego, coloque este archivo .jar en la misma carpeta de su archivo de script de Python.

luego inserte el siguiente código en el script:

import os import os.path tika_dir=os.path.join(os.path.dirname(__file__),''<tika-app-xxx>.jar'') def extract_pdf(source_pdf:str,target_txt:str): os.system(''java -jar ''+tika_dir+'' -t {} > {}''.format(source_pdf,target_txt))

La ventaja de este método:

Menos dependencia. El archivo .jar único es más fácil de administrar que un paquete de Python.

Soporte multiformato. La posición source_pdf puede ser el directorio de cualquier tipo de documento. (.doc, .html, .odt, etc.)

A hoy. tika-app.jar siempre se publica antes de la versión relevante del paquete tika python.

estable. Es mucho más estable y está bien mantenido (Desarrollado por Apache) que PyPDF.

desventaja:

Un jre-headless es necesario.


Puede usar PDFtoText pdftotext

PDF to text mantiene la sangría del formato de texto, no importa si tiene tablas.


PyPDF2 en algunos casos ignora los espacios en blanco y hace que el texto resultante sea un desastre, pero uso PyMuPDF y estoy realmente satisfecho de que pueda usar este link para obtener más información


PyPDF2 funciona, pero los resultados pueden variar. Estoy viendo resultados bastante inconsistentes de su extracción de resultados.

reader=PyPDF2.pdf.PdfFileReader(self._path) eachPageText=[] for i in range(0,reader.getNumPages()): pageText=reader.getPage(i).extractText() print(pageText) eachPageText.append(pageText)


Si lo prueba en Anaconda en Windows, PyPDF2 podría no manejar algunos de los archivos PDF con estructura no estándar o caracteres unicode. Recomiendo usar el siguiente código si necesita abrir y leer muchos archivos pdf: el texto de todos los archivos pdf en la carpeta con la ruta relativa .//pdfs// se almacenará en la lista pdf_text_list .

from tika import parser import glob def read_pdf(filename): text = parser.from_file(filename) return(text) all_files = glob.glob(".//pdfs//*.pdf") pdf_text_list=[] for i,file in enumerate(all_files): text=read_pdf(file) pdf_text_list.append(text[''content'']) print(pdf_text_list)



pdftotext es el mejor y más simple! pdftotext también se reserva la estructura también.

Probé PyPDF2, PDFMiner y algunos otros, pero ninguno de ellos dio un resultado satisfactorio.