-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDocumentParser.py
156 lines (118 loc) · 4.66 KB
/
DocumentParser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
from tika import parser
from dateutil.parser import parser as date_parser
from PortugueseParserInfo import PortugueseParserInfo
class DocumentParser():
def __init__(self):
self.portDateParser = date_parser(info = PortugueseParserInfo())
def isDate(self, token):
'''
Funcao que retorna se token passado representa uma data
'''
try:
day, month, year = token.split('/')
day = int(day)
year = int(year)
return True
except:
return False
def isMonthYear(self, token):
'''
Funcao que retorna se token passado esta no formato Mes/Ano
'''
try:
month, year = token.split('/')
year = int(year)
return month in ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"]
except:
return False
def getLineClassification(self, line):
'''
Funcao para indicar classe da linha passada
As classes sao:
- title: titulo do documento
- issue: declaracao do gasto
- detail: detalhamento do gasto
- total: total do que foi gasto
- none: nao tem classe, nao tem importancia
'''
if len(line) == 0:
return "none"
hasVereador = "Vereador(a):" in line # checa se a string "Vereador(a):" esta presente na lihnha
hasMonthYear = self.isMonthYear(line[0]) # checa se o primeiro token da linha esta no formato Mes/Ano
hasRSOnPos = len(line) > 1 and line[-2] == "R$" # checa se tem um cifrao no penultimo token da linha
firstIsDate = self.isDate(line[0]) # checa se o primeiro token da linha eh uma data
# atribui a classe de acordo com o que foi extraido sobre a linha
if hasVereador and hasRSOnPos:
return "total"
if hasVereador and not hasRSOnPos and hasMonthYear:
return "title"
if hasRSOnPos and firstIsDate:
return "detail"
if hasRSOnPos and not firstIsDate and not hasVereador:
return "issue"
return "none"
def getInfoFromTitle(self, line):
'''
Funcao para extrair informacao de class "title"
'''
info = dict()
name = []
nameStart = False
for i in range(len(line)):
if nameStart:
name.append(line[i])
elif line[i] == 'Vereador(a):':
nameStart = True
info["nameVereador"] = " ".join(name)
info["yearDocument"] = line[0].split('/')[1]
info["monthDocument"] = line[0].split('/')[0]
return info
def getInfoFromIssue(self, line):
'''
Funcao para extrair informacao de class "issue"
'''
# last two are "R$" and "float"
info = dict()
info["issueDesc"] = " ".join(line[:-2])
info["issueCost"] = float(line[-1])
return info
def getInfoFromDetail(self, line):
'''
Funcao para extrair informacao de class "detail"
'''
info = dict()
try:
info["dateDatetime"] = self.portDateParser.parse(line[0])
except:
info["dateStr"] = line[0]
info["reciptId"] = line[1]
info["cpfCnpj"] = line[2]
info["fundament"] = line[3]
info["desc"] = " ".join(line[4:-2])
info["detailCost"] = float(line[-1])
return info
def parse(self, filePath):
# usnado o tika para extrair o texto do arquivo PDF passado
raw = parser.from_file(filePath)
lines = raw['content'].split('\n')
# inicializando o dicionario que ira armazenar os dados extraidos
info = {
"issues": []
}
for line in lines: # para cada linha do PDF
# separa a string usando split por ' '
line = line.split(' ')
# corta as linhas vazias
line = [x for x in line if len(x) > 0]
# recuepra a classe da linha
group = self.getLineClassification(line)
# se for um titulo ou issue, extrai info da linha
if group == "title": info.update(self.getInfoFromTitle(line))
elif group == "issue": info["issues"].append(self.getInfoFromIssue(line))
elif group == "detail": # se for um detalhamento, adiciona a lista de detalhamentos da issue corrente
if "details" not in info["issues"][-1]:
info["issues"][-1]["details"] = []
info["issues"][-1]["details"].append(
self.getInfoFromDetail(line)
)
return info