8

PDFの各ページを文字列として抽出しようとしています。

import pyPdf

pages = []
pdf = pyPdf.PdfFileReader(file('g-reg-101.pdf', 'rb'))
for i in range(0, pdf.getNumPages()):
    this_page = pdf.getPage(i).extractText() + "\n"
    this_page = " ".join(this_page.replace(u"\xa0", " ").strip().split())
    pages.append(this_page.encode("ascii", "xmlcharrefreplace"))
for page in pages:
    print '*' * 80
    print page

しかし、このスクリプトは改行文字を無視し、次のような厄介な文字列を残しますinformation concerning an individual which, because of name, identifyingnumber, mark or description(つまり、これはでidentifying numberはなく、と読む必要がありますidentifyingumber)。

これが私が解析しようとしているPDFのタイプの例です。

4

3 に答える 3

11

PDFエンコーディングについてはよくわかりませんが、を変更することで特定の問題を解決できると思いますpdf.py。このPageObject.extractText方法では、何が起こっているかがわかります。

def extractText(self):
    [...]
    for operands,operator in content.operations:
        if operator == "Tj":
            _text = operands[0]
            if isinstance(_text, TextStringObject):
                text += _text
        elif operator == "T*":
            text += "\n"
        elif operator == "'":
            text += "\n"
            _text = operands[0]
            if isinstance(_text, TextStringObject):
                text += operands[0]
        elif operator == '"':
            _text = operands[2]
            if isinstance(_text, TextStringObject):
                text += "\n"
                text += _text
        elif operator == "TJ":
            for i in operands[0]:
                if isinstance(i, TextStringObject):
                    text += i

演算子がTjor TJ(PDFの例ではTj)の場合、テキストは単に追加され、改行は追加されません。これで、少なくともPDF参照を正しく読んでいる場合は、必ずしも改行を追加する必要はありません。これはTj/TJ単一および複数のshow-string演算子であり、何らかのセパレーターの存在は必須ではありません。

とにかく、このコードを次のように変更すると

def extractText(self, Tj_sep="", TJ_sep=""):

[...]

        if operator == "Tj":
            _text = operands[0]
            if isinstance(_text, TextStringObject):
                text += Tj_sep
                text += _text

[...]

        elif operator == "TJ":
            for i in operands[0]:
                if isinstance(i, TextStringObject):
                    text += TJ_sep
                    text += i

その場合、デフォルトの動作は同じである必要があります。

In [1]: pdf.getPage(1).extractText()[1120:1250]
Out[1]: u'ing an individual which, because of name, identifyingnumber, mark or description can be readily associated with a particular indiv'

ただし、次の場合に変更できます。

In [2]: pdf.getPage(1).extractText(Tj_sep=" ")[1120:1250]
Out[2]: u'ta" means any information concerning an individual which, because of name, identifying number, mark or description can be readily '

また

In [3]: pdf.getPage(1).extractText(Tj_sep="\n")[1120:1250]
Out[3]: u'ta" means any information concerning an individual which, because of name, identifying\nnumber, mark or description can be readily '

あるいは、オペランド自体をインプレースで変更することでセパレーターを自分で追加することもできますが、それは他の何かを壊す可能性があります(get_original_bytes私を緊張させるような方法)。

最後に、必要がなければ自分自身を編集するpdf.py必要はありません。このメソッドを関数に引き出すだけです。

于 2012-06-19T18:55:26.653 に答える
0

pyPdfは、この種のテキスト抽出用に実際に作成されたものではありません。pdfminerを試してください(または、別のプロセスを作成してもかまわない場合は、pdftotextなどを使用してください)

于 2012-06-26T14:27:18.293 に答える
0

DSMの答えを拡張します。以下は、いくつかのクラスを拡張することによってそれを実装する方法です

import PyPDF2
import pandas as pd
from PyPDF2.generic import TextStringObject
from PyPDF2.pdf import ContentStream, IndirectObject, NameObject
from PyPDF2.utils import b_, u_

class PageObject2(PyPDF2.pdf.PageObject):
    def extractText(self, Tj_sep="", TJ_sep=""):
        """
        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.
        """
        text = u_("")
        content = self["/Contents"].getObject()
        if not isinstance(content, ContentStream):
            content = ContentStream(content, self.pdf)
        # Note: we check all strings are TextStringObjects.  ByteStringObjects
        # are strings where the byte->string encoding was unknown, so adding
        # them to the text here would be gibberish.
        for operands, operator in content.operations:
            if operator == b_("Tj"):
                _text = operands[0]
                if isinstance(_text, TextStringObject):
                    text += Tj_sep
                    text += _text
            elif operator == b_("T*"):
                text += "\n"
            elif operator == b_("'"):
                text += "\n"
                _text = operands[0]
                if isinstance(_text, TextStringObject):
                    text += operands[0]
            elif operator == b_('"'):
                _text = operands[2]
                if isinstance(_text, TextStringObject):
                    text += "\n"
                    text += _text
            elif operator == b_("TJ"):
                for i in operands[0]:
                    if isinstance(i, TextStringObject):
                        text += TJ_sep
                        text += i
                text += "\n"
        return text


class PdfFileReader2(PyPDF2.PdfFileReader):
    def _flatten(self, pages=None, inherit=None, indirectRef=None):
        inheritablePageAttributes = (
            NameObject("/Resources"), NameObject(
                "/MediaBox"),
            NameObject("/CropBox"), NameObject("/Rotate")
        )
        if inherit == None:
            inherit = dict()
        if pages == None:
            self.flattenedPages = []
            catalog = self.trailer["/Root"].getObject()
            pages = catalog["/Pages"].getObject()

        t = "/Pages"
        if "/Type" in pages:
            t = pages["/Type"]

        if t == "/Pages":
            for attr in inheritablePageAttributes:
                if attr in pages:
                    inherit[attr] = pages[attr]
            for page in pages["/Kids"]:
                addt = {}
                if isinstance(page, IndirectObject):
                    addt["indirectRef"] = page
                self._flatten(page.getObject(), inherit, **addt)
        elif t == "/Page":
            for attr, value in list(inherit.items()):
                # if the page has it's own value, it does not inherit the
                # parent's value:
                if attr not in pages:
                    pages[attr] = value
            pageObj = PageObject2(self, indirectRef)
            pageObj.update(pages)
            self.flattenedPages.append(pageObj)


# creating an object
file = open('travelers.pdf', 'rb')

# creating a pdf reader object
fileReader = PdfFileReader2(file)

# print the number of pages in pdf file
no_of_pages = fileReader.numPages

pageObj = fileReader.getPage(page_no)
page = pageObj.extractText(Tj_sep='\n')
于 2021-07-21T07:46:16.720 に答える