Moduł Pythona do konwersji plików PDF na tekst [zamknięty]

385

Czy istnieje moduł Pythona do konwersji plików PDF na tekst? Wypróbowałem jeden fragment kodu znaleziony w Activestate, który używa pypdf, ale w wygenerowanym tekście nie było spacji i nie było pożytku.

cnu
źródło
1
Szukałem podobnego rozwiązania. Muszę tylko przeczytać tekst z pliku pdf. Nie potrzebuję obrazów. pdfminer to dobry wybór, ale nie znalazłem prostego przykładu, jak wyodrębnić tekst. Wreszcie otrzymałem tę SO odpowiedź ( stackoverflow.com/questions/5725278/... ) i teraz jej używam.
Nayan
2
Odkąd pytanie zostało zamknięte, opublikowałem je ponownie na Stack Exchange poświęconym zaleceniom oprogramowania na wypadek, gdyby ktoś chciał napisać nową odpowiedź: moduł Pythona do konwersji plików PDF na tekst
Franck Dernoncourt
1
Jedyne rozwiązanie, które zadziałało dla mnie w przypadku zawartości UTF-8: Apache Tika
Shoham
Chciałbym zaktualizować listę dostępnych opcji konwersji PDF na tekst w Pythonie, GroupDocs.Conversion Cloud SDK dla Pythona dokładnie konwertuje PDF na tekst.
Tilal Ahmad

Odpowiedzi:

142

Wypróbuj PDFMiner . Może wyodrębniać tekst z plików PDF w formacie HTML, SGML lub „Tagged PDF”.

Format Tagged PDF wydaje się być najczystszy, a usunięcie tagów XML pozostawia tylko czysty tekst.

Wersja Python 3 jest dostępna pod:

David Crow
źródło
2
Właśnie dodałem odpowiedź opisującą, jak używać pdfminer jako biblioteki.
codeape
24
brak wsparcia dla Pythona 3 :(
Karl Adler,
1
Odpowiedź, którą podałem w tym wątku, może być przydatna dla osób przeglądających tę odpowiedź i zastanawiających się, jak korzystać z biblioteki. Podaję przykład wykorzystania biblioteki PDFMiner do wyodrębnienia tekstu z pliku PDF. Ponieważ dokumentacja jest nieco rzadka, pomyślałem, że może pomóc kilku osobom.
DuckPuncher
17
jeśli chodzi o python 3, istnieje sześciopoziomowy widelec pypi.python.org/pypi/pdfminer.six
Denis Cornehl
1
przykładowy kod na stackoverflow.com/a/26495057/125617
Renaud
136

PDFMiner pakiet zmieniła się od codeape pisał.

EDYCJA (ponownie):

PDFMiner został ponownie zaktualizowany w wersji 20100213

Możesz sprawdzić zainstalowaną wersję za pomocą:

>>> import pdfminer
>>> pdfminer.__version__
'20100213'

Oto zaktualizowana wersja (z komentarzami do tego, co zmieniłem / dodałem):

def pdf_to_csv(filename):
    from cStringIO import StringIO  #<-- added so you can copy/paste this to try it
    from pdfminer.converter import LTTextItem, TextConverter
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item.objs:
                if isinstance(child, LTTextItem):
                    (_,_,x,y) = child.bbox                   #<-- changed
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)  #<-- changed

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, codec="utf-8")  #<-- changed 
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       #<-- changed
    parser.set_document(doc)     #<-- added
    doc.set_parser(parser)       #<-- added
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

Edytuj (jeszcze raz):

Tutaj jest aktualizacja do najnowszej wersji w PyPI , 20100619p1. W skrócie Wymieniłem LTTextItemz LTChari przeszedł wystąpienie LAParams do konstruktora CsvConverter.

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter    #<-- changed
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item.objs:
                if isinstance(child, LTChar):               #<-- changed
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, codec="utf-8", laparams=LAParams())  #<-- changed
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       
    parser.set_document(doc)     
    doc.set_parser(parser)       
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        if page is not None:
            interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

EDYCJA (jeszcze raz):

Zaktualizowano do wersji 20110515(dzięki Oeufcoque Penteano!):

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item._objs:                #<-- changed
                if isinstance(child, LTChar):
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child._text.encode(self.codec) #<-- changed

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, codec="utf-8", laparams=LAParams())
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       
    parser.set_document(doc)     
    doc.set_parser(parser)       
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        if page is not None:
            interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()
Tray
źródło
1
W [6]: import pdfminer W [7]: pdfminer .__ wersja__ Out [7]: '20100424' W [8]: z importu pdfminer.converter LTTextItem ImportError: nie można zaimportować nazwy LTTextItem .... LITERALS_DCT_DECODE LTChar LTImage LTPolygon LTTextBox LICEAR LTContainer LTLine LTRect LTTextGroup LITERAL_DEVICE_RGB LTFigure LTPage LTText LTTextLine
Skylar Saveland
@skyl, powyższy kod dotyczy poprzedniej wersji „20100213”. Z listy zmian na swojej stronie internetowej, wygląda na to, że zmieniła LTTextItemsię LTChar. unixuser.org/~euske/python/pdfminer/index.html#changes
tgray
2
@Oeufcoque Penteano, dzięki! Dodałem kolejną sekcję do odpowiedzi na wersję 20110515dla twojego komentarza.
tgray
1
Odpowiedź udzielona przez @ user3272884 działa od 5-1-2014
jmunsch
1
Musiałem dziś rozwiązać ten sam problem, nieco zmodyfikowałem kod tgraya, aby wyodrębnić informacje o białych
znakach
67

Ponieważ żadne z tych rozwiązań nie obsługuje najnowszej wersji PDFMiner, napisałem proste rozwiązanie, które zwróci tekst pdf za pomocą PDFMiner. Działa to dla tych, którzy mają błędy importowaniaprocess_pdf

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
from cStringIO import StringIO

def pdfparser(data):

    fp = file(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

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

    print data

if __name__ == '__main__':
    pdfparser(sys.argv[1])  

Zobacz poniżej kod, który działa dla Python 3:

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)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

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

    print(data)

if __name__ == '__main__':
    pdfparser(sys.argv[1])  
użytkownik3272884
źródło
2
to pierwszy znaleziony fragment, który faktycznie działa z dziwnymi plikami PDF (szczególnie z darmowymi ebookami, które można uzyskać z packtpub). Każdy inny kod po prostu zwraca dziwnie zakodowane surowe rzeczy, ale twój faktycznie zwraca tekst. Dzięki!
somada141
Prawdopodobnie zechcesz wykonać retstr.seek (0) po uzyskaniu danych, w przeciwnym razie gromadzisz tekst ze wszystkich stron.
Tshirtman
2
Aby używać python3oprócz oczywistych nawiasów po printpoleceniu, należy zastąpić filepolecenie openi zaimportować StringIOz pakietuio
McLawrence
1
Łał. Ten blok działał idealnie za pierwszym razem, gdy go skopiowałem. Niesamowite! Na parsowaniu i naprawianiu danych i bez stresowania nad ich wprowadzaniem.
SecsAndCyber
1
pdfminer nie działa dla Python3. Ten kod nie działa pdfminer3k
thang
47

Pdftotext Program typu open source (część Xpdf), który możesz wywołać z pythona (nie to, o co prosiłeś, ale może być przydatny). Użyłem go bez problemów. Myślę, że Google używa go w Google Desktop.

Jamie
źródło
6
Wydaje się, że jest to najbardziej przydatne z wymienionych tutaj narzędzi, z -layoutopcją utrzymania tekstu w tej samej pozycji, co w pliku PDF. Teraz gdybym tylko mógł wymyślić, jak umieścić w nim zawartość pliku PDF.
Matthew Schinckel
Po przetestowaniu kilku rozwiązań, to wydaje się być najprostszą i najbardziej niezawodną opcją. Może być łatwo owinięty przez Pythona za pomocą pliku tymczasowego, aby określić, gdzie zapisywane jest wyjście.
Cerin
Cerin , użyj „-” jako nazwy pliku, aby przekierować wyjście na standardowe wyjście. W ten sposób możesz użyć prostego subprocess.check_output, a to wywołanie wydawałoby się funkcją wewnętrzną.
Ctrl-C
Aby ponownie wymusić stosowanie tego, kto go używa. . . pdftotextwydaje się działać bardzo dobrze, ale potrzebuje drugiego argumentu, który jest łącznikiem, jeśli chcesz zobaczyć wyniki na standardowym wyjściu.
Gordon Linoff,
1
Spowoduje to konwersję rekursywnie wszystkich plików PDF, zaczynając od bieżącego folderu: find . -iname "*.pdf" -exec pdftotext -enc UTF-8 -eol unix -raw {} \;Domyślnie wygenerowane pliki przyjmują oryginalną nazwę z .txtrozszerzeniem.
ccpizza,
43

pyPDF działa dobrze (zakładając, że pracujesz z dobrze sformatowanymi plikami PDF). Jeśli wszystko, czego chcesz, to tekst (ze spacjami), możesz po prostu:

import pyPdf
pdf = pyPdf.PdfFileReader(open(filename, "rb"))
for page in pdf.pages:
    print page.extractText()

Możesz także łatwo uzyskać dostęp do metadanych, danych obrazu i tak dalej.

Komentarz w uwagach do kodu extractText:

Znajdź wszystkie polecenia rysowania tekstu w kolejności, w jakiej znajdują się w strumieniu treści, i wyodrębnij tekst. Działa to dobrze dla niektórych plików PDF, ale źle dla innych, w zależności od użytego generatora. Zostanie to poprawione w przyszłości. Nie polegaj na kolejności tekstu wychodzącego z tej funkcji, ponieważ zmieni się ona, jeśli ta funkcja stanie się bardziej zaawansowana.

To, czy jest to problem, zależy od tego, co robisz z tekstem (np. Jeśli kolejność nie ma znaczenia, jest w porządku, lub jeśli generator dodaje tekst do strumienia w kolejności, w jakiej będzie wyświetlany, jest w porządku) . Mam kod ekstrakcji pyPdf do codziennego użytku, bez żadnych problemów.

Tony Meyer
źródło
7
brak obsługi Unicode :(
PanosJee 14.10.10
7
pyPdf obsługuje teraz UTF.
lbolla
2
Ta biblioteka wygląda jak śmieci. Testowanie na losowej PDF daje mi błąd „pyPdf.utils.PdfReadError: znacznik EOF nie znaleziono”
CERIN
4
Z pytania: wygenerowany tekst nie miał odstępu między i był bezużyteczny . Użyłem pyPDF i uzyskałem ten sam wynik - tekst jest wyodrębniany bez spacji między słowami.
Jordan Reiter,
Kiedy wykonuję funkcję page.extractText (), pojawia się błąd „TypeError: Nie można przekonwertować obiektu„ bytes ”na niejawnie„ Jak sobie z tym poradzić?
juankysmith
21

Możesz również dość łatwo użyć pdfminer jako biblioteki. Masz dostęp do modelu treści pdf i możesz stworzyć własną ekstrakcję tekstu. Zrobiłem to, aby przekonwertować zawartość pdf na tekst oddzielony średnikiem, używając poniższego kodu.

Funkcja po prostu sortuje obiekty treści TextItem według ich współrzędnych yi x, i wysyła elementy o tej samej współrzędnej y jak jedna linia tekstu, oddzielając obiekty w tej samej linii za pomocą „;” postacie.

Dzięki takiemu podejściu udało mi się wyodrębnić tekst z pliku pdf, z którego żadne inne narzędzie nie było w stanie wyodrębnić treści odpowiedniej do dalszej analizy. Inne narzędzia, które wypróbowałem, to pdftotext, ps2ascii i narzędzie online pdftextonline.com.

pdfminer to nieocenione narzędzie do skrobania pdf.


def pdf_to_csv(filename):
    from pdflib.page import TextItem, TextConverter
    from pdflib.pdfparser import PDFDocument, PDFParser
    from pdflib.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item.objs:
                if isinstance(child, TextItem):
                    (_,_,x,y) = child.bbox
                    line = lines[int(-y)]
                    line[x] = child.text

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, "ascii")

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(doc, fp)
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

AKTUALIZACJA :

Powyższy kod jest napisany przeciwko starej wersji interfejsu API, zobacz mój komentarz poniżej.

Codeape
źródło
Jakiego rodzaju wtyczek potrzebujesz, żeby to działało? Pobrałem i zainstalowałem pdfminer, ale to nie wystarczy ...
kxk
1
Powyższy kod jest napisany przeciwko starej wersji PDFminera. Interfejs API zmienił się w nowszych wersjach (na przykład pakiet już pdfminernie jest pdflib). Sugeruję zajrzeć do źródła pdf2txt.pyw źródle PDFminer, powyższy kod został zainspirowany starą wersją tego pliku.
codeape
17

slate to projekt, który bardzo ułatwia korzystanie z PDFMiner z biblioteki:

>>> with open('example.pdf') as f:
...    doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'   
Tim McNamara
źródło
1
Podczas wykonywania polecenia „importuj tablicę” pojawia się błąd importu: {Plik "C: \ Python33 \ lib \ site-packages \ slate-0.3-py3.3.egg \ slate_ init_ .py", wiersz 48, w <module> ImportError: nie można zaimportować nazwy PDF} Ale istnieje klasa PDF! Czy wiesz jak to rozwiązać?
juankysmith
Nie, to brzmi bardzo dziwnie. Czy masz zależności?
Tim McNamara,
Zwykle otrzymuję wiadomości o brakujących zależnościach, w tym przypadku otrzymuję klasyczny komunikat „importuj plik łupków” C: \ Python33 \ lib \ site-packages \ slate-0.3-py3.3.egg \ slate_ init_ .py ”, wiersz 48 , w <module> ImportError: nie można zaimportować nazwy PDF ”
juankysmith
Slate 0.3 wymaga pdfminer 20110515, zgodnie z tym problemem GitHub
jabbett,
6
Ten pakiet nie jest już obsługiwany. Powstrzymaj się od korzystania z niego. Nie można go nawet używać w Pythonie 3.5
Sivasubramaniam Arunachalam
9

Musiałem przekonwertować określony plik PDF na zwykły tekst w module Pythona. Użyłem PDFMiner 20110515, po przeczytaniu ich narzędzia pdf2txt.py napisałem ten prosty fragment:

from cStringIO import StringIO
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

def to_txt(pdf_path):
    input_ = file(pdf_path, 'rb')
    output = StringIO()

    manager = PDFResourceManager()
    converter = TextConverter(manager, output, laparams=LAParams())
    process_pdf(manager, converter, input_)

    return output.getvalue() 
Gonz
źródło
1
def to_txt (pdf_path):
Cătălin George Feștilă
gdybym chciał przekonwertować tylko określoną liczbę stron, jak miałbym to zrobić z tym kodem?
psychok7
@ psychok7 Czy próbowałeś użyć narzędzia pdf2txt? Wygląda na to, że obsługuje tę funkcję w bieżącej wersji z flagą -p, implementacja wydaje się łatwa do śledzenia i powinna być łatwa do dostosowania: github.com/euske/pdfminer/blob/master/tools/pdf2txt.py Mam nadzieję, że to pomoże! :)
Gonz
1
thanx @gonz, próbowałem dla wszystkich powyższych, ale twoje rozwiązanie okazuje się być dla mnie idealne ,, wyjście ze spacjami :)
Lazarus
pdf2txt.py jest tutaj zainstalowany:C:\Python27\Scripts\pdfminer\tools\pdf2txt.py
The Red Pea
6

Zmiana przeznaczenia kodu pdf2txt.py, który jest dołączony do pdfminer; możesz stworzyć funkcję, która podąży ścieżką do pliku pdf; opcjonalnie typ wyjściowy (txt | html | xml | tag) i wybiera polecenie takie jak linia poleceń pdf2txt {'-o': '/path/to/outfile.txt' ...}. Domyślnie możesz zadzwonić:

convert_pdf(path)

Zostanie utworzony plik tekstowy, rodzeństwo w systemie plików do oryginalnego pliku pdf.

def convert_pdf(path, outtype='txt', opts={}):
    import sys
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf
    from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter, TagExtractor
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfdevice import PDFDevice
    from pdfminer.cmapdb import CMapDB

    outfile = path[:-3] + outtype
    outdir = '/'.join(path.split('/')[:-1])

    debug = 0
    # input option
    password = ''
    pagenos = set()
    maxpages = 0
    # output option
    codec = 'utf-8'
    pageno = 1
    scale = 1
    showpageno = True
    laparams = LAParams()
    for (k, v) in opts:
        if k == '-d': debug += 1
        elif k == '-p': pagenos.update( int(x)-1 for x in v.split(',') )
        elif k == '-m': maxpages = int(v)
        elif k == '-P': password = v
        elif k == '-o': outfile = v
        elif k == '-n': laparams = None
        elif k == '-A': laparams.all_texts = True
        elif k == '-D': laparams.writing_mode = v
        elif k == '-M': laparams.char_margin = float(v)
        elif k == '-L': laparams.line_margin = float(v)
        elif k == '-W': laparams.word_margin = float(v)
        elif k == '-O': outdir = v
        elif k == '-t': outtype = v
        elif k == '-c': codec = v
        elif k == '-s': scale = float(v)
    #
    CMapDB.debug = debug
    PDFResourceManager.debug = debug
    PDFDocument.debug = debug
    PDFParser.debug = debug
    PDFPageInterpreter.debug = debug
    PDFDevice.debug = debug
    #
    rsrcmgr = PDFResourceManager()
    if not outtype:
        outtype = 'txt'
        if outfile:
            if outfile.endswith('.htm') or outfile.endswith('.html'):
                outtype = 'html'
            elif outfile.endswith('.xml'):
                outtype = 'xml'
            elif outfile.endswith('.tag'):
                outtype = 'tag'
    if outfile:
        outfp = file(outfile, 'w')
    else:
        outfp = sys.stdout
    if outtype == 'txt':
        device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
    elif outtype == 'xml':
        device = XMLConverter(rsrcmgr, outfp, codec=codec, laparams=laparams, outdir=outdir)
    elif outtype == 'html':
        device = HTMLConverter(rsrcmgr, outfp, codec=codec, scale=scale, laparams=laparams, outdir=outdir)
    elif outtype == 'tag':
        device = TagExtractor(rsrcmgr, outfp, codec=codec)
    else:
        return usage()

    fp = file(path, 'rb')
    process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password)
    fp.close()
    device.close()

    outfp.close()
    return
Skylar Saveland
źródło
1

PDFminer dał mi może jedną linię [strona 1 z 7 ...] na każdej stronie pliku pdf, z którym próbowałem.

Najlepsza odpowiedź, jaką do tej pory mam, to pdftoipe lub kod c ++ oparty na Xpdf.

zobacz moje pytanie, jak wygląda wyjście pdftoipe.

sphereinabox
źródło
1

Dodatkowo istnieje PDFTextStream, który jest komercyjną biblioteką Java, z której można także korzystać w Pythonie.

msanders
źródło
1

Użyłem pdftohtmlz -xmlargumentem, przeczytaj wynik za pomocą subprocess.Popen(), który da ci x koordyn, y koordyn, szerokość, wysokość i czcionkę każdego fragmentu tekstu w pdf. Myślę, że tego właśnie używa „evince”, ponieważ wyrzucają te same komunikaty o błędach.

Jeśli potrzebujesz przetworzyć dane kolumnowe, staje się to nieco bardziej skomplikowane, ponieważ musisz wynaleźć algorytm, który pasuje do twojego pliku pdf. Problem polega na tym, że programy tworzące pliki PDF niekoniecznie układają tekst w jakimkolwiek logicznym formacie. Możesz wypróbować proste algorytmy sortowania i to działa czasami, ale mogą być małe „marudery” i „błąki”, fragmenty tekstu, które nie są ułożone w kolejności, w jakiej się spodziewałeś. Musisz więc być kreatywny.

Zajęło mi około 5 godzin, aby znaleźć jeden dla pdf, nad którym pracowałem. Ale teraz działa całkiem dobrze. Powodzenia.

Decora
źródło