Get annotation text from its position (PDFMiner)

Viewed 643

I want to extract the text of annotations (such as highlighted text of hyperlinks) from its position. For this I could scrape the positions and urls by using PDFminer as in the below code. Is that possible passing this position to a layout object and get out the text?

Here are the code blocks I used for this purpose.

First part includes a function, named parse_annotation, to parse annotations from each page.

def parse_annotations(page):
    positions = []
    urls = []
    for annot in pdftypes.resolve1(page.annots):
        if isinstance(annot, pdftypes.PDFObjRef):
            annotationDict = annot.resolve()
            # Skip over any annotations that are not links
            if str(annotationDict["Subtype"]) != "/'Link'":
                continue
            destID = 0
            position = annotationDict["Rect"]
            uriDict = "None"
            if any(k in annotationDict for k in {"Dest", "D"}):                
                destID = (annotationDict["Dest"][0]).objid                
                url = "Cross reference"
            elif "A" in annotationDict:
                # Key A contains PDFObjRef, then resolve it again
                if isinstance(annotationDict["A"], pdftypes.PDFObjRef):
                    uriDict = pdftypes.resolve1(annotationDict["A"])
                    if any(k in uriDict for k in {"Dest", "D"}): 
                        destID = (uriDict["D"][0]).objid
                else:
                    uriDict = annotationDict["A"]
                # Check if the key exists within resolved uriDict
                if str(uriDict["S"]) == "/'GoTo'":
                    url = "Cross reference"
                elif str(uriDict["S"]) == "/'URI'":
                    url = str(uriDict["URI"])
                    url = url.lstrip("b")
                    url = url.replace("'", "")
                else:
                    # Skip if key S in uriDict does not contain value URI, GoTo
                    continue
            else:
                sys.stderr.write("Warning: unknown key in annotationDict : ", annotationDict)
            #print(annot, '\n', annotationDict, '\n', destID, '\n', position, '\n', uriDict, '\n', url, '\n')
            print(position, '\n', url, '\n')
            positions.append(position)
            urls.append(url)
        else:
            sys.stderr.write("Warning: unknown annotation: %s\n" % annot)
    return positions, urls

Example PDF file can be found from the following link below.

https://www2.ed.gov/about/offices/list/ocr/docs/20200512-qa-psi-covid-19.pdf

Now, by using PDFMiner, created a document object and start looping over the pages found in PDF.

manager = PDFResourceManager()
output = StringIO()
codec = 'utf-8'
laparams = LAParams()
converter = TextConverter(manager, output, codec=codec, laparams=laparams)
device = PDFPageAggregator(manager, laparams=laparams)
interpreter = PDFPageInterpreter(manager, device)
page_interpreter = PDFPageInterpreter(manager, converter)
filename = '20200512-qa-psi-covid-19.pdf'
fp = open(filename, 'rb')
parser = PDFParser(fp)
document = PDFDocument(parser)
if not document.is_extractable:
    raise PDFTextExtractionNotAllowed
page_no = 0
for pageNumber, page in enumerate(PDFPage.create_pages(document)):
    print("\n================ PageNumber ", pageNumber+1, "===================\n")
    if pageNumber == page_no:
        page_interpreter.process_page(page)
        raw_text = output.getvalue()
        output.truncate(0)
        output.seek(0)
    interpreter.process_page(page)
    layout = device.get_result()
    if page.annots:
        positions, urls = parse_annotations(page)
        for obj in layout:
            print('Object name and position %s \t %s \n' % (obj.__class__.__name__ , obj.bbox))
    page_no += 1
fp.close()
converter.close()
output.close()
device.close()

Thanks in advance, A.

0 Answers
Related