get_label_dic.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. @author: bidikeji
  5. @time: 2024/7/23 14:45
  6. """
  7. #!/usr/bin/env python3
  8. # -*- coding: utf-8 -*-
  9. """
  10. @author: bidikeji
  11. @time: 2024/7/11 17:56
  12. """
  13. from BiddingKG.dl.common.Utils import getUnifyMoney
  14. import re
  15. def chinese_to_arabic(s):
  16. # 中文数字到阿拉伯数字的映射
  17. num_map = {'零': 0, '一': 1, '二': 2, '两': 2, '三': 3, '四': 4,
  18. '五': 5, '六': 6, '七': 7, '八': 8, '九': 9}
  19. # 单位到倍数的映射
  20. unit_map = {'十': 10, '百': 100}
  21. # 初始化结果和当前数值
  22. result = 0
  23. current_num = 0
  24. has_unit = False
  25. if s.startswith('十'):
  26. result = 10
  27. # 遍历字符串
  28. for char in s:
  29. if char in num_map:
  30. # 如果是数字,则进行处理
  31. if has_unit:
  32. # 如果之前已经有单位了,则需要将当前数字乘以前面的单位
  33. result += current_num * unit_map[last_unit]
  34. current_num = num_map[char]
  35. has_unit = False
  36. else:
  37. # 如果之前没有单位,则直接累加
  38. current_num = current_num * 10 + num_map[char]
  39. elif char in unit_map:
  40. # 如果是单位,则标记为已有单位,并保存最后一个单位
  41. last_unit = char
  42. has_unit = True
  43. # 处理字符串末尾的数字(如果没有单位,则直接加上)
  44. if current_num != 0:
  45. if has_unit:
  46. result += current_num * unit_map[last_unit]
  47. else:
  48. result += current_num
  49. return result
  50. def get_all_label(title, content):
  51. def is_direct_procurement():
  52. # 企业直采
  53. if re.search('询比价|询比|竞价|竞价|议价|报价', title) or re.search('我要报价|竞价起止时间|报价起止时间', content) or \
  54. (re.search('公司|集团|企业', content) and re.search('招标|中标|投标', content) == None):
  55. return 1
  56. return 0
  57. def is_target_small():
  58. # 专门面向中小企业
  59. if re.search('专门面向中小微?企业', content) and re.search('(非|不属于|不|是/否))?专门面向中小微?企业|部分面向中小微?企业', content) == None:
  60. return 1
  61. elif re.search('仅面向小微企业|专门面向.{,30}中小企业采购|是否专门面向中小微?企业(采购)?:是|本项目为中小型企业预留项目|专门面向中小微?企业', content):
  62. return 1
  63. elif re.search('落实政府采购政策需满足的资格要求.{,30}供应商为中小企业', content) and re.search('(非|不属于|不|是/否))?专门面向中小微?企业|部分面向中小微?企业',
  64. content) == None:
  65. return 1
  66. return 0
  67. def registered_years():
  68. # 注册年限
  69. ser = None
  70. if re.search('禁止\w{,5}注册未满(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月))', content):
  71. ser = re.search('禁止\w{,5}注册未满(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月))', content)
  72. elif re.search('(成立|注册)时间:?\w{,10}(不[低少]于|大于(等于)?|需满)(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月))', content):
  73. ser = re.search('(成立|注册)时间:?\w{,10}(不[低少]于|大于(等于)?|需满)(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月))',
  74. content)
  75. elif re.search('(成立|注册)时间:?\w{,10}(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月)[或及]?以上)', content):
  76. ser = re.search('(成立|注册)时间:?\w{,10}(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月)[或及]?以上)', content)
  77. elif re.search('(成立|注册)时间:?\w{,10}不满(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月)\w{,5}请勿报价)', content):
  78. ser = re.search('(成立|注册)时间:?\w{,10}不满(?P<num>([一二三四五六七八九十]+|\d+))(?P<unit>(年|个?月)\w{,5}请勿报价)', content)
  79. if ser:
  80. num = ser.group('num')
  81. unit = ser.group('unit')
  82. if num.isdigit():
  83. num = int(num)
  84. else:
  85. num = chinese_to_arabic(num)
  86. if unit == '年':
  87. num *= 12
  88. return num
  89. return 0
  90. def registered_capital():
  91. # 注册资本
  92. ser = None
  93. if re.search('注册(资本|资金):?\w{,5}(不[低少]于|大于(等于)?|≥)(?P<num>(\d+[\d.]*))(?P<unit>([万亿]?元))', content):
  94. ser = re.search('注册(资本|资金):?\w{,5}(不[低少]于|大于(等于)?|≥)(?P<num>(\d+[\d.]*))(?P<unit>([万亿]?元))', content)
  95. elif re.search('注册(资本|资金):?\w{,5}(?P<num>(\d+[\d.]*))(?P<unit>([万亿]?元)[或及]?以上)', content):
  96. ser = re.search('注册(资本|资金):?\w{,5}(?P<num>(\d+[\d.]*))(?P<unit>([万亿]?元)[或及]?以上)', content)
  97. if ser:
  98. num = ser.group('num')
  99. unit = ser.group('unit')
  100. return float(getUnifyMoney(num + unit))
  101. return 0
  102. def need_qualification():
  103. # 有资质证书要求
  104. if re.search('资质要求.{,150}(行业资质|证书|许可证|认证|经营范围|一级|二级|三级|甲级|乙级|丙级|特级|壹级|贰级|叁级)', content):
  105. return 1
  106. elif re.search('(提供|有|具备)\w{,50}(资质|认证|证书|许可证)', content):
  107. return 1
  108. elif re.search('资格)?要求:?\w{,30}(甲级|丙级|乙级|一级|二级|三级|特级|壹级|贰级|叁级)', content):
  109. return 1
  110. elif re.search('认证体系要求', content):
  111. return 1
  112. return 0
  113. def need_ca():
  114. # 7 是否需要办CA
  115. if re.search('需要\w{,20}数字证书|使用\w{,20}签章', content):
  116. return 1
  117. elif re.search('办理\w{,20}(数字证书|CA|ca)', content) and re.search('无需\w{,15}办理', content) == None:
  118. return 1
  119. elif re.search('(数字证书|CA|ca)\w{,5}办理|是否要求供应商使用(CA|ca)数字证书参与:是', content):
  120. return 1
  121. if re.search('(不使用|无需)\w{,20}(数字证书|CA|ca)|是否要求供应商使用(CA|ca)数字证书参与:不要求', content):
  122. return 0
  123. return 0
  124. def need_performance():
  125. # 有业绩要求
  126. if re.search('业绩证明|业绩要求|行业业绩|相关业绩', content):
  127. return 1
  128. elif re.search('类似\w{,10}业绩', content) or re.search('业绩.{,5}如有', content) == None:
  129. return 1
  130. elif re.search('完成[^,。]{,100}项目', content):
  131. return 1
  132. elif re.search('(提供|有|完成).{,100}业绩', content):
  133. return 1
  134. return 0
  135. def mode_of_partipation():
  136. # 参与方式 1线上 2线下 0其他
  137. if re.search('(平台|网站|http|www|官网|网址|网页|网上中介|邮件|邮箱|客户端|采购网|系统|邮寄).{,20}(注册|报名)', content):
  138. return 1
  139. elif re.search('现场报名', content):
  140. if re.search(
  141. '非现场报名|(在线报名|邮件|邮寄|邮箱|线上报名|网络报名).{,10}现场报名|现场报名.{,10}(在线报名|邮件|邮寄|邮箱|线上报名|网络报名)', content) == None:
  142. return 1
  143. return 2
  144. elif re.search('(获取采购文件|文件的获取|文件获取|获取竞价文件|获取招标文件|文件的领取|文件领取|获取投标文件).{,200}'
  145. '(平台|线上|客户端|邮寄|网上获取|网站|网址|http|www|邮箱|寄送|网络获取|采购网|网络领购|系统|邮件|在线报名|网络报名|非现场报名|线上报名)', content):
  146. return 1
  147. elif re.search('(获取采购文件|文件的获取|文件获取|获取竞价文件|获取招标文件|文件的领取|文件领取|获取投标文件).{,200}'
  148. '([\d一二三四五六七八九十]号|接待室|开标室|现场领取|会议室|线下购买|现场获取|X[\d一二三四五六七八九十]|办公楼|现场报名)', content):
  149. return 2
  150. elif re.search('(报价地址|报价信息|报价请点击|报价方法|报价式|报价方式|报价提交|报价地点).{,30}'
  151. '(平台|网站|http|www|官网|网址|网页|网上中介|邮件|邮箱|客户端|采购网|系统|在线报价|线上报价)', content):
  152. return 1
  153. elif re.search('线下报价', content) and re.search('不接受线下报价|线下报价无效', content) == None:
  154. return 2
  155. elif re.search('(文件提交|文件递交|递交方式|文件的提交|文件送达地点|递交响应文件|证明材料的递交)', content):
  156. b = re.search('(文件提交|文件递交|递交方式|文件的提交|文件送达地点|递交响应文件|证明材料的递交)', content).end()
  157. ser = re.search('联系方式|发布公告的媒介', content[b:b + 200])
  158. text = content[b:b + ser.start()] if ser else content[b:b + 200]
  159. if re.search('平台|线上|客户端|邮寄|网站|网址|http|www|邮箱|寄送|采购网|系统|邮件|网页', text):
  160. return 1
  161. elif re.search('[\d一二三四五六七八九十]号|接待室|现场递交|开标室|会议室|[\d一二三四五六七八九十]楼|线下递交|办公楼', text):
  162. return 2
  163. if re.search('(平台|线上|客户端|网站|网址|http|www|采购网|系统|网页).{,10}递交.{,10}文件', content):
  164. return 1
  165. if re.search('(开标地点|投标地点|开标时间和地点|开标时间及地点|开标方式)', content):
  166. b = re.search('(开标地点|投标地点|开标时间和地点|开标时间及地点|开标方式)', content).end()
  167. ser = re.search('联系方式|发布公告的媒介', content[b:b + 70])
  168. text = content[b:b + ser.start()] if ser else content[b:b + 70]
  169. if re.search(
  170. '平台|线上|客户端|网站|网址|http|www|线上开标|采购网|非现场开标|不见面开标|远程异地开启|系统|线上观看开标|网上开标|在线直播的方式开标|远程开标|现场开启|电子卖场|电子开标|开标现场电话联系',
  171. text):
  172. return 1
  173. elif re.search('[\d一二三四五六七八九十]号|线下开标|接待室|现场递交|开标室|现场开标|会议室|[\d一二三四五六七八九十]楼|办公楼|街道', text):
  174. return 2
  175. if re.search('(平台|线上|客户端|网站|网址|http|www|采购网|系统|网页).{,10}开标', content):
  176. return 1
  177. elif re.search('不见面开标|非现场开标|远程异地开启|线上观看开标|网上开标|在线直播的方式开标|远程开标|现场开启|非公开开启|电子开标|开标现场电话联系', content):
  178. return 1
  179. elif re.search('开启.{,20}地点', content):
  180. b = re.search('开启.{,20}地点', content).end()
  181. ser = re.search('联系方式|发布公告的媒介', content[b:b + 70])
  182. text = content[b:b + ser.start()] if ser else content[b:b + 70]
  183. if re.search(
  184. '平台|线上|客户端|网站|网址|http|www|线上开标|采购网|非现场开标|不见面开标|远程异地开启|系统|线上观看开标|网上开标|在线直播的方式开标|远程开标|电子卖场|电子开标|开标现场电话联系',
  185. text):
  186. return 1
  187. elif re.search('[\d一二三四五六七八九十]号|线下开标|接待室|现场递交|开标室|现场开标|会议室|[\d一二三四五六七八九十]楼|办公楼|街道', text):
  188. return 2
  189. return 0
  190. def suitable_small():
  191. # 适合小微企业投标
  192. if re.search('属于专门面向中小企业|有招标单位联系方式|无注册年限要求|无注册资本要求|无资质证书要求|无业绩要求', content):
  193. return 1
  194. elif re.search('属于企业直采|有招标单位联系方式|无注册年限要求|无注册资本要求|无资质证书要求|无业绩要求', content):
  195. return 2
  196. elif re.search('有招标单位联系方式|无注册年限要求|无注册资本要求|无资质证书要求|无业绩要求', content):
  197. return 3
  198. return 0
  199. label_dic = {}
  200. is_direct_procurement = is_direct_procurement() # 是否直接采购
  201. is_target_small = is_target_small() # 是否面向中小企业
  202. mode_of_partipation = mode_of_partipation() # 参与方式
  203. need_ca = need_ca() # 是否需要CA
  204. need_performance = need_performance() # 有业绩要求
  205. need_qualification = need_qualification() # 资质要求
  206. registered_capital = registered_capital() # 注册资本
  207. registered_years = registered_years() # 注册年限
  208. suitable_small = suitable_small() # 适合小微企业
  209. label_dic['is_direct_procurement'] = is_direct_procurement
  210. label_dic['is_target_small'] = is_target_small
  211. label_dic['mode_of_partipation'] = mode_of_partipation
  212. label_dic['need_ca'] = need_ca
  213. label_dic['need_performance'] = need_performance
  214. label_dic['need_qualification'] = need_qualification
  215. label_dic['registered_capital'] = registered_capital
  216. label_dic['registered_years'] = registered_years
  217. label_dic['suitable_small'] = suitable_small
  218. label_dic = {k: v for k, v in label_dic.items() if v!=0}
  219. return label_dic
  220. if __name__ == "__main__":
  221. # with open('D:\html/2.html', 'r', encoding='UTF-8') as f:
  222. # html = f.read()
  223. # rs = get_all_label('', html)
  224. # print('rs: ', rs)
  225. import pandas as pd
  226. from bs4 import BeautifulSoup
  227. import json
  228. df = pd.read_csv(r'E:\channel分类数据\2022年每月两天数据/指定日期_html2022-12-10.csv')[:]
  229. print(df.columns, len(df))
  230. df.drop_duplicates(subset=['docchannel', 'web_source_name', 'exist_table'], inplace=True)
  231. print(len(df))
  232. def get_text(html):
  233. soup = BeautifulSoup(html, 'lxml')
  234. text = soup.get_text()
  235. return text
  236. df['content'] = df['dochtmlcon'].apply(lambda x: get_text(x))
  237. df['标签'] = df.apply(lambda x: get_all_label(x['doctitle'], x['content']), axis=1)
  238. df['标签'] = df['标签'].apply(lambda x: json.dumps(x, ensure_ascii=False, indent=2))
  239. df = df[['docid', 'docchannel', 'web_source_name', 'exist_table', '标签']]
  240. df.to_excel('E:/公告标签提取结果.xlsx', index=False)