首页 文章

使用不正确的结构OCR从PDF中提取数据

提问于
浏览
0

我有定期流入的发票pdfs . 我从这些pdf中提取数据以进行各种操作和存储 .

这是一个示例部分:
enter image description here

第一步是使用Adobe的OCR . 然后,我使用tika来解析pdf . 在Python中:

from tika import parser
parsedPDF = parser.from_file("the_file.pdf")

这是预期的输出:

...
001 6 0 6 EA FSC450-WBKR FUTSAL, ADULT, WHT/BLK/RED BULK \n\n
002 6 0 6 EA SS50-P SOCCER PURPLE/BLUE/WHITE BULK \n\n
...

行由换行符分隔,您在pdf上看到的行被解析为完整行(见下文) .

这是实际输出:

001 6 0 6 \n\n
002 6 0 6 \n\n
003 13 0 13 \n\n
004 3 0 3 \n\n
EA FSC450-WBKR FUTSAL, ADULT, WHT/BLK/RED BULK \n\n
EA SS50-P SOCCER PURPLE/BLUE/WHITE BULK \n\n
...

OCR创建了一个结构,您在pdf上看到的行分为两个部分[* note] . 分裂发生在"Shipped"和"Unit" Headers 之间 .
enter image description here

对于项目002,如果我从“#” Headers 拖动到“打包” Headers ,它首先选择第一部分的数据,然后跳到第二部分的顶部 .

这个问题有一个很好的解决方案吗?有没有办法为OCR定义结构(例如,它将一行读作一行?)

[* note]:实际上文本是垂直包装的(与通常看到的水平文本换行相比) .

1 回答

  • 1

    而不是尝试重铸数据,而只是使用你拥有的东西 . 你得到两组线,第一组包含数据行的左半部分,第二组包含右半部分 . itertools.groupby 非常适合按某些分组标准拆分行 . 在这种情况下,您可以看出左半部分都以数字开头,而右半部分则没有 .

    一旦你将它们分成两个大小相等的组,使用Python的内置方法 zip 将它们拼接在一起 . 然后一连串的 split() 可以帮助您解析每一行的内容 - 请参阅下面代码中的注释:

    from itertools import groupby
    
    lines = """
    001 6 0 6 
    
    
    002 6 0 6 
    
    
    003 13 0 13 
    
    
    004 3 0 3 
    
    
    EA FSC450-WBKR FUTSAL, ADULT, WHT/BLK/RED BULK 
    
    
    EA SS50-P SOCCER PURPLE/BLUE/WHITE BULK 
    
    
    EA SS30-G SOCCER BALL GREEN/WHITE #3 BULK 
    
    
    EA VQ2000-RGW COMPOSITE VB ROYAL/GOLD/WHITE BULK 
    
    
    """.splitlines()
    
    # filter out empty lines
    lines = filter(None, lines)
    
    # use groupby to walk the list, and get the lines that start with 
    # numbers vs those that don't - from your description, there should be
    # two groups
    groups = []
    for _, grouplines in groupby(lines, key=lambda ll : ll[0].isdigit()):
        groups.append(list(grouplines))
    
    # validate the input - should be two groups of line, each the same length
    assert len(groups) == 2
    assert len(groups[0]) == len(groups[1])
    
    # use zip to walk the two groups together, and create list of consolidated data
    consolidated = [left + right for left,right in zip(groups[0], groups[1])]
    
    # now break these strings up into their various pieces, using a succession of split()s
    parsed_lines = []
    for cons_line in consolidated:
        left_items = cons_line.split(None, 4)
        right_items = left_items.pop(-1).rsplit(None,1)
        right_items, qty_type = right_items
        um, desc = right_items.split(None, 1)
        parsed_lines.append(list(map(int,left_items) + [um, desc, qty_type]))
    
    # dump out the parsed lines
    for data in parsed_lines:
        print(data)
    

    得到:

    [1, 6, 0, 6, 'EA', 'FSC450-WBKR FUTSAL, ADULT, WHT/BLK/RED', 'BULK']
    [2, 6, 0, 6, 'EA', 'SS50-P SOCCER PURPLE/BLUE/WHITE', 'BULK']
    [3, 13, 0, 13, 'EA', 'SS30-G SOCCER BALL GREEN/WHITE #3', 'BULK']
    [4, 3, 0, 3, 'EA', 'VQ2000-RGW COMPOSITE VB ROYAL/GOLD/WHITE', 'BULK']
    

相关问题