Python'da PDFMiner kullanarak bir PDF dosyasından metin çıkarmak mı?


89

Python ile PDFMiner kullanarak bir PDF dosyasından metnin nasıl çıkarılacağına dair belgeler veya örnekler arıyorum .

Görünüşe göre PDFMiner API'larını güncelledi ve bulduğum tüm ilgili örnekler güncel olmayan kod içeriyor (sınıflar ve yöntemler değişti). PDF dosyasından metin çıkarma görevini kolaylaştıran bulduğum kitaplıklar eski PDFMiner sözdizimini kullanıyor, bu yüzden bunu nasıl yapacağımdan emin değilim.

Olduğu gibi, anlayıp anlayamayacağımı görmek için sadece kaynak koduna bakıyorum.


1
Lütfen stackoverflow.com/help/how-to-ask ve stackoverflow.com/help/mcve sayfalarına göz atın ve yanıtınızı daha iyi bir biçimde ve yönergelere uygun olacak şekilde güncelleyin.
Parker

Hangi Python dağıtımını kullanıyorsunuz, 2.7.x veya 3.xx? Yazarın Python 3.xx ile çalışmadığını açıkça detaylandırdığına dikkat edilmelidir . Hata PDFmineralmanın nedeni bu olabilir import. pdfminer3kEğer öyleyse, söz konusu kütüphanenin duran Python 3 içe aktarımı olduğu için kullanmalısınız .
NullDev

@Nanashi, üzgünüm, Python versiyonumu eklemeyi unuttum. 2.7, yani sorun bu değil. Kaynak koduna bakıyordum ve bazı şeyleri yeniden yapılandırmış gibi görünüyorlar, bu yüzden ithalatlar kırılıyor. PDFMiner için de herhangi bir belge bulamıyorum ya da bunun üzerinde çalışıyordum :(
DuckPuncher

Tam anlamıyla PDFminerGitHub'dan yükledim ve iyi ithal ediyor. Lütfen kodunuzu gönderebilir ve tam hata takibinizi de gönderebilir misiniz?
NullDev

@Nanashi, Orijinal sorumda da söylediğim gibi, PDFMiner'e dayanan kütüphaneler, bulabildiğim herhangi bir örnekle birlikte içe aktarmaları bitirmeden önce kırılıyor. Bu bir PDFMiner sorunu değildir. Bu, belgeleri veya PDFMiner'ın nasıl kullanılacağına dair bir örnek arıyorum. Bulabildiğim her şey, PDFMiner için eski bir sözdizimi kullanıyor. Devam ettim ve sorumu açıklığa kavuşturmak için düzenledim. Sanırım olması gerekenden daha kafa karıştırıcı hale getirdim. Bunun için üzgünüm.
DuckPuncher

Yanıtlar:


184

PDFMiner'ın güncel sürümünü (Eylül 2016) kullanarak bir PDF dosyasından metin ayıklamanın çalışan bir örneğini burada bulabilirsiniz.

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

def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()

    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True):
        interpreter.process_page(page)

    text = retstr.getvalue()

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

PDFMiner'ın yapısı yakın zamanda değişti, bu nedenle bu, PDF dosyalarından metin çıkarmak için çalışmalıdır.

Düzenleme : 7 Haziran 2018 itibarıyla çalışmaya devam ediyor. Python Sürüm 3.x'te doğrulandı

Düzenleme: Çözüm 3 Ekim 2019'da Python 3.7 ile çalışıyor pdfminer.six. Kasım 2018'de yayınlanan Python kitaplığını kullandım .


2
iyi çalışıyor, ancak örneğin isimlerdeki boşluklarla nasıl başa çıkabilirim? bir sütunda ad ve soyadım bulunan 4 sütun içeren bir pdf'm olduğunu varsayalım, şimdi bir satırda ad ve bir satırda soyad ile ayrıştırılıyor, işte bir örnek docdro.id/rRyef3x
Deusdeorum

2
Şu anda bu kodla bir içe aktarma hatası alıyorum: ImportError: 'pdfminer.pdfpage' adlı modül yok
Jeffrey Swan

1
Teşekkürler python v2.7.12 ve ubuntu 16.04 üzerinde çalışıyor, ancak pdf belgesini utf-8 kodlamasıyla yüklemek daha iyi olacaktır, çünkü örnek pdf'mde bazı kodlama sorunları var, bu yüzden bunu utf-8 ile kodladıktan sonra deneyin ve sorunu ... import sys reload(sys) sys.setdefaultencoding('utf-8')
sib10

2
@DuckPuncher, hala çalışıyor mu? Ben değiştirmek zorunda file(path, 'rb')işe mayın almak için açık (yol, 'rb') `için.
craned

2
Halen Python3.7 kullanıcıları için çalışıyor. Yüklü pdfminer.six == 20181108 paketi. Şimdiye kadarki en iyi çözüm ve çok sayıda çözümü karşılaştırdım.
aze45sq6d

30

DuckPuncher'dan müthiş cevap, Python3 için pdfminer2'yi kurduğunuzdan ve yaptığınızdan emin olun:

import io

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


def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos = set()

    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages,
                                  password=password,
                                  caching=caching,
                                  check_extractable=True):
        interpreter.process_page(page)



    fp.close()
    device.close()
    text = retstr.getvalue()
    retstr.close()
    return text

1
Benim için çalışmıyor: ModuleNotFoundError: 'pdfminer.pdfpage' adlı modül yok python 3.6 kullanıyorum
Atti

@Atti, her ihtimale karşı, pdfminer2'nin kurulu olduğundan emin ol, çünkü başka bir pdfminer paketi var (bundan nefret ediyorum). Pip3 dondurma işlemi yaparken pdfminer2 == 20151206 sürümü için çalışır.
juan Isaza

5
teşekkürler sonunda çalıştırdım, conda forge'dan pdfminer.six'i yükledim
Atti

8
Python 3 için pdfminer.six önerilen pakettir - github.com/pdfminer/pdfminer.six
Mike Driscoll

Bu hala güncel mi? Aynı ImportError:mesajı alıyorum

14

Bu, Mayıs 2020'de Python3'te PDFminer altı kullanılarak çalışır.

Paketi kurmak

$ pip install pdfminer.six

Paketi içe aktarma

from pdfminer.high_level import extract_text

Diske kaydedilmiş bir PDF'yi kullanma

text = extract_text('report.pdf')

Veya alternatif olarak:

with open('report.pdf','rb') as f:
    text = extract_text(f)

Zaten bellekte bulunan PDF'yi kullanma

PDF zaten bellekteyse, örneğin istek kitaplığıyla web'den alınırsa, iokitaplık kullanılarak bir akışa dönüştürülebilir :

import io

response = requests.get(url)
text = extract_text(io.BytesIO(response.content))

PyPDF2 ile karşılaştırıldığında Performans ve Güvenilirlik

PDFminer.six, PyPDF2'den (belirli PDF türlerinde başarısız olur), özellikle de PDF sürüm 1.7'den daha güvenilir çalışır

Bununla birlikte, PDFminer.six ile metin çıkarma, PyPDF2'den 6 kat daha yavaştır.

Metin çıkarma işlemini timeit15 "MBP (2018) ile, 10 sayfalık bir PDF ile yalnızca çıkarma işlevini (dosya açma vb.) Zamanlayarak zamanladım ve aşağıdaki sonuçları aldım:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six ayrıca, Alpine Linux üzerinde 80 MB'den 350 MB'a kadar minimum yükleme docker imajını iterek GCC ve kurulu diğer şeylere ihtiyaç duyan pycryptodome gerektiren büyük bir ayak izine sahiptir. PyPDF2'nin gözle görülür bir depolama etkisi yoktur.


Bu yaklaşım son güncellemeden bu yana bozulmuş olabilir. Şu anda ImportError: cannot import name 'open_filename' from 'pdfminer.utils'çalıştırdığımda hatayı alıyorumfrom pdfminer.high_level import extract_text
Daha Fazla Okuma

1
Güncelleme: Bunu yeni bir venv oluşturarak ve pdfminer.six'i yeniden yükleyerek düzelttim. Sanırım daha önce denediğim diğer pdf paketlerinden biri bir şekilde karışıyordu.
Ek Okuma

11

Tam açıklama, ben pdfminer.six'in koruyucularından biriyim.

Günümüzde, ihtiyaçlarınıza bağlı olarak bir PDF'den metin çıkarmak için birden fazla API vardır. Perde arkasında, bu API'lerin tümü düzeni ayrıştırmak ve analiz etmek için aynı mantığı kullanır.

(Tüm örnekler, PDF dosyanızın example.pdf olarak adlandırıldığını varsayar )

Komut satırı

Metni yalnızca bir kez çıkarmak istiyorsanız, pdf2txt.py komut satırı aracını kullanabilirsiniz:

$ pdf2txt.py example.pdf

Üst düzey API

Python ile metin çıkarmak istiyorsanız, yüksek seviyeli api'yi kullanabilirsiniz. Birçok PDF'den programlı olarak metin çıkarmak istiyorsanız, bu yaklaşım ideal bir çözümdür.

from pdfminer.high_level import extract_text

text = extract_text('example.pdf')

Oluşturulabilir API

Ortaya çıkan nesnelerin işlenmesinde çok fazla esneklik sağlayan bir araya getirilebilir api de vardır. Örneğin, bunu kullanarak kendi düzen algoritmanızı uygulayabilirsiniz. Bu yöntem diğer yanıtlarda önerilmektedir, ancak bunu yalnızca pdfminer.six'in çalışma şeklini özelleştirmeniz gerektiğinde tavsiye ederim.

from io import StringIO

from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser

output_string = StringIO()
with open('example.pdf', 'rb') as in_file:
    parser = PDFParser(in_file)
    doc = PDFDocument(parser)
    rsrcmgr = PDFResourceManager()
    device = TextConverter(rsrcmgr, output_string, laparams=LAParams())
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.create_pages(doc):
        interpreter.process_page(page)

print(output_string.getvalue())

0

bu kod python 3 için pdfminer ile test edilmiştir (pdfminer-20191125)

from pdfminer.layout import LAParams
from pdfminer.converter import PDFPageAggregator
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.layout import LTTextBoxHorizontal

def parsedocument(document):
    # convert all horizontal text into a lines list (one entry per line)
    # document is a file stream
    lines = []
    rsrcmgr = PDFResourceManager()
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.get_pages(document):
            interpreter.process_page(page)
            layout = device.get_result()
            for element in layout:
                if isinstance(element, LTTextBoxHorizontal):
                    lines.extend(element.get_text().splitlines())
    return lines

Nitro Pro aracını kullanarak dönüştürebildiğim PDF dosyalarım var. Bununla birlikte, aynı PDF'yi burada yayınlanan kodu kullanarak dönüştürmeye çalıştığımda, bir izin hatası olduğunu gösteren çıktı alıyorum. Çıktı: ('SAGE Sosyal Bilimler Koleksiyonları'ndan. Tüm Hakları Saklıdır. \ N \ n \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c ')
b00kgrrl

Dosya akışı ne demek?
Vincent

@Vincent ile akış olarak açık (dosya, 'rb'): [...]
Rodrigo Formighieri

bu dosyayı ideal olarak bir masa / pandalar olarak almayı başarıyor musunuz? groupe-psa.com/en/publication/monthly-world-sales-march-2020
Nono London
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.