2016-07-05 61 views
0

我有一個經常性的發票pdf流入。 我從這些pdf中提取數據以進行各種操作和存儲。使用錯誤的結構OCR從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看到該行分爲兩個部分[*注]的結構。拆分發生在「已發貨」和「單元」標題之間。 enter image description here

對於項目002,如果從「#」標題拖動到「包裝」標題,它將首先在第一部分中選擇數據,然後跳轉到第二部分的頂部。

有沒有很好的解決這個問題? 有沒有辦法來定義的OCR結構(例如,所以它讀取一行作爲一個單行?)

[*注]:它實際上是將文本包裹垂直(與水平文本通常看到的包裝)。

回答

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'] 
+0

感謝您提供一種新的方式來看待問題。 –