resume_parse.py 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  1. #!/usr/bin/env python
  2. # coding: utf-8
  3. import os
  4. import sys
  5. import re
  6. import subprocess
  7. from pprint import pprint
  8. import logging
  9. logging.basicConfig(format='%(asctime)s: %(name)s: %(levelname)s: %(filename)s: %(funcName)s: %(message)s', level=logging.INFO)
  10. import jieba
  11. import pandas as pd
  12. from docx import Document
  13. from docx.shared import Inches
  14. from numpy import mean, median, bincount, argmax
  15. from pdfminer.high_level import extract_pages
  16. from pdfminer.layout import LTTextContainer, LTChar, LTLine, LAParams, LTTextBox, LTFigure, LTImage, LTText, LTAnno, LTTextLine, LTTextLineHorizontal
  17. from pdfminer.pdfdocument import PDFDocument
  18. from pdfminer.pdfpage import PDFPage
  19. from pdfminer.pdfparser import PDFParser
  20. from pdfminer.converter import PDFPageAggregator
  21. from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
  22. import pdfplumber
  23. from paddlenlp import Taskflow
  24. from rich.console import Console
  25. console = Console()
  26. # import uvicorn
  27. # from fastapi import FastAPI
  28. # app = FastAPI()
  29. ner = Taskflow("ner", mode='fast')
  30. ner_tag = Taskflow("ner")
  31. global block, block_rev
  32. block = {
  33. "个人信息":1, "基本信息":1, "个人简历":1, "基基本本信信息息":1, "基本信息基本信息":1, "基本信息文本内容":1,
  34. "求职意向":2, "求职意向求职意向":2, "期望工作文本内容":2,
  35. "教育背景":3, "教育经历":3, "教教育育经经历历":3, "教育经历教育经历":3, "教育经历文本内容":3, "学历学位":3,
  36. "工作经验":4, "主要工作内容与职责":4, "工作方面":4, "实习经历":4, "工作经历":4, "工工作作经经历历":4, "工作经历工作经历":4, "工作经历文本内容":4,
  37. "项目经历":5, "项目经验":5, "科研项目经历":5, "项项目目经经历历":5, "项目经历项目经历":5, "研究生参与代表性项目":5, "项目经历文本内容":5,
  38. "专业技能":6, "个人技能":6, "专业/外语技能":6, "技能素质":6, "个人技能文本内容":6,
  39. "自我评价":7, "个人简介":7, "个人评价":7, "自我描述":7, "自自我我评评价价":7, "自我评价自我评价":7, "自我评价文本内容":7,
  40. "兴趣爱好":8, "兴趣爱好文本内容":8,
  41. "语言及方言":9, "语言能力":9, "英语能力":9, "语语言言能能力力":9, "语言能力语言能力":9, "语言技能文本内容":9,
  42. "证书":10, "所获证书文本内容":10,
  43. "获得奖励":11, "获奖经历":11, "获奖情况":11, "获获奖奖经经历历":11, "获奖经历获奖经历":11, "获奖情况及社会活动":11, "校内奖励":11, "校内活动&奖励":11, "所获奖励文本内容":11,"奖惩情况":11,
  44. "培训":12, "培训经历":12, "培培训训经经历历":12, "培训经历文本内容":12,
  45. "家庭成员":13, "家家庭庭成成员员":13, "家庭成员家庭成员":13, "主要家庭成员及社会关系":13,
  46. "社会活动":"other", "实践经验":"other", "社会活动及社会实践":"other", "近三年年度考核结果":"other", "其他意愿":"other",
  47. }
  48. block_rev = {1:"基本信息", 2:"求职意向", 3:"教育经历", 4:"工作经历", 5:"项目经历", 6:"专业技能", 7:"自我评价", 8:"兴趣爱好", 9:"语言能力", 10:"证书", 11:"获奖情况", 12:"培训经历", 13:"家庭成员", "other":"其他"}
  49. # 基本信息(已完成)
  50. def get_base_info(lines):
  51. pprint(lines)
  52. schema = {
  53. '姓名': None,
  54. }
  55. for line in [' '.join(' '.join(lines).split('\n'))]:
  56. line = line.replace(r'[ ]{5,}','\n')
  57. w = re.sub(r'[\W]+(\w[::])[\W]{0,}\w', r'\1', line)
  58. pprint(w)
  59. for i in w.split():
  60. if ':' in i:
  61. try:
  62. key, val = i.split(':')
  63. schema[key] = val
  64. except Exception as e:
  65. logging.error(e)
  66. if ':' in i:
  67. try:
  68. key, val = i.split(':')
  69. schema[key] = val
  70. except Exception as e:
  71. logging.error(e)
  72. if not schema.get('姓名'):
  73. schema['姓名'] = re.search(r'[姓名::]{3,}(\w{2,4})', w).group(1) if re.search(r'[姓名::]{3,}(\w{2,4})', w) else None
  74. if not schema.get('姓名'):
  75. for word, tag in ner_tag(w):
  76. if tag == "人物类_实体":
  77. schema['姓名'] = word
  78. if not schema.get('性别'):
  79. schema['性别'] = re.search(r'[男女]', w).group() if re.search(r'[男女]', w) else None
  80. if not schema.get('婚姻状况'):
  81. schema['婚姻状况'] = re.search(r'[已未]婚', w).group() if re.search(r'[已未]婚', w) else None
  82. # if not schema.get('籍贯'):
  83. # schema['籍贯'] = re.search(r'[籍贯::]{3,}(\w{2,5})', w).group(1) if re.search(r'[籍贯::]{3,}(\w{2,})', w) else None
  84. # if not schema.get('学历'):
  85. # schema['学历'] = re.search(r'[学历::]{3,}(\w{2,4})', w).group(1) if re.search(r'[学历::]{3,}(\w{2,4})', w) else None
  86. if not schema.get('电子邮箱'):
  87. schema['电子邮箱'] = re.search(r'([.\w]+@[.\w]+)', w).group() if re.search(r'([.\w]+@[.\w]+)', w) else None
  88. if not schema.get('政治面貌'):
  89. schema['政治面貌'] = re.search(r'[预备中共党团员群众无派人士]{2,6}', w).group() if re.search(r'[预备中共党团员群众无派人士]{2,6}', w) else None
  90. if not schema.get('手机号码'):
  91. schema['手机号码'] = re.search(r'\W(1[\d]{10})\W', w).group(1) if re.search(r'\W(1[\d]{10})\W', w) else None
  92. # if not schema.get('出生年月'):
  93. # schema['出生年月'] = re.search(r'\d{4}[./年\-]\d{1,2}[月]', w).group() if re.search(r'\d{4}[./年\-]\d{1,2}[月]', w) else None
  94. # if not schema.get('当前职位'):
  95. # schema['当前职位'] = re.search(r'[当前职位: ]{3,}(\w)+', w).group() if re.search(r'[当前职位: ]{3,}(\w)+', w) else None
  96. # if not schema.get('参加工作时间'):
  97. # schema['参加工作时间'] = re.search(r'[参加工作事件:]{3,}(\d{4}[./年\-]\d{1,2}[月])', w).group(1) if re.search(r'[参加工作事件:]{3,}(\d{4}[./年\-]\d{1,2}[月])', w) else None
  98. return {key:value for key, value in schema.items() if value}
  99. # 求职意向(已完成)
  100. def get_job_intention(lines):
  101. pprint(lines)
  102. schema = {}
  103. for line in lines:
  104. regex = re.compile(r'\W{0,3}[::]\s+')
  105. line = regex.sub(':', line)
  106. for i in line.split():
  107. if ":" in i:
  108. try:
  109. key, val = i.split(":")
  110. schema[key] = val
  111. except Exception as e:
  112. logging.error(e)
  113. return schema
  114. # 教育经历 (已完成)
  115. # ner + 分词 (判断学校,时间,学历) 专业需要单独处理。
  116. def get_edu_list_old(lines):
  117. pprint(lines)
  118. job_list = []
  119. job_dict = {'edu_time_beg':'', 'edu_time_end':'', 'edu_name':'','edu_leval':'','edu_domain':'', 'edu_statue':0}
  120. re_txt = '\d{4,4}.\d{1,2}.?\040{0,2}[\-–至-\—~]\040{0,2}\d{4,4}.\d{1,2}[月]?|\d+\.\d+\-至今|\d+年\d+月\-\d+年\d+月|\d+年\d+月\-\~|\d+年\d+月[\-\~]至今|\d+-\d+\040{0,2}[\~至]\040{0,2}\d+-\d+|\d+-\d+\~|\d+-\d+\~至今|\d+-\d+\040{0,2}至今|^\d{4,4}.\d{1,2}|19\d{2,2}.|20\d{2,2}.'
  121. re_txt_1 = '\d{4,4}.\d{1,2}.?\040{0,2}[\-–至-\—~]\040{0,2}\d{4,4}.\d{1,2}[月]?|\d+\.\d+\-至今|\d+年\d+月\-\d+年\d+月|\d+年\d+月\-\~|\d+年\d+月[\-\~]至今|\d+-\d+\040{0,2}[\~至]\040{0,2}\d+-\d+|\d+-\d+\~|\d+-\d+\~至今|\d+-\d+\040{0,2}至今'
  122. nums = []
  123. for i in range(len(lines)):
  124. if re.findall(re_txt, lines[i]):
  125. nums.append(i)
  126. nums.append(len(lines))
  127. edu_level = {'本科':18, "大专":17, "博士研究生":20, "学士":18, "博士":20, "硕士":19, "研究生":19, "博后":21, '博士后':21}
  128. year_dict = {18:4, 17:3,20:3,19:3,21:2}
  129. edu_dict = {18:'本科', 17:'大专',20:'博士研究生',19:'硕士',21:'博士后'}
  130. edu_list = []
  131. for i in range(1, len(nums[:])):
  132. job_dict = {'edu_time_beg':'', 'edu_time_end':'', 'edu_name':'','edu_leval':'','edu_domain':''}
  133. data_list = lines[nums[i-1]:nums[i]]
  134. if len(data_list) > 1 and data_list[1] and data_list[1][-1] == '|' and data_list[0][-1] != '|':
  135. data_list[0] = data_list[0] + data_list[1]
  136. data_list[1] = ''
  137. if len(data_list) > 2 and data_list[2] and data_list[2][-1] == '|' and data_list[0][-1] != '|' and '|' in str(data_list[0]) and data_list[1] and data_list[1][-1] != '|':
  138. data_list[0] = data_list[0] + data_list[1] + data_list[2]
  139. data_list[1] = ''
  140. data_list[2] = ''
  141. if '' in data_list:
  142. data_list.remove('')
  143. data_line = ' '.join(data_list)
  144. data_line = re.sub('[\|]', ' ', data_line)
  145. data_line = re.sub('-{3,}', '', data_line)
  146. ner_data = ner(''.join(data_list[:2]))
  147. org = ''
  148. time_list = []
  149. for jj in range(1, len(ner_data)):
  150. if ner_data[jj][1] == ner_data[jj-1][1]:
  151. ner_data[jj] = list(ner_data[jj])
  152. ner_data[jj][0] = ner_data[jj-1][0] + ner_data[jj][0]
  153. ner_data[jj-1] = ('','')
  154. for _ in ner_data:
  155. if _[1] == 'ORG' and not org:
  156. org = _[0].strip()
  157. elif _[1] == 'TIME' and len(_[1]) >= 4:
  158. time_list.append(_[0])
  159. #TIME
  160. # print(data_line)
  161. _list_data = re.split('\040+',data_line)
  162. top_level = 18
  163. remove_list = []
  164. logging.debug(_list_data)
  165. logging.debug(time_list)
  166. for ii in range(len(_list_data)):
  167. for t in time_list:
  168. if t in _list_data[ii]:
  169. _list_data[ii] = ''
  170. break
  171. for i in range(len(_list_data)):
  172. #if org in _list_data[i]:
  173. # _list_data[i] = ''
  174. if re.findall('^\d{4,4}', _list_data[i]):
  175. _list_data[i] = ''
  176. _data = re.findall('本科|学士|硕士|博士研究生|博士后|博后|博士|研究生|大专', _list_data[i])
  177. if not _data:
  178. continue
  179. top_level = edu_level[_data[0]]
  180. _list_data[i] = ''
  181. break
  182. #remove_list.append(i)
  183. logging.debug(_list_data)
  184. job_time = re.findall(re_txt_1, data_list[0])
  185. if job_time:
  186. job_dict['edu_time'] = job_time[0]
  187. else:
  188. job_dict['edu_time'] = ''
  189. _nums = re.findall('\d+', job_dict['edu_time'])
  190. if len(_nums) >= 4:
  191. job_dict['edu_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  192. job_dict['edu_time_end'] = '%s-%02d'%(_nums[2], int(_nums[3]))
  193. job_dict['edu_time'] = '%s-%02d~%s-%02d'%(_nums[0], int(_nums[1]), _nums[2], int(_nums[3]))
  194. elif len(_nums) == 2:
  195. job_dict['edu_time'] = '%s-%02d~%s'%(_nums[0], int(_nums[1]), '至今')
  196. job_dict['edu_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  197. job_dict['edu_time_end'] = '%s'%('至今')
  198. elif len(time_list) == 2:
  199. nums_1 = re.findall('\d+', time_list[0])
  200. nums_2 = re.findall('\d+', time_list[1])
  201. nums_1.append('09')
  202. nums_2.append('07')
  203. job_dict['edu_time_beg'] = '%s-%02d'%(nums_1[0], int(nums_1[1]))
  204. try:
  205. job_dict['edu_time_end'] = '%s-%02d'%(nums_2[0], int(nums_2[1]))
  206. except:
  207. job_dict['edu_time_end'] = None
  208. try:
  209. job_dict['edu_time'] = '%s-%02d~%s-%02d'%(nums_1[0], int(nums_1[1]), nums_2[0], int(nums_2[1]))
  210. except:
  211. job_dict['edu_time'] = '%s-%02d~今'%(nums_1[0], int(nums_1[1]))
  212. elif len(time_list) == 1:
  213. _nums = re.findall('\d+', time_list[0])
  214. if '毕业' in data_list[0]:
  215. _nums.append('06')
  216. _nums.insert(0, '09')
  217. _nums.insert(0, str(int(_nums[1]) - year_dict[top_level]))
  218. job_dict['edu_time'] = '%s-%02d~%s-%02d'%(_nums[0], int(_nums[1]), _nums[2], int(_nums[3]))
  219. job_dict['edu_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  220. job_dict['edu_time_end'] = '%s-%02d'%(_nums[2], int(_nums[3]))
  221. else:
  222. _nums.append('09')
  223. job_dict['edu_time'] = '%s-%02d~%s'%(_nums[0], int(_nums[1]), '至今')
  224. job_dict['edu_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  225. job_dict['edu_time_end'] = '%s'%('至今')
  226. job_dict['edu_leval'] = edu_dict[top_level]
  227. if org:
  228. job_dict['edu_name'] = org
  229. else:
  230. job_dict['edu_name'] = ''
  231. edu_domain = ''
  232. for i in range(len(_list_data)):
  233. if org in _list_data[i]:
  234. continue
  235. if not _list_data[i] and '专业' in _list_data[i]:
  236. edu_domain = _list_data[i]
  237. if not edu_domain:
  238. for i in range(len(_list_data)):
  239. if org in _list_data[i]:
  240. continue
  241. if _list_data[i] and len(_list_data[i]) >= 3:
  242. edu_domain = _list_data[i]
  243. break
  244. if not edu_domain:
  245. for i in range(len(_list_data)):
  246. if org in _list_data[i]:
  247. for j in range(i+1, len(_list_data)):
  248. if _list_data[i] and len(_list_data[j]) >= 2:
  249. edu_domain = _list_data[j]
  250. break
  251. break
  252. job_dict['edu_domain'] = edu_domain
  253. # print(job_dict)
  254. # print(_list_data)
  255. if len(job_list) ==0:
  256. job_list.append(job_dict)
  257. else:
  258. if job_dict in job_list:
  259. continue
  260. if not job_dict['edu_time']:
  261. continue
  262. if int(job_dict['edu_time'][:4]) > int(job_list[-1]['edu_time'][:4]):
  263. job_list = [job_dict] + job_list
  264. else:
  265. job_list.append(job_dict)
  266. continue
  267. data_list[0] = re.sub(job_time[0], '', data_list[0])
  268. _list = re.split('\|\040+', data_list[0])
  269. #print(_list)
  270. if len(_list) == 1:
  271. __list = re.split('\040+', data_list[0])
  272. job_dict['edu_name'] = __list[1].strip()
  273. job_dict['edu_domain'] = __list[2].strip()
  274. job_dict['edu_leval'] = __list[3].strip()
  275. else:
  276. #if job_dict['edu_leval'] not in
  277. if len(_list) > 3:
  278. job_dict['edu_name'] = _list[2].strip()
  279. job_dict['edu_domain'] = _list[3].strip()
  280. job_dict['edu_leval'] = _list[1].strip()
  281. else:
  282. job_dict['edu_leval'] = _list[0].strip()
  283. job_dict['edu_name'] = _list[1].strip()
  284. job_dict['edu_domain'] = _list[2].strip()
  285. if '硕士' in _list[0] or '研究生' in _list[0]:
  286. job_dict['edu_leval'] = '硕士'
  287. elif '博士' in _list[0]:
  288. job_dict['edu_leval'] = '博士'
  289. elif '本科' in _list[0]:
  290. job_dict['edu_leval'] = '本科'
  291. elif '学士' in _list[0]:
  292. job_dict['edu_leval'] = '本科'
  293. # print(job_dict)
  294. if len(job_list) ==0:
  295. job_list.append(job_dict)
  296. else:
  297. if job_dict in job_list:
  298. continue
  299. if int(job_dict['edu_time'][:4]) > int(job_list[-1]['edu_time'][:4]):
  300. job_list = [job_dict] + job_list
  301. else:
  302. job_list.append(job_dict)
  303. #edu_list.append(job_dict['edu_time'] + job_dict['edu_name'] + job_dict['edu_domain'] + job_dict['edu_leval'])
  304. #if job_list[0]['edu_leval'] not in ['硕士', '博士', '本科', '博后'] and len(job_list[0]['edu_leval']) > 5:
  305. # job_list[0]['edu_leval'] = '本科'
  306. return job_list
  307. # 教育经历改 (已完成)
  308. def get_edu_list(lines):
  309. pprint(lines)
  310. edu_list = [{"Time":None, "startTime":None, "endTime":None, "edu_name":None, "edu_domain":None, "edu_level":None}]
  311. regex_time = re.compile(r'((\d{4})[年\W]{1,2}(\d{1,2})[月\W]?[\d]{0,2})[至到\W]+((\d{4})[年\W]{1,2}(\d{1,2})[月\W]?)?([今])?|(\d{4})[至\W]+([\d今]{4})')
  312. regex_end = re.compile(r'毕业时间[\w\W]{0,5}(\d{4})[\W年]?(\d{0,2})[月\W]?')
  313. regex_level = re.compile(r'[大本专科硕博士研究生后]{2,}')
  314. regex_domain = re.compile(u'[\u4E00-\u9FA5]{2,10}', re.UNICODE)
  315. count = 0
  316. for line in lines:
  317. line = line.replace("学士","本科").replace("专业","").replace("学位","")
  318. for cell in re.split(r'[·\|\t]', line):
  319. if not cell.strip():
  320. continue
  321. flags = 0
  322. edu_time = regex_time.search(cell)
  323. edu_end_time = regex_end.search(cell)
  324. edu_level = regex_level.search(cell)
  325. edu_domain = regex_domain.search(cell)
  326. # 标准时间格式
  327. if edu_time:
  328. # 提交信息
  329. if edu_list[count].get("Time") and edu_list[count].get("edu_name"):
  330. edu_list.append({"Time":None, "startTime":None, "endTime":None, "edu_name":None, "edu_domain":None, "edu_level":None})
  331. count += 1
  332. edu_list[count]["startTime"] = '{:4d}-{:02d}'.format(int(edu_time.group(2)),int(edu_time.group(3)))
  333. if edu_time.group(5) != None:
  334. edu_list[count]["endTime"] = '{:4d}-{:02d}'.format(int(edu_time.group(5)),int(edu_time.group(6)))
  335. edu_list[count]["Time"] = '{:4d}-{:02d}~{:4d}-{:02d}'.format(int(edu_time.group(2)),int(edu_time.group(3)),int(edu_time.group(5)),int(edu_time.group(6)))
  336. elif edu_time.group(8) != None:
  337. edu_list[count]["Time"] = '{:4d}~{:4d}'.format(int(edu_time.group(8)),int(edu_time.group(9)))
  338. edu_list[count]["startTime"] = '{:4d}'.format(int(edu_time.group(8)))
  339. edu_list[count]["endTime"] = '{:4d}'.format(int(edu_time.group(9)))
  340. else:
  341. edu_list[count]["endTime"] = edu_time.group(7)
  342. edu_list[count]['Time'] = '{:4d}-{:02d}~{}'.format(int(edu_time.group(2)),int(edu_time.group(3)),edu_time.group(7))
  343. flags = 1
  344. elif edu_end_time:
  345. if edu_list[count].get("endTime") and edu_list[count].get("edu_name"):
  346. edu_list.append({"Time":None, "startTime":None, "endTime":None, "edu_name":None, "edu_domain":None, "edu_level":None})
  347. count += 1
  348. if edu_end_time.group(2):
  349. edu_list[count]["Time"] = '{:4d}-{:02d}~{:4d}-{:02d}'.format(int(edu_end_time.group(1)),int(edu_end_time.group(2)),int(edu_end_time.group(1))-3,int(edu_end_time.group(2)))
  350. edu_list[count]["endTime"] = '{:4d}-{:02d}'.format(int(edu_end_time.group(1)),int(edu_end_time.group(2)))
  351. elif edu_end_time.group(1):
  352. edu_list[count]["Time"] = '{:4d}~{:4d}'.format(int(edu_end_time.group(1)),int(edu_end_time.group(1))-3)
  353. edu_list[count]["endTime"] = '{:4d}'.format(int(edu_end_time.group(1)))
  354. if (not edu_list[count].get("edu_level")) and edu_level:
  355. edu_list[count]["edu_level"] = edu_level.group(0)
  356. for word, tag in ner_tag(cell):
  357. if (not edu_list[count].get("edu_name")) and (tag == "组织机构类_教育组织机构"):
  358. edu_list[count]["edu_name"] = word.strip()
  359. flags = 1
  360. elif (not edu_list[count].get("edu_domain")) and (tag in "_术语类型"):
  361. edu_list[count]["edu_domain"] = word.strip()
  362. elif edu_list[count].get("edu_name") and edu_list[count].get("edu_domain"):
  363. break
  364. else:
  365. for word, tag in ner(cell):
  366. if (tag == "ORG"):
  367. edu_list[count]["edu_name"] = word
  368. flags = 1
  369. break
  370. if (not (edu_level or flags or edu_list[count].get("edu_domain"))) and edu_domain:
  371. edu_list[count]["edu_domain"] = edu_domain.group(0)
  372. if (not edu_list[-1].get("Time")) or (not edu_list[-1].get("edu_name")):
  373. edu_list.pop()
  374. return edu_list
  375. # 工作经历 (已完成)
  376. # ner + 分词 机构信息,人物身份信息,时间 工作内容区分判断
  377. # 其中,时间是判断是否下一份工作情况的主要标识符之一。字符数量
  378. # 时间类 数量词
  379. def get_job_list(lines):
  380. pprint(lines)
  381. job_list = []
  382. re_txt = '\d{4,4}\040{0,2}.\d+\040{0,2}.?\040{0,2}[\-–至-\—~]{1,2}\040{0,2}\d{4,4}\040{0,2}.\040{0,2}\d+.?|\d{4,4}.\d+.?\040{0,2}[\-–-—]{0,2}\040{0,2}至?今|\d{4,4}.\d+.?\040{0,2}[\-–-]{1,2}\040{0,2}现在|\d{4,4}年\d+月\-\d{4,4}年\d+月|\d{4,4}年\d+月\-\~|\d{4,4}年\d+月[\-\~-]至今|\d{4,4}-\d+\040{0,2}[-\~至]\040{0,2}\d{4,4}-\d+|\d{4,4}-\d+\~|\d{4,4}-\d+\[~-]至今|\d{4,4}-\d+\040{0,2}至今'
  383. nums = []
  384. for i in range(len(lines)):
  385. #print(lines[i])
  386. #print(lines[i], re.findall(re_txt, lines[i]), re.findall('\||\040{1,}', lines[i]))
  387. if re.findall(re_txt, lines[i].replace(' ', '')) and re.findall('\||\040{1,}', lines[i]):
  388. nums.append(i)
  389. continue
  390. if re.findall(re_txt, lines[i].replace(' ', '')[:20]):
  391. nums.append(i)
  392. continue
  393. if len(lines[i].strip().replace(' ', '')) > 50:
  394. continue
  395. year_list = re.findall('19\d{2,2}.\d{1,2}|20\d{2,2}.\d{1,2}', lines[i])
  396. if len(year_list) >= 2:
  397. nums.append(i)
  398. elif len(year_list) == 1 and '至今' in lines[i]:
  399. nums.append(i)
  400. nums.append(len(lines))
  401. # pprint(nums)
  402. logging.debug('get_job_list :{}'.format(nums))
  403. for i in range(1, len(nums[:])):
  404. job_dict = {'job_time':'', 'job_leval':'','job_company':'','job_content':''}
  405. data_list = lines[nums[i-1]:nums[i]]
  406. if '' in data_list:
  407. data_list.remove('')
  408. org = ''
  409. person_professor_list = []
  410. org_index = -1
  411. end_index = 3
  412. job_time = re.findall(re_txt, data_list[0])
  413. if not job_time:
  414. year_list = re.findall('19\d{2,2}.\d{1,2}|20\d{2,2}.\d{1,2}', data_list[0])
  415. if len(year_list) >= 2:
  416. job_time = ['-'.join(year_list)]
  417. elif len(year_list) == 1 and '至今' in lines[i]:
  418. job_time = [year_list[0] + '-' + '至今']
  419. pprint("342{}".format(job_time))
  420. if not job_time:
  421. regex = re.compile(r'((\d{4})[年\W]+(\d{1,2})[\W]?[\w]?)[至到\W]+((\d{4})[年\W]+(\d{1,2})[\W]?[\w]?)?([今])?')
  422. job_time = [re.search(regex, data_list[0]).group(0)]
  423. pprint("346{}".format(job_time))
  424. job_dict['job_time'] = job_time[0]
  425. _nums = re.findall('\d+', job_dict['job_time'])
  426. #print(_nums)
  427. if len(_nums) >= 4:
  428. job_dict['job_time'] = '%s-%02d~%s-%02d'%(_nums[0], int(_nums[1]), _nums[2], int(_nums[3]))
  429. elif len(_nums) == 2:
  430. job_dict['job_time'] = '%s-%02d~%s'%(_nums[0], int(_nums[1]), '至今')
  431. data_list[0] = re.sub(job_time[0], '', data_list[0])
  432. data_list[0] = data_list[0].strip()
  433. ner_list = []
  434. for i in range(len(data_list[:3])):
  435. if '工作' in data_list[i][:4] and (re.findall(':|\:', data_list[i])):
  436. end_index = i
  437. break
  438. if not re.findall('\040|\||/', data_list[i]) and org:
  439. end_index = i
  440. break
  441. if len(data_list[i]) > 80:
  442. end_index = i
  443. break
  444. if data_list[i]:
  445. ner_data = ner_tag(data_list[i].strip())
  446. else:
  447. continue
  448. ner_list.append(ner_data)
  449. for x in ner_data:
  450. if x[1] == '人物类_概念' and len(x[0]) > 2:
  451. person_professor_list.append(x[0].strip())
  452. elif x[1] == '组织机构类_企事业单位' or x[1] == '组织机构类_教育组织机构':
  453. if not org:
  454. org = re.split('\040|\|/', x[0].strip())[0]
  455. org_index = i
  456. if not org:
  457. for i in range(len(ner_list)):
  458. ner_data = ner_list[i]
  459. for x in ner_data:
  460. if x[1] == '组织机构类':
  461. org = re.split('\040|\|/', x[0].strip())[0]
  462. break
  463. if not person_professor_list:
  464. for i in range(len(ner_list)):
  465. ner_data = ner_list[i]
  466. for x in ner_data:
  467. if x[1] == '人物类_概念':
  468. person_professor_list = [re.split('\040|\|/', x[0].strip())[0]]
  469. break
  470. data_line = ' '.join(data_list[:end_index])
  471. data_line = re.sub('\||/', ' ', data_line)
  472. _list_data = re.split('\040+',data_line)
  473. if len(_list_data) == 1:
  474. end_index = 0
  475. if not person_professor_list:
  476. for x in range(len(_list_data)):
  477. if re.findall('经理|工程师|会计|董事长|总监|秘书|主管|处长|局长|主任|讲师|教授', _list_data[x][-4:]):
  478. person_professor_list.append(_list_data[x])
  479. if not org:
  480. for x in range(len(_list_data)):
  481. if len(_list_data[x]) < 4:
  482. _list_data[x] = ''
  483. elif person_professor_list and re.findall('|'.join(person_professor_list), _list_data[x]):
  484. _list_data[x] = ''
  485. elif '经理' == _list_data[x][-2:]:
  486. _list_data[x] = ''
  487. for x in range(len(_list_data)):
  488. if _list_data[x]:
  489. org = _list_data[x]
  490. break
  491. if not person_professor_list:
  492. for x in range(len(_list_data)):
  493. if org in _list_data[x]:
  494. for j in range(x+1, len(_list_data)):
  495. if _list_data[j]:
  496. person_professor_list = [_list_data[j]]
  497. break
  498. break
  499. #print(org, person_professor_list, job_time)
  500. job_dict['job_company'] = org
  501. job_dict['job_leval'] = ' '.join(person_professor_list)
  502. job_dict['job_content'] = re.sub('工工作作内内容容::|工工作作内内容容::|工工作作内内容容', '工作内容:', ''.join(data_list[end_index:]))
  503. job_dict['job_content'] = re.sub('/', '-', job_dict['job_content'])
  504. job_list.append(job_dict)
  505. continue
  506. if len(data_list) > 1 and data_list[1] and data_list[1][-1] == '|':# and data_list[0] and data_list[0][-1] != '|':
  507. data_list[0] = data_list[0] + data_list[1]
  508. data_list[1] = ''
  509. elif len(data_list) > 2 and data_list[2] and data_list[2][-1] == '|' and data_list[0][-1] != '|' and '|' in str(data_list[0]) and data_list[1] and data_list[1][-1] != '|':
  510. data_list[0] = data_list[0] + data_list[1] + data_list[2]
  511. data_list[1] = ''
  512. data_list[2] = ''
  513. elif len(data_list) > 1 and data_list[1] and '工作职责:' in data_list[2]:
  514. data_list[0] = data_list[0] + data_list[1]
  515. data_list[1] = ''
  516. elif len(data_list) > 1 and '工作职责:' in data_list[3]:
  517. data_list[0] = data_list[0] + data_list[1] + data_list[2]
  518. data_list[1] = ''
  519. data_list[2] = ''
  520. job_time = re.findall(re_txt, data_list[0])
  521. job_dict['job_time'] = job_time[0]
  522. _nums = re.findall('\d+', job_dict['job_time'])
  523. #print(_nums)
  524. if len(_nums) >= 4:
  525. job_dict['job_time'] = '%s-%02d~%s-%02d'%(_nums[0], int(_nums[1]), _nums[2], int(_nums[3]))
  526. elif len(_nums) == 2:
  527. job_dict['job_time'] = '%s-%02d~%s'%(_nums[0], int(_nums[1]), '至今')
  528. data_list[0] = re.sub(job_time[0], '', data_list[0])
  529. data_list[0] = data_list[0].strip()
  530. data_list[0] = re.sub('历任:', ' ', data_list[0])
  531. _list = data_list[0].split('|')
  532. if len(_list) == 1:
  533. __list = re.split('\040{2,}', data_list[0])
  534. #print(__list)
  535. job_dict['job_leval'] = __list[1].strip()
  536. job_dict['job_company'] = __list[0].strip()
  537. else:
  538. job_dict['job_leval'] = _list[0].strip()
  539. job_dict['job_company'] = _list[1].strip()
  540. if '职级:' in data_list[1:]:
  541. data_list.remove('职级:')
  542. job_dict['job_content'] = re.sub('工工作作内内容容::|工工作作内内容容::|工工作作内内容容', '工作内容:', ''.join(data_list[1:]))
  543. job_dict['job_content'] = re.sub('/', '-', job_dict['job_content'])
  544. #print(job_dict)
  545. job_list.append(job_dict)
  546. return job_list
  547. # 项目经历 (已完成)
  548. # 项目名称未知
  549. def get_pro_list(lines):
  550. pprint(lines)
  551. pro_list = [{"Time":None,"startTime":None,"endTime":None,"pro_name":None,"job_leval":None,"job_company":None,"content":None,},]
  552. regex = re.compile(r'((\d{4})[年\W]+(\d{1,2})[\W]?[\w]?)[至到\W]+((\d{4})[年\W]+(\d{1,2})[\W]?[\w]?)?([今])?')
  553. re_con = re.compile(r'负责内容(.*?)')
  554. re_na = re.compile(r'\W(.*?项目)\W')
  555. count = 0
  556. for line in lines:
  557. regex_time = regex.search(line)
  558. regex_content = re_con.search(line)
  559. regex_name = re_na.search(line)
  560. if regex_time:
  561. # data_list = line.split()
  562. # # for i in regex_time.groups():
  563. # # data_list.remove(i)
  564. # console.print(regex_time.groups(), style='red', justify='left')
  565. # console.print(data_list, style='red', justify='left')
  566. if pro_list[count].get("Time"):
  567. pro_list.append({"Time":None,"startTime":None,"endTime":None,"pro_name":None,"job_leval":None,"job_company":None,"content":None,})
  568. count += 1
  569. pro_list[count]["startTime"] = '{:4d}-{:02d}'.format(int(regex_time.group(2)),int(regex_time.group(3)))
  570. if regex_time.group(5) != None:
  571. pro_list[count]["endTime"] = '{:4d}-{:02d}'.format(int(regex_time.group(5)),int(regex_time.group(6)))
  572. pro_list[count]["Time"] = '{:4d}-{:02d}~{:4d}-{:02d}'.format(int(regex_time.group(2)),int(regex_time.group(3)),int(regex_time.group(5)),int(regex_time.group(6)))
  573. else:
  574. pro_list[count]["endTime"] = regex_time.group(7)
  575. pro_list[count]['Time'] = '{:4d}-{:02d}~{}'.format(int(regex_time.group(2)),int(regex_time.group(3)),regex_time.group(7))
  576. elif regex_name and (not pro_list[count].get("job_name")):
  577. pro_list[count]["pro_name"] = regex_name.group()
  578. elif pro_list[count].get("content"):
  579. pro_list[count]["content"] += line
  580. else:
  581. try:
  582. for word, tag in ner_tag(line):
  583. if (not pro_list[count].get("job_leval")) and (tag == "人物类_概念"):
  584. pro_list[count]["job_leval"] = word
  585. if (not pro_list[count].get("job_company")) and (tag in "组织机构类_企事业单位"):
  586. pro_list[count]["job_company"] = word
  587. except Exception as e:
  588. logging.error(e)
  589. pro_list[count]["content"] = line
  590. return pro_list
  591. # 培训经历 (已完成)
  592. # ner + 分词 (机构名) 培训项目 时间
  593. def get_cultivate_list(lines):
  594. pprint(lines)
  595. job_list = []
  596. re_txt = '\d{4,4}.\d{1,2}.?\040{0,2}[\-–至-\—~]\040{0,2}\d{4,4}.\d{1,2}[月]?|\d+\.\d+\-至今|\d+年\d+月\-\d+年\d+月|\d+年\d+月\-\~|\d+年\d+月[\-\~]至今|\d+-\d+\040{0,2}[\~至]\040{0,2}\d+-\d+|\d+-\d+\~|\d+-\d+\~至今|\d+-\d+\040{0,2}至今|^\d{4,4}.\d{1,2}|\d{4,4}.'
  597. re_txt_1 = '\d{4,4}.\d{1,2}.?\040{0,2}[\-–至-\—~]\040{0,2}\d{4,4}.\d{1,2}[月]?|\d+\.\d+\-至今|\d+年\d+月\-\d+年\d+月|\d+年\d+月\-\~|\d+年\d+月[\-\~]至今|\d+-\d+\040{0,2}[\~至]\040{0,2}\d+-\d+|\d+-\d+\~|\d+-\d+\~至今|\d+-\d+\040{0,2}至今'
  598. nums = []
  599. for i in range(len(lines)):
  600. if re.findall(re_txt, lines[i].replace(' ', '')) and re.findall('\||\040{1,}', lines[i]):
  601. nums.append(i)
  602. continue
  603. if re.findall(re_txt, lines[i].replace(' ', '')[:20]):
  604. nums.append(i)
  605. if len(lines[i].strip().replace(' ', '')) > 50:
  606. continue
  607. nums.append(len(lines))
  608. year_dict = {18:4, 17:3,20:3,19:3,21:2,22:1}
  609. for i in range(1, len(nums[:])):
  610. job_dict = {'cultivate_time':'', 'cultivate_time_beg':'', 'cultivate_time_end':'', 'cultivate_name':'','cultivate_leval':'','cultivate_content':''}
  611. data_list = lines[nums[i-1]:nums[i]]
  612. data_line = ' '.join(data_list)
  613. data_line = re.sub('[\|\t]', ' ', data_line)
  614. data_line = re.sub('-{3,}', '', data_line)
  615. ner_data = ner(''.join(data_list[:2]))
  616. org = ''
  617. time_list = []
  618. for _ in ner_data:
  619. if _[1] == 'ORG' and not org:
  620. org = _[0].strip()
  621. elif _[1] == 'TIME' and len(_[1]) >= 4:
  622. time_list.append(_[0])
  623. #TIME
  624. logging.debug(data_line)
  625. _list_data = re.split('\040+', data_line)
  626. top_level = 22
  627. end_index = 0
  628. remove_list = []
  629. if len(_list_data) <= 2:
  630. end_index = 0
  631. #continue
  632. job_time = re.findall(re_txt_1, data_list[0])
  633. if job_time:
  634. job_dict['cultivate_time'] = job_time[0]
  635. data_list[0] = re.sub(job_time[0], '', data_list[0])
  636. else:
  637. job_dict['cultivate_time'] = ''
  638. for t in time_list:
  639. data_list[0] = re.sub(t, '', data_list[0])
  640. _list = data_list[0].split('|')
  641. if len(_list) >= 2:
  642. job_dict['cultivate_name'] = _list[0].strip()
  643. job_dict['cultivate_leval'] = _list[1].strip()
  644. end_index = 1
  645. _nums = re.findall('\d+', job_dict['cultivate_time'])
  646. if len(_nums) >= 4:
  647. job_dict['cultivate_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  648. job_dict['cultivate_time_end'] = '%s-%02d'%(_nums[2], int(_nums[3]))
  649. job_dict['cultivate_time'] = '%s-%02d~%s-%02d'%(_nums[0], int(_nums[1]), _nums[2], int(_nums[3]))
  650. elif len(_nums) == 2:
  651. job_dict['cultivate_time'] = '%s-%02d~%s'%(_nums[0], int(_nums[1]), '至今')
  652. job_dict['cultivate_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  653. job_dict['cultivate_time_end'] = '%s'%('至今')
  654. elif len(time_list) == 2:
  655. nums_1 = re.findall('\d+', time_list[0])
  656. nums_2 = re.findall('\d+', time_list[1])
  657. nums_1.append('09')
  658. nums_2.append('07')
  659. job_dict['cultivate_time_beg'] = '%s-%02d'%(nums_1[0], int(nums_1[1]))
  660. job_dict['cultivate_time_end'] = '%s-%02d'%(nums_2[0], int(nums_2[1]))
  661. job_dict['cultivate_time'] = '%s-%02d~%s-%02d'%(nums_1[0], int(nums_1[1]), nums_2[0], int(nums_2[1]))
  662. elif len(time_list) == 1:
  663. _nums = re.findall('\d+', time_list[0])
  664. if '获得' in data_list[0]:
  665. _nums.append('01')
  666. _nums.insert(0, '01')
  667. _nums.insert(0, str(int(_nums[1]) - year_dict[top_level]))
  668. job_dict['cultivate_time'] = '%s-%02d~%s-%02d'%(_nums[0], int(_nums[1]), _nums[2], int(_nums[3]))
  669. job_dict['cultivate_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  670. job_dict['cultivate_time_end'] = '%s-%02d'%(_nums[2], int(_nums[3]))
  671. else:
  672. _nums.append('01')
  673. job_dict['cultivate_time'] = '%s-%02d~%s'%(_nums[0], int(_nums[1]), '至今')
  674. job_dict['cultivate_time_beg'] = '%s-%02d'%(_nums[0], int(_nums[1]))
  675. job_dict['cultivate_time_end'] = '%s'%('至今')
  676. job_dict['cultivate_content'] = re.sub('培培训训内内容容::|培培训训内内容容::|培培训训内内容容', '培训内容:', ''.join(data_list[end_index:]))
  677. if not job_dict['cultivate_name']:
  678. job_dict['cultivate_name'] = org
  679. logging.debug(job_dict)
  680. job_list.append(job_dict)
  681. continue
  682. '''
  683. #print(nums)
  684. for i in range(1, len(nums[:])):
  685. job_dict = {'cultivate_time':'', 'cultivate_name':'','cultivate_leval':'','cultivate_content':''}
  686. data_list = lines[nums[i-1]:nums[i]]
  687. if '' in data_list:
  688. data_list.remove('')
  689. if len(data_list) > 1 and data_list[1] and data_list[1][-1] == '|' and data_list[0][-1] != '|':
  690. data_list[0] = data_list[0] + data_list[1]
  691. data_list[1] = ''
  692. job_time = re.findall(re_txt_1, data_list[0])
  693. job_dict['cultivate_time'] = job_time[0]
  694. _nums = re.findall('\d+', job_dict['cultivate_time'])
  695. if len(_nums) >= 4:
  696. job_dict['cultivate_time'] = '%s-%02d~%s-%02d'%(_nums[0], int(_nums[1]), _nums[2], int(_nums[3]))
  697. elif len(_nums) == 2:
  698. job_dict['cultivate_time'] = '%s-%02d~%s'%(_nums[0], int(_nums[1]), '至今')
  699. data_list[0] = re.sub(job_time[0], '', data_list[0])
  700. _list = data_list[0].split('|')
  701. if len(_list) >= 2:
  702. job_dict['cultivate_name'] = _list[0].strip()
  703. job_dict['cultivate_leval'] = _list[1].strip()
  704. job_dict['cultivate_content'] = re.sub('培培训训内内容容|培培训训内内容容::|培培训训内内容容::', '培训内容:', ''.join(data_list[1:]))
  705. else:
  706. job_dict['cultivate_content'] = re.sub('培培训训内内容容|培培训训内内容容::|培培训训内内容容::', '培训内容:', ''.join(data_list[0:]))
  707. #print(job_dict)
  708. '''
  709. return job_list
  710. # 语言能力
  711. def get_lag_list(lines):
  712. pprint(lines)
  713. job_list = []
  714. re_lan = re.compile(r'(\w+[语话])')
  715. lag_dict = {'lag_name':'', 'lag_leval':""}
  716. for l in lines:
  717. if not l.strip():
  718. continue
  719. lag_name = re.search(re_lan, l)
  720. if lag_name and lag_name.group(1):
  721. if lag_dict['lag_name']:
  722. job_list.append(lag_dict)
  723. lag_dict['lag_name'] = lag_name.group(1)
  724. return job_list
  725. # 家庭情况
  726. def get_fam_list(lines):
  727. job_list = []
  728. #re_txt = '\d+年\d+月\-\d+年\d+月|\d+年\d+月\-\~|\d+年\d+月[\-\~]至今|\d+-\d+\~\d+-\d+|\d+-\d+\~|\d+-\d+\~至今'
  729. fam_dict = {}
  730. for l in lines:
  731. if not l.strip():
  732. continue
  733. ls = l.split('|')
  734. if len(ls) == 1:
  735. continue
  736. fam_dict = {'fam_name':"",'fam_company':"",'fam_lable':"","fam_status":"", 'fam_job':""}
  737. fam_dict["fam_lable"] = ls[0].strip()
  738. fam_dict["fam_name"] = ls[1].strip()
  739. flag = 0
  740. if re.findall('\d岁|\d{4,5}', ls[2]):
  741. flag = 1
  742. fam_dict["fam_company"] = ls[flag+2].strip()
  743. fam_dict["fam_job"] = ls[flag+3].strip()
  744. fam_dict["fam_status"] = ls[flag+4].strip()
  745. #print(fam_dict)
  746. job_list.append(fam_dict)
  747. return job_list
  748. # 证书情况 时间+证书名称 (已完成)
  749. def get_cet_list(lines):
  750. pprint(lines)
  751. job_list = []
  752. re_txt = '\d+年\d+月|\d+-\d+|\d+\.\d+'
  753. lines_word = ' '.join(lines)
  754. lines = re.findall('\d+年\d+月|\d+-\d+|\d+\.\d+', lines_word)
  755. nums = []
  756. for x in range(len(lines) - 1):
  757. _index = lines_word.index(lines[x])
  758. _end_index = lines_word.index(lines[x+1])
  759. l = lines_word[_index : _end_index]
  760. if not l.strip():
  761. continue
  762. lines_word = lines_word[_end_index:]
  763. job_time = re.findall(re_txt, l)
  764. cet_dict = {'cet_name':'','cet_time':""}
  765. if job_time:
  766. cet_dict['prize_time'] = job_time[0]
  767. l = re.sub(job_time[0], '', l)
  768. else:
  769. continue
  770. ls = re.split('\||\040+|\t+', l)
  771. logging.debug(ls)
  772. for l in ls:
  773. if len(l) <= 3:
  774. continue
  775. cet_dict['prize_name'] = l.strip()
  776. break
  777. #print(cet_dict)
  778. job_list.append(cet_dict)
  779. return job_list
  780. # 获奖情况 时间+获奖名称 (已完成)
  781. def get_prize_list(lines):
  782. pprint(lines)
  783. job_list = []
  784. re_txt = '\d+年\d+月|\d+-\d+|\d{4,4}.\d{1,2}'
  785. lines_word = ' '.join(lines)
  786. lines = re.findall('\d+年\d+月|\d{4,4}-\d+|\d{4,4}.\d{1,2}', lines_word)
  787. nums = []
  788. for x in range(len(lines) - 1):
  789. _index = lines_word.index(lines[x])
  790. _end_index = lines_word.index(lines[x+1])
  791. l = lines_word[_index : _end_index]
  792. if not l.strip():
  793. continue
  794. lines_word = lines_word[_end_index:]
  795. job_time = re.findall(re_txt, l)
  796. cet_dict = {'prize_name':'','prize_time':""}
  797. if job_time:
  798. cet_dict['prize_time'] = job_time[0]
  799. l = re.sub(job_time[0], '', l)
  800. else:
  801. continue
  802. ls = re.split('\||\040+|\t+', l)
  803. logging.debug(ls)
  804. for l in ls:
  805. if len(l) <= 3:
  806. continue
  807. cet_dict['prize_name'] = l.strip()
  808. break
  809. logging.debug(cet_dict)
  810. job_list.append(cet_dict)
  811. return job_list
  812. # Linux doc 文件处理
  813. def doc2pdf_linux(docPath, pdfPath):
  814. """
  815. 允许的文档格式:doc,docx
  816. 仅在linux平台下可以
  817. 需要在linux中下载好libreoffice
  818. """
  819. # 注意cmd中的libreoffice要和linux中安装的一致
  820. cmd = 'libreoffice --headless --convert-to pdf'.split() + [docPath] + ['--outdir'] + [pdfPath]
  821. # cmd = 'libreoffice6.2 --headless --convert-to pdf'.split() + [docPath]
  822. p = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
  823. p.wait(timeout=30) # 停顿30秒等待转化
  824. stdout, stderr = p.communicate()
  825. if stderr:
  826. raise subprocess.SubprocessError(stderr)
  827. # Win32 doc 文件处理
  828. def doc2pdf(docPath, pdfPath, system):
  829. """
  830. 注意使用绝对路径
  831. pdf的生成只写路径,不写名字
  832. """
  833. docPathTrue = os.path.abspath(docPath) # bugfix - searching files in windows/system32
  834. if system == "Linux":
  835. return doc2pdf_linux(docPathTrue, pdfPath)
  836. # txt 纯文本解析(已完成)
  837. def parse_txt(path):
  838. with open(path, 'r', encoding='utf-8') as fp:
  839. data = fp.read()
  840. global block, block_rev
  841. chun = 1
  842. page = {1: []}
  843. if len(data.split("\n")) <= 2:
  844. for line in data.split("\n"):
  845. line = line.replace("\xa0", "").replace("【","").replace("】","").replace("教育/培训","教育经历")
  846. for word in line.split():
  847. if word in block.keys():
  848. chun = block[word]
  849. page[chun] = []
  850. elif word:
  851. page[chun].append(word)
  852. else:
  853. for line in data.split("\n"):
  854. line = line.replace("\xa0", "").replace("【","").replace("】","").replace("教育/培训","教育经历")
  855. regex = re.compile(u'[\u3000]+',re.UNICODE)
  856. line = regex.sub('', line)
  857. if line in block.keys():
  858. chun = block[line]
  859. page[chun] = []
  860. elif line:
  861. page[chun].append(line)
  862. for key in page.keys():
  863. for index, func in zip([1, 2, 3, 4, 5, 9, 10, 11, 12], [get_base_info, get_job_intention, get_edu_list, get_job_list, get_pro_list, get_lag_list, get_cet_list, get_prize_list, get_cultivate_list]):
  864. if key == index:
  865. console.print(block_rev[index], style="yellow", justify="left")
  866. console.print(func(page[index]), style="green", justify="left")
  867. # 纯文本 word 解析
  868. def read_from_word(doc):
  869. para_text = []
  870. for para in doc.paragraphs:
  871. para_text.append(para.text)
  872. global block, block_rev
  873. chun = 1
  874. page = {1: []}
  875. for line in para_text:
  876. regex = re.compile(u'[\uF000-\uF0FF]+',re.UNICODE)
  877. line = regex.sub('', line)
  878. if line in block.keys():
  879. chun = block[line]
  880. page[chun] = []
  881. elif line:
  882. page[chun].append(line)
  883. for key in page.keys():
  884. for index, func in zip([1, 2, 3, 4, 5, 10, 11, 12], [get_base_info, get_job_intention, get_edu_list, get_job_list, get_pro_list, get_cet_list, get_prize_list, get_cultivate_list]):
  885. if key == index:
  886. console.print(block_rev[index])
  887. try:
  888. console.print(func(page[index]), justify="left")
  889. except Exception as e:
  890. logging.error(e)
  891. return ''
  892. # 提取 word 表格(已完成)
  893. def check_word(path):
  894. doc = Document(path)
  895. tables = doc.tables
  896. if not tables:
  897. logging.info("this is raw text")
  898. read_from_word(doc)
  899. logging.info("this is a Table")
  900. prk = {"姓名":1, "性别":1, "出生年月":1, "民族":1, "籍贯":1, "户籍地":1, "政治面貌":1, "参加工作时间":1, "健康状况":1, "专业技术资格":1, "外语水平":9, "熟悉专业有何专长":8, "学历学位":1, "工作单位":1, "现任职务":1, "任职时间":1, "提职时间":1, "联系电话":1, "邮箱地址":1, "称谓":13, "工作单位及职务":1, "毕业时间、院校及专业":3,}
  901. block = {
  902. "个人信息":1, "基本信息":1, "个人简历":1, "基基本本信信息息":1, "基本信息基本信息":1, "基本信息文本内容":1,
  903. "求职意向":2, "求职意向求职意向":2, "期望工作文本内容":2,
  904. "教育背景":3, "教育经历":3, "教教育育经经历历":3, "教育经历教育经历":3, "教育经历文本内容":3, "学历学位":3,
  905. "工作经验":4, "主要工作内容与职责":4, "工作方面":4, "实习经历":4, "工作经历":4, "工工作作经经历历":4, "工作经历工作经历":4, "工作经历文本内容":4,
  906. "项目经历":5, "项目经验":5, "科研项目经历":5, "项项目目经经历历":5, "项目经历项目经历":5, "研究生参与代表性项目":5, "项目经历文本内容":5,
  907. "专业技能":6, "个人技能":6, "专业/外语技能":6, "技能素质":6, "个人技能文本内容":6,
  908. "自我评价":7, "个人简介":7, "个人评价":7, "自我描述":7, "自自我我评评价价":7, "自我评价自我评价":7, "自我评价文本内容":7,
  909. "兴趣爱好":8, "兴趣爱好文本内容":8,
  910. "语言及方言":9, "语言能力":9, "英语能力":9, "语语言言能能力力":9, "语言能力语言能力":9, "语言技能文本内容":9,
  911. "证书":10, "所获证书文本内容":10,
  912. "获得奖励":11, "获奖经历":11, "获奖情况":11, "获获奖奖经经历历":11, "获奖经历获奖经历":11, "获奖情况及社会活动":11, "校内奖励":11, "校内活动&奖励":11, "所获奖励文本内容":11,"奖惩情况":11,
  913. "培训":12, "培训经历":12, "培培训训经经历历":12, "培训经历文本内容":12,
  914. "家庭成员":13, "家家庭庭成成员员":13, "家庭成员家庭成员":13, "主要家庭成员及社会关系":13,
  915. "社会活动":"other", "实践经验":"other", "社会活动及社会实践":"other", "近三年年度考核结果":"other", "其他意愿":"other",
  916. }
  917. regex = re.compile(r'(\(\w{2,8}\))?((\w{2,8}))?')
  918. chun = 1
  919. page = {1: []}
  920. for table in tables:
  921. lo = {} # 存储每一行去重后的数据
  922. for row in range(0, len(table.rows)):
  923. row_list = []
  924. for col in range(0, len(table.row_cells(row))): # 提取row行的全部列数据
  925. row_list.append(regex.sub("", table.cell(row,col).text.replace(" ","").replace(":", ":").replace("学历\n学位","学历学位"))) # 去除字符串中的特殊字符,并添加到临时列表中
  926. lo[row] = (sorted(set(row_list), key=row_list.index)) # 在不变顺序的前提下,去除List中的重复项
  927. # 去除空项
  928. for key in lo.keys():
  929. if "" in lo[key]:
  930. lo[key].remove("")
  931. for _, line in lo.items():
  932. if (line[0] in block.keys()) or (line[0] in prk.keys()):
  933. # 包含大类目名
  934. if line[0] in block.keys():
  935. # 指向当前类目
  936. chun = block[line[0]]
  937. if not page.get(chun):
  938. page[chun] = []
  939. # 去除类目名
  940. line = '\n'.join(line[1:])
  941. # 包含小类目
  942. elif line[0] in prk.keys():
  943. # 指向当前类目
  944. chun = prk[line[0]]
  945. if not page.get(chun):
  946. page[chun] = []
  947. # 不去除
  948. line = '\n'.join(line)
  949. else:
  950. line = '\n'.join(line)
  951. # 标准化小类目
  952. for k in prk.keys():
  953. line = line.replace(k+"\n", k+":")
  954. page[chun].extend(line.split())
  955. for key in page.keys():
  956. for index, func in zip([1, 2, 3, 4, 5, 10, 11, 12], [get_base_info, get_job_intention, get_edu_list, get_job_list, get_pro_list, get_cet_list, get_prize_list, get_cultivate_list]):
  957. if key == index:
  958. console.print(block_rev[index])
  959. console.print(func(page[index]), justify="left")
  960. return ''
  961. # pdf 解析句子(已完成)
  962. def parse_line_layout(layout):
  963. texts = []
  964. """解析页面内容,一行一行的解析"""
  965. # bbox:
  966. # x0:从页面左侧到框左边缘的距离。
  967. # y0:从页面底部到框的下边缘的距离。
  968. # x1:从页面左侧到方框右边缘的距离。
  969. # y1:从页面底部到框的上边缘的距离
  970. for textbox in layout:
  971. if isinstance(textbox, LTTextBox) or isinstance(textbox, LTTextLine):
  972. for char in textbox:
  973. if isinstance(char, LTTextLineHorizontal):
  974. texts.append([char.bbox[0], char.bbox[3], char.get_text().strip()])
  975. # 按行排序
  976. texts.sort(key=lambda x:-x[1])
  977. # print(texts)
  978. global block, block_rev
  979. chun = 1
  980. page = {1: []}
  981. for _, _, line in texts:
  982. regex = re.compile(u'[\uF000-\uF0FF]+',re.UNICODE)
  983. line = regex.sub('', line)
  984. if line in block.keys():
  985. chun = block[line]
  986. page[chun] = []
  987. elif line:
  988. page[chun].append(line)
  989. return page
  990. # pdf 样式解析(已完成)
  991. def read_from_pdf(path):
  992. result = {}
  993. with open(path, 'rb') as in_file:
  994. parser = PDFParser(in_file) # 用文件对象来创建一个pdf文档分析器
  995. doc: PDFDocument = PDFDocument(parser) # 创建pdf文档
  996. rsrcmgr = PDFResourceManager() # 创建PDF,资源管理器,来共享资源
  997. # 创建一个PDF设备对象
  998. laparams = LAParams()
  999. device = PDFPageAggregator(rsrcmgr, laparams=laparams)
  1000. # 创建一个PDF解释其对象
  1001. interpreter = PDFPageInterpreter(rsrcmgr, device)
  1002. # 循环遍历列表,每次处理一个page内容
  1003. # doc.get_pages() 获取page列表
  1004. interpreter = PDFPageInterpreter(rsrcmgr, device)
  1005. # 处理文档对象中每一页的内容
  1006. # doc.get_pages() 获取page列表
  1007. # 循环遍历列表,每次处理一个page的内容
  1008. # 这里layout是一个LTPage对象 里面存放着 这个page解析出的各种对象 一般包括LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等等 想要获取文本就获得对象的text属性,
  1009. for page in PDFPage.create_pages(doc):
  1010. logging.debug('================ 新页面 ================')
  1011. interpreter.process_page(page)
  1012. layout = device.get_result()
  1013. r = parse_line_layout(layout)
  1014. for key in r.keys():
  1015. if result.get(key):
  1016. result[key].extend(r[key])
  1017. else:
  1018. result[key] = r[key]
  1019. block_rev = {1:"基本信息",2:"求职意向",3:"教育经历",4:"工作经历",5:"项目经历",6:"专业技能",7:"自我评价",8:"兴趣爱好",9:"语言能力",10:"证书",11:"获奖情况",12:"培训经历",13:"家庭成员","other":"其他"}
  1020. for key in result.keys():
  1021. for index, func in zip([1, 2, 3, 4, 5, 9, 10, 11, 12], [get_base_info, get_job_intention, get_edu_list, get_job_list, get_pro_list, get_lag_list, get_cet_list, get_prize_list, get_cultivate_list]):
  1022. if key == index:
  1023. console.print(block_rev[index])
  1024. console.print(func(result[index]), justify="left")
  1025. # try:
  1026. # console.print(func(result[index]), justify="left")
  1027. # except Exception as e:
  1028. # logging.error(e)
  1029. # pdf 表格解析 ()
  1030. def parse_table_from_pdf(path):
  1031. global block, block_rev
  1032. result = {}
  1033. with pdfplumber.open(path) as pdf:
  1034. for page in pdf.pages:
  1035. key = None
  1036. for table in page.extract_tables():
  1037. for line in table:
  1038. for word in line:
  1039. if not key:
  1040. key = word
  1041. else:
  1042. result[key] = word
  1043. key = None
  1044. for key in block.keys():
  1045. if result.get(key):
  1046. pprint({key: result[key]})
  1047. console.print(result)
  1048. # for key in result.keys():
  1049. # for index, func in zip([1, 2, 3, 4, 5, 10, 11, 12], [get_base_info, get_job_intention, get_edu_list, get_job_list, get_pro_list, get_cet_list, get_prize_list, get_cultivate_list]):
  1050. # if (key in block.keys()) and (block[key] == index):
  1051. # console.print(block_rev[index])
  1052. # try:
  1053. # console.print(func(result[index]), justify="left")
  1054. # except Exception as e:
  1055. # logging.error(e)
  1056. # break
  1057. # else:
  1058. # console.print({key: result[key]})
  1059. # break
  1060. return None
  1061. # 检测 pdf 格式 (已完成)
  1062. def check_pdf(path):
  1063. """
  1064. # 输入:
  1065. # pdf 文件路径
  1066. # 输出:
  1067. # 文件包含元素 [Word, Table]
  1068. """
  1069. rst = []
  1070. for page_layout in extract_pages(path):
  1071. for element in page_layout:
  1072. if isinstance(element, LTFigure):
  1073. for cell in element:
  1074. if isinstance(cell, LTChar):
  1075. rst.append("Table")
  1076. break
  1077. elif isinstance(element, LTTextContainer):
  1078. rst.append("Word")
  1079. return set(rst)
  1080. # 检测传入格式(已完成)
  1081. def detection_type(path, system):
  1082. # 传入目录
  1083. if os.path.isdir(path):
  1084. for filename in os.listdir(path):
  1085. filename = os.path.join(path, filename)
  1086. # 传入为 doc
  1087. logging.info(filename)
  1088. if filename.endswith('.doc') and not filename.startswith('.~'):
  1089. doc2pdf(docPath = filename, pdfPath = './', system=system)
  1090. # 传入为 docx
  1091. elif os.path.isfile(filename) and filename.endswith('.docx'):
  1092. check_word(filename)
  1093. # 传入为 pdf
  1094. if os.path.isfile(filename) and filename.endswith('.pdf'):
  1095. rst = check_pdf(filename)
  1096. if "Table" in rst:
  1097. parse_table_from_pdf(filename)
  1098. pass
  1099. if "Word" in rst:
  1100. read_from_pdf(filename)
  1101. # 传入为 txt
  1102. elif os.path.isfile(filename) and filename.endswith('.txt'):
  1103. parse_txt(filename)
  1104. # 传入为 doc
  1105. elif os.path.isfile(path) and path.endswith('.doc'):
  1106. doc2pdf(docPath = path, pdfPath = './', system=system)
  1107. # 传入为 docx
  1108. elif os.path.isfile(path) and path.endswith('.docx'):
  1109. check_word(path)
  1110. # 传入为 pdf
  1111. elif os.path.isfile(path) and path.endswith('.pdf'):
  1112. rst = check_pdf(path)
  1113. if "Table" in rst:
  1114. parse_table_from_pdf(path)
  1115. if "Word" in rst:
  1116. read_from_pdf(path)
  1117. # 传入为 txt
  1118. elif os.path.isfile(path) and path.endswith('.txt'):
  1119. parse_txt(path)
  1120. return None
  1121. if __name__ == '__main__':
  1122. import platform
  1123. system = platform.system()
  1124. if (system == "Windows"):
  1125. logging.info("Windows")
  1126. elif (system == "Linux"):
  1127. logging.info("Linux")
  1128. else:
  1129. logging.error("Unnot support this system")
  1130. # try:
  1131. # detection_type(sys.argv[1], system)
  1132. # except Exception as e:
  1133. # logging.error(e)
  1134. detection_type(sys.argv[1], system)
  1135. # detection_type('w1.pdf', system)