如何使用Python从PDF文件中提取特定文本

3

我正在尝试提取这段文本:

 DLA LAND AND MARITIME
ACTIVE DEVICES DIVISION
PO BOX 3990
COLUMBUS OH 43218-3990
USA
 Name: Desmond Forshey Buyer Code:PMCMTA9 Tel: 614-692-6154 Fax:   614-692-6930
 Email: Desmond.Forshey@dla.mil

从这个pdf文件中,我能够使用以下代码提取两个参考之间的一些文本:

import PyPDF2


pdfFileObj = open('SPE7M518T446E.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)

print(pdfReader.numPages)

pageObj1 = pdfReader.getPage(0)
pagecontent = pageObj1.extractText()


def between(value, a, b):
    # Find and validate before-part.
    pos_a = value.find(a)
    if pos_a == -1: return ""
    # Find and validate after part.
    pos_b = value.rfind(b)
    if pos_b == -1: return ""
    # Return middle part.
    adjusted_pos_a = pos_a + len(a)
    if adjusted_pos_a >= pos_b: return ""
    return value[adjusted_pos_a:pos_b]

desired = between(pagecontent,"5. ","8. ")
print(desired)

以上代码输出如下内容:
20
REQUEST FOR QUOTATIONSTHIS RFQ           IS             IS NOT A SMALL BUSINESS SET-ASIDE 4. CERT.FOR NAT. DEF.      UNDER BDSA REG. 2      AND/OR DMS REG. 15. ISSUED BY7. DELIVERY   9. DESTINATION10. PLEASE FURNISH QUOTATIONS TO THE       ISSUING OFFICE IN BLOCK 5 ON OR  BEFORE CLOSE OF BUSINESS (Date)IMPORTANT: This is a request for information,  and quotations furnished are  not offers. If you are unable  to quote, please so indicate on this form and return it to the  address in Block 5.   This  request  does not commit the Government to pay any costs incurred  in  the preparation of the submission of this  quotation or to contract for supplies  or services. Supplies are of domestic origin unless otherwise indicated by quoter. Any representations and/or certifications attached to this Request for Quotations must be completed by  the quoter.11. SCHEDULE  (See Continuation Sheets)     12. DISCOUNT FOR PROMPT PAYMENTd. CALENDAR DAYSNUMBERPERCENTAGE  NOTE:   Additional   provisions   and   representations                    are             are not attached.13. NAME AND ADDRESS OF QUOTERa. NAME OF QUOTER16. SIGNERAUTHORIZED FOR LOCAL REPRODUCTION Previous edition not useableSTANDARD FORM 18       (REV. 6-95)     Prescribed by GSA-FAR (48 CFR) 53.215-1(a)    SPE7M5-18-T-446E1. REQUEST NO.2018 APR 302. DATE ISSUED00739229623. REQUISITION/PURCHASE REQUEST NO.DO-C9RATINGDLA LAND AND MARITIME 
ACTIVE DEVICES DIVISION 
PO BOX 3990 
COLUMBUS OH  43218-3990 
USA 
Name: Desmond Forshey Buyer Code:PMCMTA9 Tel: 614-692-6154 Fax: 614-692-6930 
Email: Desmond.Forshey@dla.mil175 DAYS ADO 6. DELIVER BY  (Date)8. TO: c. CITYd. STATE b. STREET ADDRESS a. NAME OF CONSIGNEEe. ZIP CODE a. 10 CALENDAR DAYS (%)b. 20 CALENDAR DAYS (%) c. 30 CALENDAR DAYS (%)15. Date of Quotationa. NAME (Type or Print)  
AREA CODEc. TITLE (Type or Print)d. CITY  c. COUNTY    b. STREET ADDRESSe. STATE f. ZIP CODESee  Schedule2018 MAY 10NUMBERFOB DESTINATIONOTHER  (See Schedule)CAGE          b. TELEPHONE PAGE     OF      PAGES1 
POC INFORMATION: 

WHEN TECHNICAL DATA IS PROVIDED IT MUST BE OBTAINED AT:https://pcf1x.bsm.dla.mil/cfolders. DISCREPANCIES FOUND IN TECHNICAL DATA SHOULD SUBMIT 
REQUEST TO THE DLA CUSTOMER SERVICE WEBSITE:https://www.pdmd.dla.mil/cs/ 

ALL OTHER QUESTIONS (SOLICITATION REQUIREMENTS, ITEM DESCRIPTION, AWARD CHOICE, ETC.), PLEASE CONTACT THE BUYER SHOWN ABOVE. 

QUESTIONS REGARDING OPERATION OF THE DLA-BSM INTERNET BID BOARD SYSTEM SHOULD BE E-MAILED TO: DibbsBSM@dla.mil 

FOR IMMEDIATE ASSISTANCE, PLEASE REFER TO THE FREQUENTLY ASKED QUESTIONS (FAQS) ON BSM DIBBS AT: 
https://www.dibbs.bsm.dla.mil/Refs/help/DIBBSHelp.htm  OR PHONE 1-855-DLA-0001 (1-855-352-0001). 


MASTER SOLICITATION 

THIS SOLICITATION INCORPORATES THE TERMS AND CONDITIONS SET FORTH IN THE DLA MASTER SOLICITATION FOR AUTOMATED SIMPLIFIED 
ACQUISITIONS REVISION 46 (FEBRURARY 7, 2018) WHICH CAN BE FOUND ON THE WEB AT: 
http://www.dla.mil/Portals/104/Documents/J7Acquisition/Master%20Solicitation%20Rev-46%20February-7-2018.pdf?ver=2018-02-08-063754-70 

This solicitation incorporates technical/quality requirements (‚R™ or ‚I™ number in section B). The full text is in the DLA Technical and Quality Master List of Requirements at: 
http://www.dla.mil/HQ/Acquisition/Offers/eprocurement.aspx The revisionof the TQ Master in effect on the award date controls.14. SIGNATURE OF PERSON AUTHORIZED TO SIGN QUOTATION 1                20
###################
ISSUED BY7. DELIVERY   9. DESTINATION10. PLEASE FURNISH QUOTATIONS TO THE       ISSUING OFFICE IN BLOCK 5 ON OR  BEFORE CLOSE OF BUSINESS (Date)IMPORTANT: This is a request for information,  and quotations furnished are  not offers. If you are unable  to quote, please so indicate on this form and return it to the  address in Block 5.   This  request  does not commit the Government to pay any costs incurred  in  the preparation of the submission of this  quotation or to contract for supplies  or services. Supplies are of domestic origin unless otherwise indicated by quoter. Any representations and/or certifications attached to this Request for Quotations must be completed by  the quoter.11. SCHEDULE  (See Continuation Sheets)     12. DISCOUNT FOR PROMPT PAYMENTd. CALENDAR DAYSNUMBERPERCENTAGE  NOTE:   Additional   provisions   and   representations                    are             are not attached.13. NAME AND ADDRESS OF QUOTERa. NAME OF QUOTER16. SIGNERAUTHORIZED FOR LOCAL REPRODUCTION Previous edition not useableSTANDARD FORM 18       (REV. 6-95)     Prescribed by GSA-FAR (48 CFR) 53.215-1(a)    SPE7M5-18-T-446E1. REQUEST NO.2018 APR 302. DATE ISSUED00739229623. REQUISITION/PURCHASE REQUEST NO.DO-C9RATINGDLA LAND AND MARITIME 
ACTIVE DEVICES DIVISION 
PO BOX 3990 
COLUMBUS OH  43218-3990 
USA 
Name: Desmond Forshey Buyer Code:PMCMTA9 Tel: 614-692-6154 Fax: 614-692-6930 
Email: Desmond.Forshey@dla.mil175 DAYS ADO 6. DELIVER BY  (Date)

如何从PDF文件中提取以下文本?
DLA LAND AND MARITIME
ACTIVE DEVICES DIVISION
PO BOX 3990
COLUMBUS OH 43218-3990
USA
Name: Desmond Forshey Buyer Code:PMCMTA9 Tel: 614-692-6154 Fax:   614-692-6930
Email: Desmond.Forshey@dla.mil

微不足道的编辑建议(因为我无法自己编辑此帖):“How extract extract” 应该改为 “how to extract”。我注意到这一点是因为另一个问题链接到了这个问题,这是一个好迹象,说明其他人可能也会链接到这个问题。 - aschultz
1个回答

2

那个PDF阅读器不太能与返回数据的结构进行交互。但是,可以向其添加一个新函数,使每个元素作为列表中的另一项返回。然后,您至少能够提取两个项目之间的数据。这种方法仍然不是完美的,因为您仍然需要决定可能的终止情况:

import PyPDF2
import itertools


def extractTextList(self):
    text_list = []
    content = self["/Contents"].getObject()
    if not isinstance(content, ContentStream):
        content = ContentStream(content, self.pdf)

    for operands, operator in content.operations:
        if operator == b_("Tj"):
            _text = operands[0]
            if isinstance(_text, TextStringObject) and len(_text.strip()):
                text_list.append(_text.strip())
        elif operator == b_("T*"):
            pass
        elif operator == b_("'"):
            pass
            _text = operands[0]
            if isinstance(_text, TextStringObject) and len(operands[0]):
                text_list.append(operands[0])
        elif operator == b_('"'):
            _text = operands[2]
            if isinstance(_text, TextStringObject) and len(_text):
                text_list.append(_text)
        elif operator == b_("TJ"):
            for i in operands[0]:
                if isinstance(i, TextStringObject) and len(i):
                    text_list.append(i)
    return text_list


from PyPDF2.pdf import PageObject, u_, ContentStream, b_, TextStringObject
PageObject.extractTextList = extractTextList


def between(text_elements, drop_while, take_while):    
    return list(itertools.takewhile(take_while, itertools.dropwhile(drop_while, text_elements)))[1:]    


pdfFileObj = open('SPE7M518T446E.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)

page0 = pdfReader.getPage(0)
text_elements = page0.extractTextList()

lines = between(text_elements, lambda x: x != 'RATING', lambda x: 'DAYS' not in x)
print('\n'.join(lines))

这将为您提供所需的行,然后将它们组合成以下单个输出:
DLA LAND AND MARITIME
ACTIVE DEVICES DIVISION
PO BOX 3990
COLUMBUS OH  43218-3990
USA
Name: Desmond Forshey Buyer Code:PMCMTA9 Tel: 614-692-6154 Fax: 614-692-6930
Email: Desmond.Forshey@dla.mil

作为新功能extractTextList()返回在页面中找到的文本元素列表,我使用itertools.dropwhile()itertools.takewhile()来处理返回的列表。 between()函数分两个阶段工作,首先它逐个读取字符串列表并将其丢弃,直到它匹配第一个测试(即查找RATING)。然后开始向takewhile()函数返回元素。这会一直获取元素,直到在其中一个元素中发现单词DAYS。使用list()创建过滤列表。然后我删除第一个元素(因为它是单词RATING)。
实际上,这是对列表进行切片的迭代方式。
注意:lambda只是另一种定义函数的方式。在这种情况下,它接受一个名为x的文本元素,并在其值等于特定值时返回True,或者对于takewhile,如果单词DAYS在其中某个地方,则返回True。两个itertool函数为列表中的每个元素调用这些lambda函数。

谢谢,您能尽可能详细地解释一下代码吗?因为我需要从PDF中检索其他数据,希望能使用这个答案中的相同逻辑从PDF的其他位置提取。 - jone2
1
我已经改进了解释,并创建了一个 between() 函数,您可能可以在其他情况下更多地使用它。我建议您打印 text_elements,这样它的工作原理就更清楚了。 - Martin Evans
非常感谢,这真是救命之恩。 - jone2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接