python - पीडीएफ को पाठ में परिवर्तित करने के लिए पायथन मॉड्यूल




pdf text-extraction (9)

PDFMiner आज़माएं। यह पीडीएफ फाइलों से एचटीएमएल, एसजीएमएल या "टैग किए गए पीडीएफ" प्रारूप के रूप में पाठ निकाल सकता है।

http://www.unixuser.org/~euske/python/pdfminer/index.html

टैग की गईं पीडीएफ प्रारूप सबसे साफ प्रतीत होता है, और एक्सएमएल टैग को अलग करना केवल नंगे पाठ को छोड़ देता है।

एक पायथन 3 संस्करण के तहत उपलब्ध है:

पीडीएफ फाइलों को पाठ में बदलने के लिए सबसे अच्छे पायथन मॉड्यूल कौन से हैं?


Pdfmint के साथ आता है जो pdf2txt.py कोड repurposing; आप एक ऐसा कार्य कर सकते हैं जो पीडीएफ का मार्ग लेगा; वैकल्पिक रूप से, एक आउटटाइप (txt | html | xml | टैग) और कमांडलाइन pdf2txt {'-o': '/path/to/outfile.txt' ...} की तरह ऑप्ट आउट करता है। डिफ़ॉल्ट रूप से, आप कॉल कर सकते हैं:

convert_pdf(path)

एक पाठ फ़ाइल बनाई जाएगी, फाइल सिस्टम पर मूल पीडीएफ पर एक भाई।

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

आप लाइब्रेरी के रूप में पीडीएफमिनेर का आसानी से उपयोग कर सकते हैं। आपके पास पीडीएफ के सामग्री मॉडल तक पहुंच है, और अपना खुद का टेक्स्ट निष्कर्षण बना सकता है। मैंने पीडीएफ सामग्री को अर्ध-कोलन से अलग पाठ में परिवर्तित करने के लिए नीचे दिए गए कोड का उपयोग करके किया।

फ़ंक्शन बस टेक्स्ट वाईटम सामग्री ऑब्जेक्ट्स को उनके वाई और एक्स निर्देशांक के अनुसार टाइप करता है, और एक ही वाई समन्वय वाले आइटम को एक टेक्स्ट लाइन के रूप में आउटपुट करता है, ऑब्जेक्ट को उसी पंक्ति पर ';' से अलग करता है वर्ण।

इस दृष्टिकोण का उपयोग करके, मैं एक पीडीएफ से पाठ निकालने में सक्षम था कि कोई अन्य उपकरण आगे की पार्सिंग के लिए उपयुक्त सामग्री निकालने में सक्षम नहीं था। मैंने कोशिश की अन्य टूल्स में पीडीएफटीओटीएक्स, ps2ascii और ऑनलाइन टूल pdftextonline.com शामिल हैं।

पीडीएफमिनेर पीडीएफ-स्क्रैपिंग के लिए एक अमूल्य उपकरण है।


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()

अद्यतन :

ऊपर दिया गया कोड एपीआई के पुराने संस्करण के खिलाफ लिखा गया है, नीचे मेरी टिप्पणी देखें।


इसके अतिरिक्त PDFTextStream जो एक वाणिज्यिक जावा लाइब्रेरी है जिसे पायथन से भी इस्तेमाल किया जा सकता है।


पीडीएफमिनर ने मुझे एक पीडीएफ फ़ाइल के प्रत्येक पृष्ठ पर शायद एक पंक्ति [7 का पृष्ठ 1 ...] दिया था।

अब तक का सबसे अच्छा जवाब पीडीएफटोइप है, या सी ++ कोड यह एक्सपीडीएफ पर आधारित है।

पीडीएफटोइप के आउटपुट की तरह दिखने के लिए मेरा प्रश्न देखें।


मुझे एक विशिष्ट पीडीएफ को एक पायथन मॉड्यूल के भीतर सादे पाठ में बदलने की जरूरत थी। मैंने http://www.unixuser.org/~euske/python/pdfminer/index.html 2txt.py टूल के माध्यम से पढ़ने के बाद http://www.unixuser.org/~euske/python/pdfminer/index.html 20110515 का इस्तेमाल किया, मैंने यह सरल स्निपेट लिखा था:

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() 

Pdftotext एक ओपन सोर्स प्रोग्राम (एक्सपीडीएफ का हिस्सा) जिसे आप पाइथन से कॉल कर सकते हैं (जो आपने नहीं पूछा लेकिन उपयोगी हो सकता है)। मैंने इसे बिना किसी समस्या के इस्तेमाल किया है। मुझे लगता है कि Google इसे Google डेस्कटॉप में उपयोग करता है।


pyPDF ठीक काम करता है (यह मानते हुए कि आप अच्छी तरह से गठित पीडीएफ के साथ काम कर रहे हैं)। यदि आप चाहते हैं कि पाठ (रिक्त स्थान के साथ) है, तो आप बस ऐसा कर सकते हैं:

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

आप आसानी से मेटाडेटा, छवि डेटा और अन्य तक पहुंच प्राप्त कर सकते हैं।

निकालने में एक टिप्पणी टेक्स्ट कोड नोट्स:

सभी टेक्स्ट ड्राइंग आदेशों को ढूंढें, क्रम में वे सामग्री स्ट्रीम में प्रदान किए गए क्रम में, और टेक्स्ट निकालें। यह कुछ पीडीएफ फाइलों के लिए अच्छी तरह से काम करता है, लेकिन इस्तेमाल किए गए जेनरेटर के आधार पर दूसरों के लिए खराब है। यह भविष्य में परिष्कृत किया जाएगा। इस फ़ंक्शन से बाहर आने वाले पाठ के क्रम पर भरोसा न करें, क्योंकि यह कार्य अधिक परिष्कृत होने पर बदल जाएगा।

चाहे यह एक समस्या है या नहीं, इस बात पर निर्भर करता है कि आप पाठ के साथ क्या कर रहे हैं (उदाहरण के लिए यदि ऑर्डर कोई फर्क नहीं पड़ता है, तो यह ठीक है, या यदि जेनरेटर ऑर्डर में स्ट्रीम में टेक्स्ट जोड़ता है तो यह प्रदर्शित होगा, यह ठीक है) । मेरे पास दैनिक उपयोग में पीईपीडीएफ निष्कर्षण कोड है, बिना किसी समस्या के।


codeape पोस्ट किए जाने के बाद http://www.unixuser.org/~euske/python/pdfminer/index.html पैकेज बदल गया है।

संपादित करें (दोबारा):

पीडीएफमिनर को संस्करण 20100213 में फिर से अपडेट किया गया है

आप निम्न संस्करण के साथ स्थापित संस्करण की जांच कर सकते हैं:

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

यहां अपडेट किया गया संस्करण है (मैंने जो बदल दिया / जोड़ा है उस पर टिप्पणियों के साथ):

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()

संपादित करें (फिर भी):

यहां pypi , 20100619p1 में नवीनतम संस्करण के लिए एक अद्यतन है। संक्षेप में मैंने LTTextItem को LTTextItem साथ बदल दिया और LTChar LTTextItem को LTChar का एक उदाहरण पास कर दिया।

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()

संपादित करें (एक और बार):

संस्करण 20110515 लिए अपडेट किया गया (ओउफोक पेंटेनोनो के लिए धन्यवाद!):

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()




pdf-scraping