การแยกข้อความจากไฟล์ PDF โดยใช้ PDFMiner ใน python?


89

ฉันกำลังมองหาเอกสารหรือตัวอย่างเกี่ยวกับการแยกข้อความจากไฟล์ PDF โดยใช้ PDFMiner กับ Python

ดูเหมือนว่า PDFMiner จะอัปเดต API และตัวอย่างที่เกี่ยวข้องทั้งหมดที่ฉันพบมีโค้ดที่ล้าสมัย (คลาสและวิธีการมีการเปลี่ยนแปลง) ไลบรารีที่ฉันพบว่าทำให้การแยกข้อความจากไฟล์ PDF ง่ายขึ้นคือการใช้ไวยากรณ์ PDFMiner แบบเก่าดังนั้นฉันไม่แน่ใจว่าจะทำอย่างไร

ตามที่เป็นอยู่ฉันแค่ดูซอร์สโค้ดเพื่อดูว่าฉันสามารถหาได้หรือไม่


1
โปรดตรวจสอบstackoverflow.com/help/how-to-askและstackoverflow.com/help/mcveและอัปเดตคำตอบของคุณเพื่อให้อยู่ในรูปแบบที่ดีขึ้นและสอดคล้องกับหลักเกณฑ์
Parker

คุณใช้ Python แบบใด 2.7.x หรือ 3.xx ควรสังเกตว่าผู้เขียนมีรายละเอียดอย่างชัดเจนซึ่งใช้PDFminerไม่ได้กับ Python 3.xx นั่นอาจเป็นสาเหตุที่คุณได้รับimportข้อผิดพลาด คุณควรใช้ในpdfminer3kกรณีนี้เนื่องจากเป็นการนำเข้า Python 3 แบบยืนของไลบรารีดังกล่าว
NullDev

@ Nanashi ขออภัยฉันลืมเพิ่มเวอร์ชัน Python ของฉัน มันคือ 2.7 นั่นไม่ใช่ปัญหา ฉันได้ตรวจสอบซอร์สโค้ดแล้วและดูเหมือนว่าพวกเขาปรับโครงสร้างบางอย่างซึ่งเป็นสาเหตุที่การนำเข้าพัง ฉันไม่พบเอกสารใด ๆ สำหรับ PDFMiner หรือฉันจะแก้ไขสิ่งนั้น :(
DuckPuncher

ฉันเพิ่งติดตั้งPDFminerออกจาก GitHub และนำเข้าได้ดี กรุณาโพสต์รหัสของคุณและโพสต์การตรวจสอบย้อนกลับข้อผิดพลาดทั้งหมดด้วย
NullDev

@ Nanashi เช่นเดียวกับที่ฉันพูดในคำถามเดิมของฉันไลบรารีที่ใช้ PDFMiner แตกก่อนที่จะเสร็จสิ้นการนำเข้าพร้อมกับตัวอย่างใด ๆ ที่ฉันสามารถหาได้ นี่ไม่ใช่ปัญหา PDFMiner นี่คือฉันกำลังมองหาเอกสารหรือตัวอย่างวิธีใช้ PDFMiner ทุกสิ่งที่ฉันหาได้ใช้ไวยากรณ์เก่าสำหรับ PDFMiner ฉันดำเนินการแก้ไขคำถามเพื่อความชัดเจน ฉันคิดว่าฉันทำให้มันสับสนมากกว่าที่จะเป็น ขอโทษสำหรับเรื่องนั้น.
DuckPuncher

คำตอบ:


184

นี่คือตัวอย่างการทำงานของการแยกข้อความจากไฟล์ PDF โดยใช้ PDFMiner เวอร์ชันปัจจุบัน (กันยายน 2016)

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 มีการเปลี่ยนแปลงเมื่อเร็ว ๆ นี้ดังนั้นสิ่งนี้ควรใช้สำหรับการแยกข้อความจากไฟล์ PDF

แก้ไข : ยังคงใช้งานได้ ณ วันที่ 7 มิถุนายน 2018 ตรวจสอบแล้วใน Python เวอร์ชัน 3.x

แก้ไข: โซลูชันนี้ใช้ได้กับ Python 3.7 เมื่อวันที่ 3 ตุลาคม 2019 ฉันใช้ไลบรารี Python pdfminer.sixซึ่งเผยแพร่เมื่อเดือนพฤศจิกายน 2018


2
ใช้งานได้ดี แต่ฉันจะจัดการกับช่องว่างในชื่อตัวอย่างได้อย่างไร สมมติว่าฉันมี pdf ที่มี 4 คอลัมน์ที่ฉันมีชื่อและนามสกุลในหนึ่ง col ตอนนี้มันถูกแยกวิเคราะห์ด้วยชื่อแรกในแถวเดียวและนามสกุลในหนึ่งแถวนี่คือตัวอย่างdocdro.id/rRyef3x
Deusdeorum

2
ขณะนี้ได้รับข้อผิดพลาดในการนำเข้าด้วยรหัสนี้: ImportError: No module named 'pdfminer.pdfpage'
Jeffrey Swan

1
ขอบคุณที่ใช้งานได้กับ python v2.7.12 และบน ubuntu 16.04 แม้ว่าจะดีกว่าถ้าโหลดเอกสาร pdf ด้วยการเข้ารหัส utf-8 เนื่องจาก pdf ตัวอย่างของฉันมีปัญหาในการเข้ารหัสดังนั้นให้ลองใช้สิ่งนี้หลังจากเข้ารหัสด้วย utf-8 และแก้ไขได้ ปัญหา ... import sys reload(sys) sys.setdefaultencoding('utf-8')
sib10

2
@DuckPuncher ตอนนี้ยังทำงานอยู่ไหม? ฉันต้องเปลี่ยนเป็นfile(path, 'rb')`` open (path, 'rb') เพื่อให้ฉันทำงาน
ปั้น

2
ยังคงใช้งานได้สำหรับผู้ใช้ Python3.7 ติดตั้ง pdfminer.six == 20181108 package ทางออกที่ดีที่สุดสำหรับกรณีของฉันและฉันเปรียบเทียบวิธีแก้ปัญหามากมาย
aze45sq6d

30

คำตอบที่ยอดเยี่ยมจาก DuckPuncher สำหรับ Python3 ตรวจสอบให้แน่ใจว่าคุณติดตั้ง pdfminer2 และทำ:

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
มันใช้ไม่ได้สำหรับฉัน: ModuleNotFoundError: ไม่มีโมดูลชื่อ 'pdfminer.pdfpage' ฉันใช้ python 3.6
Atti

@Atti ในกรณีตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง pdfminer2 แล้วเนื่องจากมี pdfminer แพ็คเกจอื่น (ฉันเกลียดสิ่งนี้) ใช้งานได้กับ pdfminer2 == 20151206 เวอร์ชันเมื่อทำการหยุด pip3
juan Isaza

5
ขอบคุณฉันทำงานได้ในที่สุดฉันติดตั้ง pdfminer.six จาก conda forge
Atti

8
สำหรับ Python 3 pdfminer.six เป็นแพ็คเกจที่แนะนำ - github.com/pdfminer/pdfminer.six
Mike Driscoll

ปัจจุบันยังอยู่ไหม. ฉันได้รับImportError:ข้อความเดียวกัน

14

สิ่งนี้ใช้ได้ในเดือนพฤษภาคม 2020 โดยใช้ PDFminer six ใน Python3

การติดตั้งแพ็คเกจ

$ pip install pdfminer.six

การนำเข้าแพคเกจ

from pdfminer.high_level import extract_text

ใช้ PDF ที่บันทึกไว้ในดิสก์

text = extract_text('report.pdf')

หรืออีกทางหนึ่ง:

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

ใช้ PDF อยู่แล้วในหน่วยความจำ

หาก PDF อยู่ในหน่วยความจำแล้วตัวอย่างเช่นหากดึงมาจากเว็บด้วยไลบรารีคำขอก็สามารถแปลงเป็นสตรีมโดยใช้ioไลบรารี:

import io

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

ประสิทธิภาพและความน่าเชื่อถือเมื่อเทียบกับ PyPDF2

PDFminer.six ทำงานได้อย่างน่าเชื่อถือมากกว่า PyPDF2 (ซึ่งล้มเหลวกับ PDF บางประเภท) โดยเฉพาะ PDF เวอร์ชัน 1.7

อย่างไรก็ตามการแยกข้อความด้วย PDFminer.six นั้นช้ากว่า PyPDF2 อย่างมีนัยสำคัญโดยมีค่าเท่ากับ 6

ฉันตั้งเวลาการแยกข้อความด้วยtimeitMBP ขนาด 15 "(2018) กำหนดเวลาเฉพาะฟังก์ชันการแยก (ไม่มีการเปิดไฟล์เป็นต้น) ด้วย PDF 10 หน้าและได้ผลลัพธ์ดังต่อไปนี้:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six ยังมีขนาดใหญ่โดยต้องใช้ pycryptodome ซึ่งต้องการ GCC และสิ่งอื่น ๆ ที่ติดตั้งโดยผลักดันอิมเมจนักเทียบท่าติดตั้งขั้นต่ำบน Alpine Linux จาก 80 MB เป็น 350 MB PyPDF2 ไม่มีผลกระทบในการจัดเก็บที่เห็นได้ชัดเจน


วิธีนี้อาจพังตั้งแต่การอัปเดตครั้งล่าสุด ขณะนี้ได้รับข้อผิดพลาดImportError: cannot import name 'open_filename' from 'pdfminer.utils'เมื่อฉันเรียกใช้from pdfminer.high_level import extract_text
อ่านเพิ่มเติม

1
อัปเดต: ฉันแก้ไขสิ่งนี้โดยการสร้าง venv ใหม่และติดตั้ง pdfminer.six ใหม่ ฉันเดาว่าหนึ่งในแพ็คเกจ pdf อื่น ๆ ที่ฉันลองก่อนหน้านี้กำลังรบกวนอยู่
อ่านเพิ่มเติม

11

การเปิดเผยข้อมูลทั้งหมดฉันเป็นหนึ่งในผู้ดูแล pdfminer.six

ปัจจุบันมี API หลายตัวในการแยกข้อความจาก PDF ขึ้นอยู่กับความต้องการของคุณ เบื้องหลัง api ทั้งหมดนี้ใช้ตรรกะเดียวกันในการแยกวิเคราะห์และวิเคราะห์เค้าโครง

(ตัวอย่างทั้งหมดถือว่าไฟล์ PDF ของคุณเรียกว่าexample.pdf )

บรรทัดคำสั่ง

หากคุณต้องการแยกข้อความเพียงครั้งเดียวคุณสามารถใช้เครื่องมือ commandline pdf2txt.py:

$ pdf2txt.py example.pdf

API ระดับสูง

หากคุณต้องการแยกข้อความด้วย Python คุณสามารถใช้ api ระดับสูงได้ วิธีนี้เป็นวิธีแก้ปัญหาหากคุณต้องการแยกข้อความโดยใช้โปรแกรมจาก PDF จำนวนมาก

from pdfminer.high_level import extract_text

text = extract_text('example.pdf')

api ที่ประกอบได้

นอกจากนี้ยังมี api แบบผสมที่ให้ความยืดหยุ่นอย่างมากในการจัดการกับวัตถุที่เป็นผลลัพธ์ ตัวอย่างเช่นคุณสามารถใช้อัลกอริทึมการจัดวางของคุณเองโดยใช้สิ่งนั้น วิธีนี้แนะนำในคำตอบอื่น ๆ แต่ฉันจะแนะนำวิธีนี้ก็ต่อเมื่อคุณต้องการปรับแต่งวิธีการทำงานของ pdfminer.six

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

รหัสนี้ได้รับการทดสอบด้วย pdfminer สำหรับ python 3 (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

ฉันมีไฟล์ PDF ที่สามารถแปลงโดยใช้เครื่องมือ Nitro Pro เมื่อฉันพยายามแปลง PDF เดียวกันโดยใช้รหัสที่โพสต์ที่นี่ฉันได้รับผลลัพธ์ซึ่งแสดงให้เห็นว่ามีข้อผิดพลาดในการอนุญาต นี่คือผลลัพธ์: ('จาก SAGE Social Science Collections สงวนลิขสิทธิ์ \ 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

คุณหมายถึงอะไรสตรีมไฟล์?
Vincent

@ Vincent with open (file, 'rb') as stream: [... ]
Rodrigo Formighieri

คุณจัดการเพื่อให้ได้ไฟล์นี้เป็นตาราง / หมีแพนด้าหรือไม่? groupe-psa.com/th/publication/monthly-world-sales-march-2020
Nono London
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.