Как извлечь текст из файла PDF?
Я пытаюсь извлечь текст, включенный в этот файл PDF, используя Python
.
Я использую модуль PyPDF2, и у меня есть следующий скрипт:
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
Когда я запускаю код, я получаю следующий вывод, который отличается от того, который включен в документ PDF:
!"#$%#$%&%$&'()*%+,-%./01'*23%4
5'%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&)
%
Как я могу извлечь текст, как в документе PDF?
Ответы
Ответ 1
Ищет простое решение для использования в python 3.x и windows. Кажется, нет поддержки от textract, что является неудачным, но если вы ищете простое решение для windows/python 3, то посмотрите на пакет tika, действительно прямо для чтения pdf файлов
from tika import parser
raw = parser.from_file('sample.pdf')
print(raw['content'])
Ответ 2
Используйте textract.
Он поддерживает множество типов файлов, включая файлы PDF
import textract
text = textract.process("path/to/file.extension")
Ответ 3
Посмотрите на этот код:
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')
Выход:
!"#$%#$%&%$&'()*%+,-%./01'*23%4
5'%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&)
%
Используя тот же код, чтобы прочитать pdf файл с 201308FCR.pdf. Выход нормальный.
В его документации объясняется, почему:
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.
"""
Ответ 4
Попробовав textract (который, казалось, слишком много зависимостей) и pypdf2 (который не смог извлечь текст из pdf файлов, которые я тестировал) и tika (который был слишком медленным), я закончил использование pdftotext
из xpdf (как уже было сказано в другом ответе) и просто вызвал двоичный код из python напрямую (вам может понадобиться адаптировать путь к 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')
Существует pdftotext, который делает в основном то же самое, но это предполагает pdftotext в /usr/local/bin, тогда как я использую это в AWS lambda и хочу использовать его из текущего каталога.
Btw: Для использования этого на лямбда вам нужно поместить двоичный код и зависимость к libstdc++.so
в вашу лямбда-функцию. Мне лично нужно было компилировать xpdf. Поскольку инструкции для этого взорвут этот ответ, я помещаю их в свой личный блог.
Ответ 5
Возможно, вы захотите использовать проверенные временем xPDF и производные инструменты для извлечения текста, а pyPDF2, похоже, все еще имеет проблемы с извлечением текста.
Долгий ответ заключается в том, что существует множество вариантов того, как текст кодируется внутри PDF и что может потребоваться сама декодированная строка PDF, тогда может потребоваться сопоставить с CMAP, тогда может потребоваться проанализировать расстояние между словами и буквами и т.д.
В случае повреждения PDF файла (т.е. Отображения правильного текста, но при копировании он дает мусор), и вам действительно нужно извлечь текст, тогда вы можете захотеть конвертировать PDF в изображение (используя ImageMagik), а затем использовать Tesseract для получения текста из изображения используя OCR.
Ответ 6
Нижеприведенный код является решением вопроса на Python 3. Перед запуском кода убедитесь, что вы установили библиотеку PyPDF2
в свою среду. Если не установлено, откройте командную строку и выполните следующую команду:
pip3 install PyPDF2
Код решения:
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())
Ответ 7
Многостраничный pdf файл можно извлекать как текст на одном участке, а не указывать номер страницы в качестве аргумента, используя приведенный ниже код
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')
Ответ 8
Вы можете использовать PDFtoText
https://github.com/jalan/pdftotext
PDF в текст сохраняет отступ текстового формата, не имеет значения, есть ли у вас таблицы.
Ответ 9
Вот самый простой код для извлечения текста
код:
# 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()
Ответ 10
PyPDF2 в некоторых случаях игнорирует пробелы и делает текст результата беспорядочным, но я использую PyMuPDF, и я действительно доволен, что вы можете использовать эту ссылку для получения дополнительной информации
Ответ 11
pdftotext самый лучший и самый простой! pdftotext также сохраняет структуру.
Я пробовал PyPDF2, PDFMiner и несколько других, но ни один из них не дал удовлетворительного результата.
Ответ 12
Я нашел решение здесь PDFLayoutTextStripper
Это хорошо, потому что он может сохранить макет оригинального PDF.
Он написан на Java, но я добавил шлюз для поддержки Python.
Образец кода:
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']
Пример вывода из PDFLayoutTextStripper : ![enter image description here]()
Вы можете увидеть больше деталей здесь Stripper with Python
Ответ 13
Я пробовал много конвертеров Python PDF, Тика лучше.
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 )
Ответ 14
Я добавляю код для этого: он отлично работает для меня:
# 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)
Ответ 15
Вы можете скачать tika-app-xxx.jar (последняя) отсюда.
Затем поместите этот.jar файл в ту же папку вашего файла сценария python.
затем вставьте следующий код в скрипт:
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))
Преимущество этого метода:
меньше зависимости. Один файл.jar проще управлять пакетом python.
многоформатная поддержка. Позиция source_pdf
может быть каталогом любого документа. (.doc,.html,.odt и т.д.)
до настоящего времени. tika-app.jar всегда выпускает ранее, чем соответствующая версия пакета tika python.
стабильный. Он намного более стабилен и ухожен (поддерживается Apache), чем PyPDF.
недостаток:
Необходима белая голова.
Ответ 16
Если вы попробуете это в Anaconda в Windows, PyPDF2 может не обрабатывать некоторые PDF файлы с нестандартной структурой или символами Юникода. Я рекомендую использовать следующий код, если вам нужно открыть и прочитать много файлов PDF - текст всех файлов PDF в папке с относительным путем .//pdfs//
будет сохранен в списке 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)
Ответ 17
PyPDF2 работает, но результаты могут отличаться. Я вижу весьма противоречивые выводы из результатов его извлечения.
reader=PyPDF2.pdf.PdfFileReader(self._path)
eachPageText=[]
for i in range(0,reader.getNumPages()):
pageText=reader.getPage(i).extractText()
print(pageText)
eachPageText.append(pageText)