浏览代码

first commit

lijunliang 1 年之前
当前提交
5f6551555f
共有 77 个文件被更改,包括 6576 次插入0 次删除
  1. 31 0
      README.md
  2. 145 0
      app.py
  3. 4 0
      clear.py
  4. 47 0
      client.py
  5. 二进制
      docs/__pycache__/config.cpython-37.pyc
  6. 67 0
      docs/config.py
  7. 31 0
      docs/table_head_doc/abnormal_buyer_begin.csv
  8. 39 0
      docs/table_head_doc/abnormal_buyer_contain.csv
  9. 57 0
      docs/table_head_doc/abnormal_buyer_end.csv
  10. 342 0
      docs/table_head_doc/amount_label.csv
  11. 408 0
      docs/table_head_doc/budget_label.csv
  12. 1998 0
      docs/table_head_doc/field_label.csv
  13. 128 0
      docs/table_head_doc/general_label.csv
  14. 119 0
      docs/table_head_doc/projectcode.csv
  15. 二进制
      docs/table_head_doc/table_head_clf_model
  16. 二进制
      docs/table_head_doc/table_head_le
  17. 二进制
      docs/table_head_doc/table_head_vocab
  18. 二进制
      docs/乡镇.xlsx
  19. 二进制
      docs/区县.xlsx
  20. 二进制
      docs/市.xlsx
  21. 二进制
      docs/省份.xlsx
  22. 75 0
      quality_server.py
  23. 38 0
      score.py
  24. 90 0
      tables/__init__.py
  25. 二进制
      tables/__pycache__/__init__.cpython-37.pyc
  26. 83 0
      tables/ai/__init__.py
  27. 二进制
      tables/ai/__pycache__/__init__.cpython-37.pyc
  28. 二进制
      tables/ai/__pycache__/table_field_category.cpython-37.pyc
  29. 181 0
      tables/ai/table_field_category.py
  30. 244 0
      tables/fields/NoField.py
  31. 15 0
      tables/fields/__init__.py
  32. 二进制
      tables/fields/__pycache__/NoField.cpython-37.pyc
  33. 二进制
      tables/fields/__pycache__/__init__.cpython-37.pyc
  34. 二进制
      tables/fields/__pycache__/area.cpython-37.pyc
  35. 二进制
      tables/fields/__pycache__/bidamount.cpython-37.pyc
  36. 二进制
      tables/fields/__pycache__/budget.cpython-37.pyc
  37. 二进制
      tables/fields/__pycache__/buyer.cpython-37.pyc
  38. 二进制
      tables/fields/__pycache__/fieldtype.cpython-37.pyc
  39. 二进制
      tables/fields/__pycache__/projectcode.cpython-37.pyc
  40. 二进制
      tables/fields/__pycache__/projectname.cpython-37.pyc
  41. 二进制
      tables/fields/__pycache__/purchasing.cpython-37.pyc
  42. 二进制
      tables/fields/__pycache__/subpackage.cpython-37.pyc
  43. 二进制
      tables/fields/__pycache__/title.cpython-37.pyc
  44. 二进制
      tables/fields/__pycache__/winner.cpython-37.pyc
  45. 80 0
      tables/fields/area.py
  46. 53 0
      tables/fields/bidamount.py
  47. 53 0
      tables/fields/budget.py
  48. 312 0
      tables/fields/buyer.py
  49. 43 0
      tables/fields/content.py
  50. 106 0
      tables/fields/fieldtype.py
  51. 132 0
      tables/fields/projectcode.py
  52. 90 0
      tables/fields/projectname.py
  53. 369 0
      tables/fields/purchasing.py
  54. 24 0
      tables/fields/subpackage.py
  55. 92 0
      tables/fields/title.py
  56. 290 0
      tables/fields/winner.py
  57. 31 0
      test.py
  58. 0 0
      test.txt
  59. 1 0
      util/README.md
  60. 二进制
      util/__pycache__/dictionary.cpython-37.pyc
  61. 二进制
      util/__pycache__/fs_client.cpython-37.pyc
  62. 二进制
      util/__pycache__/get_region.cpython-37.pyc
  63. 二进制
      util/__pycache__/htmltag.cpython-37.pyc
  64. 二进制
      util/__pycache__/mogodb_helper.cpython-37.pyc
  65. 二进制
      util/__pycache__/sensitive_word.cpython-37.pyc
  66. 146 0
      util/dictionary.py
  67. 87 0
      util/fs_client.py
  68. 81 0
      util/get_region.py
  69. 78 0
      util/htmltag.py
  70. 26 0
      util/info_preprocess/__init__.py
  71. 二进制
      util/info_preprocess/__pycache__/__init__.cpython-37.pyc
  72. 二进制
      util/info_preprocess/__pycache__/attach_preprocess.cpython-37.pyc
  73. 二进制
      util/info_preprocess/__pycache__/html_preprocess.cpython-37.pyc
  74. 53 0
      util/info_preprocess/attach_preprocess.py
  75. 91 0
      util/info_preprocess/html_preprocess.py
  76. 76 0
      util/mogodb_helper.py
  77. 120 0
      util/sensitive_word.py

+ 31 - 0
README.md

@@ -0,0 +1,31 @@
+# 剑鱼数据质量检查
+
+## 一、功能
+1、标讯字段有选择性(错误)检查
+
+2、标讯整体评估
+
+
+## 二、函数说明
+> 1、from tables import CatchContentObject
+
+>> 1.CatchContentObject为行中间结果存储而设立,后续需要其它公用的结果可以存储。举例:
+
+>>  正文标签清理,附件标签清理。当第一个字段使用以后,后续字段可以直接使用缓存
+
+>> 2.固定名称类型:
+
+>> 入参数名称:catch_content
+
+>> 入参数类型:CatchContentObject
+
+> 2、check_params
+
+>> 1.多参数结果方案,虽然检查的是单字段,但是检查需求的字段数量是不同的。规范如下
+
+>> def check0101(budget: float, bidamount: float)
+
+>> budget 入参数的名称与标讯的名称保持一致。或等于catch_content 
+
+>> budget==>float  入参类型检查的必要条件,当前默认不启用参数类型检查
+

文件差异内容过多而无法显示
+ 145 - 0
app.py


+ 4 - 0
clear.py

@@ -0,0 +1,4 @@
+with open("test.txt","w") as f:
+    for row in f.readlines():
+        if "工程" in row or "服务" in row or"新建" in row:
+            print(row)

文件差异内容过多而无法显示
+ 47 - 0
client.py


二进制
docs/__pycache__/config.cpython-37.pyc


+ 67 - 0
docs/config.py

@@ -0,0 +1,67 @@
+# 表头识别模型
+ai2config = {
+    "table_field_config": {
+        "corpus_path": "./docs/table_head_doc/field_label.csv",
+        "vocab_file": './docs/table_head_doc/table_head_vocab',
+        "vocab_label": './docs/table_head_doc/table_head_le',
+        "epochs": 4000,
+        "lr": 1e-2,
+        "momentum": .8,
+        "model_path": './docs/table_head_doc/table_head_clf_model'
+    }}
+amount_config = {
+    "table_field_config": {
+        "path": "./docs/table_head_doc/amount_label.csv",
+    }}
+budget_config = {
+    "table_field_config": {
+        "path": "./docs/table_head_doc/budget_label.csv",
+    }}
+general_config = {
+    "table_field_config": {
+        "path": "./docs/table_head_doc/general_label.csv",
+    }}
+abnormal_config = {
+    "table_field_config": {
+        "path1": "./docs/table_head_doc/abnormal_buyer_begin.csv",
+        "path2": "./docs/table_head_doc/abnormal_buyer_contain.csv",
+        "path3": "./docs/table_head_doc/abnormal_buyer_end.csv",
+        "path4": "./docs/table_head_doc/projectcode.csv",
+    }}
+
+# 调试
+DEBUG = True
+
+# 字段识别模型
+FieldServer = {
+    "a2s_ip": "192.168.3.240:9090",
+    "topic": "goods_field",
+    "timeout": 60,
+    "retry_times": 5,
+}
+
+# 组织机构识别模型
+RecognitionServer = {
+    "a2s_ip": "192.168.3.240:9090",
+    "topic": "recognition_org",
+    "timeout": 60,
+    "retry_times": 5,
+}
+
+# 产品识别模型
+ProductServer = {
+    "a2s_ip": "192.168.3.240:9090",
+    "topic": "recognition_goods",
+    "timeout": 60,
+    "retry_times": 5,
+}
+
+# update_urls_mongodb
+
+ReluMongodb = {
+    "ip_port": "192.168.3.71:29099",
+    "user": "",
+    "password": "",
+    "db": "re4art",
+    "col": "quality",
+}

+ 31 - 0
docs/table_head_doc/abnormal_buyer_begin.csv

@@ -0,0 +1,31 @@
+一
+二
+一中学
+一公司
+二完全
+一个
+一贯制
+后勤
+一楼
+位于
+一致
+选定
+应
+依法
+口国
+代表
+这
+逝沮省
+上半年
+第一
+一次性
+门市
+配套
+八月
+七月
+集回
+维修
+遴选
+但
+口
+增加

+ 39 - 0
docs/table_head_doc/abnormal_buyer_contain.csv

@@ -0,0 +1,39 @@
+第一轮
+第一次
+第一词
+第一季
+各学校
+第一批
+完全学校
+一致同意
+X
+保体障局
+人们政府
+校医院
+上设局
+后勤
+开发茎
+场场
+设保
+武鳖
+集回
+项日
+代理银行
+病院
+辽宁省省会
+菖处
+口国共产党
+中华人民共口国
+口国人毛
+口国
+口国铁塔股份
+人民汰院
+肉州市
+有限公司厂
+()
+()
+火车站社
+自然资源和规局
+村民委会
+萎员会
+经济技术开发茎

+ 57 - 0
docs/table_head_doc/abnormal_buyer_end.csv

@@ -0,0 +1,57 @@
+院院
+局局
+场场
+小学室
+和社
+人屡政府
+谈话室
+小区局
+今作社
+点场
+人昆政府
+年度室
+分行银行
+人政府
+民政府
+人民矢院
+教学楼局
+笺理局
+地场
+人民唉院
+瞥理局
+所院
+农业衣村局
+民丢局
+委员会老干部
+办非处
+等支局
+监督站局
+停车库局
+检查员
+办直处
+进行局
+楼局
+等局
+人民政府社
+模块局
+人民政俯
+人民医标院
+农业农局
+园局
+规则局
+人乓政府
+人事条局
+箐理所
+在政府
+重点局
+大学入场
+入场
+发也站
+赘源局
+计划生育服务中心政府
+第一人民吹院
+有限公司室
+教标育局
+一民政府
+场部
+埋局

+ 342 - 0
docs/table_head_doc/amount_label.csv

@@ -0,0 +1,342 @@
+"总合计"
+"总计"
+"成交总金额(元)"
+"成交总金额(元)"
+"总中标金额"
+"总中标成交金额"
+"中标金额"
+"中标金额(万元/人民币)"
+"总价(人民币)大写"
+"合同总金额(万元)"
+"总中标金额(元)"
+"中标(成交金额)"
+"最终中标价(元)"
+"预期中选价(元)"
+"投标报价(元/费率)"
+"投标报价(元)/下浮率"
+"中标估算价(元)"
+"中标估算价"
+"中标价(万元)"
+"中标、成交金额(元)"
+"中标价(费率或单价等)"
+"总成交额(单位:元)"
+"合同金额(元)"
+"成交价格(元)"
+"成交总价(人民币:元)"
+"中标金额(元)"
+"预中标价(元)"
+"中标价(元)"
+"承包价"
+"中选报价"
+"中标值"
+"成交(中标)总金额"
+"总报价(人民币)"
+"总报价"
+"中标价(元)"
+"中标(成交)金额"
+"中标(成交)金额"
+"中标(成交)金额(元)"
+"中标价(万元)"
+"中标价(万元)"
+"中标金额/元"
+"成交结果"
+"成交金额(含增值税)"
+"成交金额(元)"
+"订单总价(元)"
+"总价(元)"
+"最终价格(元)"
+"投标总价(万元)"
+"订单总价"
+"总价(元)"
+"总价(含增值税价)"
+"订单总价(元)"
+"中选金额"
+"总成交金额(元)"
+"成交金额(元)"
+"总成交额"
+"中标总金额"
+"中标成交金额"
+"中标成交价"
+"中标价"
+"中包价"
+"中标总价"
+"合计(元)"
+"中标标价"
+"中标工程金额"
+"中标工程价格"
+"中标价格"
+"中标供应价"
+"中标单位中标价"
+"中标供应商名称及金额"
+"中标供应商名称及中标金额"
+"中标供应商及中标金额"
+"中标供应商信息"
+"中标成交供应商名称及中标金额"
+"中标供应商中标金额"
+"中标单位及中标金额"
+"中标单位名称及中标金额"
+"中标价合计金额"
+"成交价(元)"
+"采购价格"
+"成交单位金额"
+"投标价格"
+"中标供货商金额"
+"中标候选人投标金额"
+"中标候选人金额"
+"预中标价(元)"
+"【中标或者成交金额】"
+"中标(成交)金额(单位"
+"每包中标金额"
+"每包中标金额合计"
+"每包成交金额"
+"成交额"
+"中标人中标价"
+"预期中标价(元)"
+"第一中标金额"
+"第一中标候选人金额"
+"成交总额"
+"总成交金额"
+"成交总金额"
+"成交金额"
+"成交总价(万元)"
+"成交总价"
+"成交价格"
+"成交项目金额"
+"成交供应商名称及成交金额"
+"成交供应商和成交总金额"
+"成交供应商成交价"
+"成交人成交价"
+"成交价"
+"成交信息成交价"
+"成交报价"
+"确定成交报价"
+"成交总报价"
+"成交年租金"
+"成交结果成交价"
+"成交信息金额"
+"拟成交金额"
+"采购结果总金额"
+"投标总金额"
+"投标总额"
+"经评审的投标价"
+"投标报价"
+"投标报价总价"
+"投标金额"
+"投标报价金额"
+"投标总报价"
+"报价总金额"
+"报价总额"
+"成交\n金额"
+"成交\t金额"
+"报价金额"
+"中选价格"
+"中选价"
+"最终成交金额"
+"成交供应商(投标报价)"
+"报价"
+"投标价(万元)"
+"报标价(万元)"
+"拟成交价格"
+"拟成交价"
+"拟成交价(元)"
+"拟中标金额"
+"项目中标金额"
+"项目成交金额"
+"含税成交价格"
+"含税成交价"
+"含税加权单价合计"
+"预中标价格"
+"供应商报价"
+"合同金额"
+"询价成交金额"
+"采购结果成交价"
+"谈判成交金额"
+"最终成交价"
+"磋商成交金额"
+"拟定中标金额"
+"预成交金额"
+"预期成交价(元)"
+"预中标价"
+"预中标金额"
+"预中标人中标金额"
+"预计中标金额"
+"预计成交金额"
+"最终报价"
+"最终报价总价"
+"总价报价"
+"合计总金额"
+"预期中标价"
+"预成交价格"
+"预中标额"
+"预成交价"
+"地址及成交金额"
+"合同总金额"
+"合同总金"
+"中标报价"
+"投标价"
+"成交供应商名称、地址和成交金额地址"
+"中标供应商名称及中标价格"
+"结果价"
+"中标结果"
+"成交价款"
+"现更正为:中标价"
+"含税投标报价"
+"最高报价成交金额"
+"成交人及价格"
+"合同价(万元)"
+"合同价款"
+"中标造价"
+"中标工程总造价"
+"工程报价"
+"拟中标价"
+"中标价款"
+"中标额"
+"预中标总价(元)"
+"合同价(万元)"
+"成交报价小写金额"
+"承包标价"
+"验收金额"
+"验收金额(元)"
+"评标价(万元)"
+"投标总价"
+"投标总价合计"
+"采购合同金额(元)"
+"最终报价(元)"
+"成交金额¥"
+"拟中标价格(万元)"
+"拟中标价格为"
+"投标报价(万元)"
+"投标报价(元)"
+"投标报价(元)"
+"投标报价(万元)"
+"投标报价(万元)"
+"中标价(元)/费率"
+"投标报价/费率/其他形式报价"
+"中标价格(元)"
+"中标价格(元)/费率"
+"第1中标金额"
+"入围报价"
+"中标价(万元)\\费率(%)"
+"投标价(元)/费率(%)"
+"中标价(元)/费率(%)"
+"中标价√(元)\\费率(%)"
+"中标价eq\\o\\ac(□√)√(元)\\□费率(%)"
+"本工程交易价为人民币"
+"拟交易价格"
+"中标单价(元)"
+"中标单价"
+"中标金额(人民币:万元)/年"
+"中标金额(人民币万元)/年"
+"中标人信息"
+"投标报价(元/%)"
+"中标价(万元|%)"
+"总价/优惠率"
+"建安费(万元)"
+"可行性缺口补助现值总和(元)"
+"追加金额"
+"合同价格(元)"
+"投资总金额"
+"中标、成交金额(万元)"
+"中标人价格"
+"中标金额(含税/元)"
+"拟中标总金额(元)"
+"成交价含税(元)"
+"中标结果金额"
+"中标(成交)价(元/%)"
+"合同价(元)"
+"合同价"
+"立项金额(万元)"
+"成交金额(元人民币)"
+"中标(成交)金额(万元)"
+"第1名投标报价"
+"成交价不含税(元)"
+"中标总额"
+"成交价格(万元)"
+"中标价格(万元)"
+"最终中标价(元)"
+"合同结算金额(元)"
+"总成交额(元)"
+"合同结算金额"
+"成交金额(万元)"
+"总中标总金额"
+"中标(成交)价格(元)"
+"中标总价(万元)"
+"实际采购总金额"
+"签约合同价(其他价格形式)"
+"合同金额(万元)"
+"合同金额(万元)"
+"中标金额(万元)"
+"成交总额(元)"
+"成交总价(万元)"
+"中标金额(元/优惠率)"
+"计划批文总投资额"
+"中标价格(元)"
+"签约合同价(元)"
+"签约合同价"
+"签约合同价(元)"
+"签约合同价为"
+"签约合同价(含税)为"
+"合同估算价"
+"合同结算金额(元)"
+"中标价(万元)"
+"中标总金额(元)"
+"合同总价款(人民币小写)"
+"中标价(元)"
+"合同总额(元)"
+"成交总价(元)"
+"中标(成交)金额(元)"
+"成交金额(万元)"
+"中标(成交)金额(元)\\(%)"
+"中标金额(元)"
+"中标金额(万元)"
+"合同金额(元)"
+"投标报价(人民币万元)"
+"投标报价(人民币万元)"
+"报价总额(元)"
+"报价总额(元)"
+"投标总报价\n(元)"
+"评标价"
+"合价"
+"合同金额小写"
+"合同暂定金额"
+"报价(万元)"
+"含税总价"
+"含税总报价"
+"项目总价(元)"
+"折后金额"
+"总造价(万元)"
+"各包中标/成交候选供应商及报价"
+"竞价总价"
+"中标总价合计"
+"项目中包金额"
+"标段报价"
+"有效投标价"
+"应答含税总价"
+"标的价格总计"
+"含增值税中标金额"
+"中标价(含增值税)"
+"有效报价总价"
+"报价总价"
+"竞价总报价"
+"中标总报价"
+"含税中标价"
+"中选总价"
+"投标报价投标费率"
+"投标报价(元)/投标费率(%)"
+"投标报价/投标费率"
+"中标价(元)/费率(%)"
+"报价/费率"
+"合同金额或者费率"
+"中标价(总价(元))"
+"含增值税价总金额"
+"含增值税总价"
+"中选含税报价"
+"中标含税价(元)及税率"
+"含增值税单价"
+"不含税中标金额"
+"不含增值税总金额"
+"不含税投标价(元)"
+"第一中标候选人报价"
+"成交工时价"
+"中选人报价(元)"
+"拟中商报价"

+ 408 - 0
docs/table_head_doc/budget_label.csv

@@ -0,0 +1,408 @@
+"采购总资金"
+"预算合计金额(人民币/元)"
+"采购项目预算金额(元)"
+"预算批复金额"
+"项目招标预算金额"
+"预算金额(人民币:元)"
+"预算金额(人民币万元)"
+"预算金额(万元)"
+"预算金额(元)"
+"最高投标限价"
+"项目财政预算"
+"投标总价(元)"
+"总预算"
+"总估算价"
+"总投资估算"
+"投标最高限价"
+"投标最高限价(元)"
+"预算(万元)"
+"预算(元)"
+"预算金额(万元)"
+"采购总预算(元)"
+"预算投资"
+"投标最高限价(元)"
+"本项目预算金额/最高限价"
+"采购预算(万元)"
+"采购限额"
+"预算"
+"预算(元)"
+"預算"
+"预算额"
+"概算金额"
+"概算金额(万元)"
+"最高投标限价(元)"
+"最高投标限价(万元)"
+"最高投标限价(元)"
+"预估总金额"
+"预估含税金额"
+"资金预算"
+"招标预算"
+"采购计划金额(元)"
+"项目预估投资额或规模"
+"预算合计"
+"总预算价"
+"招标控制总价"
+"招标控制金额"
+"包组预算合计"
+"分包控制金额"
+"政府采购预算"
+"投资预算金额"
+"投资预算"
+"最高采购限价"
+"控制预算"
+"估算金额"
+"采购估算金额"
+"估算金额(万元)"
+"项目估算招标金额"
+"分包预算"
+"分包预算金额"
+"标包概算金额"
+"标段合同估算价"
+"标段预算金额"
+"各标段预算金额"
+"采购总预算"
+"合同估算价"
+"合同估算价(元)"
+"估算价"
+"估算价(元)"
+"估算价(万元)"
+"预算内"
+"预算金额"
+"项目概算总投资"
+"本标段最高限价"
+"本标段采购预算"
+"本采购项目总预算金额"
+"预算金额总计"
+"预算总投资"
+"预算控制金额"
+"预算总金额"
+"预算总金额(元)"
+"采购预算金额"
+"采购预算金额(万元)"
+"采购预算金额(元)"
+"采购预算(元)"
+"采购预算控制额度"
+"采购预算及资金来源"
+"招标项目预算金额"
+"标段招标控制价"
+"预算总额(元)"
+"预算总额"
+"预算资金"
+"预算控制额度"
+"采购预算合计"
+"预算费用"
+"投资估算额"
+"财政预算资金"
+"采购控制价金额"
+"采购预算"
+"采购预算单价总和"
+"项目总预算控制价"
+"项目采购预算价"
+"预金额"
+"含税预算"
+"每包控制金额"
+"釆购项目预算金额"
+"项目预算"
+"项目预算(万元)"
+"项目预算(元)"
+"预算造价"
+"本项目的招标控制价"
+"本标段投资额"
+"本标项目的招标控制金额"
+"采购预算总价"
+"预算总价(万元)"
+"采购预算总价(万元)"
+"采购有效期内年度预算"
+"项目采购预算"
+"项目预算资金"
+"预测金额"
+"预算采购金额"
+"预算金额金额"
+"采购预算价"
+"采购预算及最高限价"
+"预算金额(最高限价)"
+"总预算金额"
+"控制价"
+"控制价(元)"
+"控制价(万元)"
+"预算内资金"
+"预算项目总金额"
+"项目预算金额"
+"预算金额合计"
+"预算金额*"
+"项目概算"
+"预算采购额"
+"项目总预算"
+"计划投资"
+"计划投资(万元)"
+"投资金额"
+"总投资金额"
+"概算投资"
+"概算投资金额"
+"预算价格"
+"预算价"
+"预算价(元)"
+"预算价(万元)"
+"预算(万元)"
+"预算总价"
+"预算总价(元)"
+"总预算资金"
+"总投资"
+"预估金额"
+"预估金额(含税)"
+"预算单价"
+"预成交金额"
+"项目主要内容及采购预算金额"
+"项目政府采购预算价"
+"政府采购预算价"
+"采购总预算金额"
+"项目投资概算"
+"项目投资"
+"项目内容及预算控制金额"
+"项目内容及预算金额"
+"项目金额"
+"采购预算单价"
+"采购预算额度"
+"采购项目预算金额"
+"采购项目预算总金额"
+"采购项目预算"
+"采购内容及金额"
+"采购控制金额"
+"采购金额"
+"采购预算总金额"
+"采购预算资金"
+"采购限价"
+"采购限价(元)"
+"不含税预算"
+"预算金"
+"预算金额或上限价"
+"采购概算"
+"招标控制价"
+"招标控制价(元)"
+"招标控制价(万元)"
+"项目招标控制价"
+"确定招标控制价为"
+"投资总额"
+"工程概算投资(万元)"
+"投资总额(万元)"
+"投资规模"
+"投资概算"
+"投资额度"
+"投资额"
+"本招标投资额"
+"计划投资额"
+"建安投资额"
+"本项目投资"
+"本项目投资额"
+"招标工程投资额"
+"招标投资额"
+"工程概算投资额"
+"工程预算总造价"
+"本包预算金额"
+"本包预算金额(最高限价万元)"
+"服务投资额"
+"项目投资额"
+"项目概算投资额"
+"投资估算"
+"拟采购金额"
+"控制金额"
+"合同估算价"
+"工程投资规模"
+"工程总投资"
+"工程投资"
+"工程投资额"
+"工程总投资额"
+"工程概算总投资"
+"资金来源及预算金额"
+"资金来源及预算"
+"标段预算"
+"标段预估金额"
+"预成交价"
+"预计投资"
+"预计投资额"
+"预计标的"
+"招标金额"
+"工程控制价"
+"资金来源及投资额"
+"最高限价工期"
+"最高限价"
+"最高限价(人民币元)"
+"最高限价(万元)"
+"最高限价(万元)"
+"最高限价(元)"
+"本包预算价"
+"本项目最高限价"
+"项目最高限价"
+"预算控制"
+"预算最高费用"
+"预算采购资金"
+"预计采购金额"
+"本项目监理费"
+"财政预算金额"
+"项目预算最高限价"
+"标的金额"
+"本项目建安费"
+"本项目响应限价"
+"本项目上限价"
+"项目预算价"
+"概算"
+"估算总投资"
+"工程发包价"
+"招标控制价标价"
+"拟成交金额经费预算"
+"建设资金"
+"最高投标限价暂定"
+"采购预算最高限价子包1"
+"结算金额"
+"招标预算价"
+"本标段预算金额"
+"本招标项目预算"
+"采购控制价"
+"预算控制价"
+"采购项目金额"
+"采购预算及评标办法"
+"控制价合计"
+"工程预算"
+"合同包预算"
+"工程造价"
+"发包估价"
+"最高限额"
+"最高限额(万元)"
+"计划总投资"
+"项目总金额"
+"市场价单位"
+"招标的控制价格"
+"该项目预计采购金额"
+"招标项目投资额"
+"工程预算总造价金额"
+"标段预算价"
+"发包预算价"
+"暂估采购量预算"
+"采购人预算"
+"采购预估规模"
+"预估费用"
+"谈判采购招标的财政预算"
+"采购货物的预算金额"
+"项目限价"
+"项目上限金额"
+"工程最高限价"
+"拦标价"
+"拦标价(万元)"
+"总招标控制价"
+"拦标价(万元)"
+"招标上限控制价"
+"最高控制价"
+"最高报价上限"
+"分包及预算控制价"
+"工程合同估算价"
+"项目估算"
+"谈判控制价"
+"批准投资总额(万元)"
+"投资估算价"
+"工程概算"
+"项目概算(万元)"
+"项目预算为"
+"▲预算金额"
+"招标部分估价"
+"预算金额及资金来源"
+"项目内容及规模"
+"预算总价或上限价(人民币元)"
+"本次工程项目预算价为"
+"投资估算约(元)"
+"含税预算(元)"
+"预算价及最高限价"
+"预估不含税金额(元)"
+"预算金额及最高限价"
+"采购预算金额及最高限价"
+"项目总造价"
+"采购含税限价"
+"交易预估价为"
+"财政预算价"
+"预估采购规模"
+"预估含税总价(万元)"
+"含税总价限价"
+"项目的最高限价"
+"最高限价(如有)"
+"采购规模"
+"项目工程造价"
+"项目合同估算价为"
+"备注本项目最高限价"
+"采购项目最高限价(元)"
+"预算金额(不含税万元)"
+"采购预算及控制价"
+"采购控制价(万元)"
+"含税总规模(万元)"
+"项目范围与规模"
+"项目预估金额"
+"预算控制总价"
+"本项目采购总金额"
+"项目投标限价"
+"谈判采购预算"
+"项目估算总投资"
+"项目估算总投资为"
+"项目总投资"
+"本项目总投资额"
+"总投资额"
+"项目总投资额"
+"预算金额(含税元)"
+"最高限价金额"
+"最高限价金额(元)"
+"估算总金额"
+"项目总规模"
+"项目预算或最高限价"
+"项目投资估算价"
+"项目投资估算"
+"项目预算及最高限价"
+"预算/最高限价(元)"
+"最高限价(元)"
+"最高限价(万元)"
+"招标项目规模"
+"采购最高限价"
+"采购预算控制价"
+"本次采购最高限价为"
+"代理项目估算金额"
+"工程预算投资额"
+"报价总金额(元)"
+"规模及合同估算价"
+"招标控制价/审定造价"
+"标底价或概(预)算价"
+"招标预算金额"
+"项目估算价"
+"限价或预算"
+"规模(估算价)"
+"预计项目金额"
+"控制总价(元)"
+"招标控制价总价"
+"审定预算价"
+"最高限制单价(元)"
+"项目最高限价金额"
+"采购项目最高限价(元人民币)"
+"财政预算限额(元)"
+"招标估算金额"
+"招标估算价"
+"立项金额(万元)"
+"本最高投标限价"
+"最高限价总金额(元)"
+"最高投标限价总价"
+"本期概算(万元)"
+"预算控制最高价"
+"财政预算限额(元)"
+"本项目设置最高限价"
+"批预算金额"
+"预算安排"
+"最高限价(或招标控制价)(元)"
+"采购项目最高限价"
+"最低限价"
+"合理最低价"
+"品目预算(元)"
+"招标标底或预算"
+"项目控制价"
+"预计合同额(万元)"
+"本次发包工程估价"
+"最高限价总计"
+"包最高限价(元)"
+"包预算(元)"
+"预算额及最高限价(元)"
+"资金来源及预算控制金额"
+"含税最高限价"
+"本期预算"

+ 1998 - 0
docs/table_head_doc/field_label.csv

@@ -0,0 +1,1998 @@
+corpus,label
+主要中标货物规格型号,型号;规格
+3.主要中标货物规格型号,型号;规格
+标准型号或产品规格,型号;规格
+产品型号,型号
+规格参数,规格
+技术参数等,规格
+技术标准及要求,规格
+技术规范,规格
+技术规程,规格
+技术标准,规格
+技术规约,规格
+技术要求,规格
+技术规定,规格
+材质、规格,规格
+材料规格,规格
+材质规范,规格
+规格说明,规格
+规格标准,规格
+材质标准,规格
+材质要求,规格
+材质规定,规格
+材料参数,规格
+物资描述,名称
+物品描述,名称
+物资明细,名称
+物品明细,名称
+产品描述,名称
+商品描述,名称
+用品描述,名称
+规格描述,规格
+成交内容,名称
+九.成交内容,名称
+询价名称,名称
+6.询价名称,名称
+项目细项,名称
+六、项目细项,名称
+含税综合单价,单价
+7、含税综合单价,单价
+含税综合总价,总价
+四、含税综合总价,总价
+类型,名称
+八、类型,名称
+产品名称,名称3
+4、产品名称,名称
+安全运维服务配置要求,规格
+九.安全运维服务配置要求,规格
+配置要求,规格
+八、配置要求,规格
+采购预算价,总价
+2.采购预算价,总价
+规格型号、主要配置,型号;规格
+九.规格型号、主要配置,型号;规格
+主要中标、成交标的名称,名称
+2.主要中标、成交标的名称,名称
+配置,规格
+2、配置,规格
+产品品牌及型号,品牌;型号
+1、产品品牌及型号,品牌;型号
+总价(元),总价
+一、总价(元),总价
+投标单价组成,单价
+8.投标单价组成,单价
+单价(元/台),单价
+六、单价(元/台),单价
+小计,总价
+5.小计,总价
+品牌及厂家、规格型号,品牌;型号;规格
+7、品牌及厂家、规格型号,品牌;型号;规格
+配件名称,名称
+5、配件名称,名称
+单价(元/年),单价
+9、单价(元/年),单价
+投标总价(元),总价
+一.投标总价(元),总价
+基本配置,规格
+5.基本配置,规格
+成交金额(人民币),总价
+7、成交金额(人民币),总价
+服务时间,数量
+7.服务时间,数量
+标的名称,名称
+6.标的名称,名称
+中标、成交金额,总价
+七、中标、成交金额,总价
+控制价(元)全费用综合单价,单价
+8、控制价(元)全费用综合单价,单价
+预算(元),总价
+1、预算(元),总价
+数量,数量
+4、数量,数量
+品种描述,规格;名称
+3、品种描述,规格;名称
+预算金额(万元),总价
+八.预算金额(万元),总价
+小计(元),总价
+五.小计(元),总价
+质保及服务要求,规格
+一、质保及服务要求,规格
+货物/服务名称,名称
+8、货物/服务名称,名称
+型号/规格,型号;规格
+八.型号/规格,型号;规格
+单价,单价
+3、单价,单价
+到站单价,单价
+二、到站单价,单价
+报价金额(元),总价
+二、报价金额(元),总价
+商品类目,名称
+4、商品类目,名称
+采购人名称,采购单位
+5.采购人名称,采购单位
+报价,总价
+九.报价,总价
+主要技术参数/指标,规格
+8、主要技术参数/指标,规格
+指标,规格
+3、指标,规格
+详细内容及具体参数,规格
+一.详细内容及具体参数,规格
+最后报价(元),总价
+二、最后报价(元),总价
+规格、技术参数、性能要求,规格
+一、规格、技术参数、性能要求,规格
+总价(万元),总价
+7、总价(万元),总价
+预算金额(万元),总价
+8.预算金额(万元),总价
+项目预算(元),总价
+一.项目预算(元),总价
+预算金额,总价
+6、预算金额,总价
+货物(设备)名称,名称
+四.货物(设备)名称,名称
+服务项目名称,采购项目名称
+九、服务项目名称,采购项目名称
+总价,总价
+8、总价,总价
+技术规格、参数及要求,规格
+1、技术规格、参数及要求,规格
+中标、成交金额(元),总价
+八、中标、成交金额(元),总价
+品牌/型号,品牌;型号
+九.品牌/型号,品牌;型号
+品牌,品牌
+一、品牌,品牌
+品牌、规格、型号及要求,品牌;型号;规格
+2、品牌、规格、型号及要求,品牌;型号;规格
+技术参数、性能要求,规格
+6.技术参数、性能要求,规格
+技术参数或详细性能要求,规格
+8、技术参数或详细性能要求,规格
+预算总金额(元),总价
+四、预算总金额(元),总价
+技术规格、参数要求,规格
+3.技术规格、参数要求,规格
+交货地点/备注,备注
+3、交货地点/备注,备注
+控制金额(元),总价
+七、控制金额(元),总价
+技术参数,规格
+5、技术参数,规格
+采购内容备注,备注
+8.采购内容备注,备注
+标的的名称,名称
+3、标的的名称,名称
+单价(元人民币),单价
+六.单价(元人民币),单价
+品牌/型号/参数/性能指标,品牌;型号;规格
+一、品牌/型号/参数/性能指标,品牌;型号;规格
+招标内容,名称;采购需求
+3.招标内容,名称;采购需求
+采购预算,总价
+4.采购预算,总价
+产品(项目)名称,名称
+六、产品(项目)名称,名称
+数量/单位,计量单位
+八.数量/单位,计量单位
+报价技术配置,规格
+九、报价技术配置,规格
+品目分类,名称;采购品目
+4、品目分类,名称;采购品目
+中标、成交标的名称,名称
+3.中标、成交标的名称,名称
+总价(万元),总价
+7.总价(万元),总价
+技术规格、参数,规格
+六、技术规格、参数,规格
+合计(元),总价
+五、合计(元),总价
+一、类型,名称
+采购项目预算(万元),总价
+一、采购项目预算(万元),总价
+主要中标货物名称,名称
+9、主要中标货物名称,名称
+参考规格型号,型号;规格
+四.参考规格型号,型号;规格
+数量(台),数量
+三.数量(台),数量
+参考品牌:,品牌
+七、参考品牌:,品牌
+三、品牌,品牌
+成交标的名称,名称
+一、成交标的名称,名称
+产品配置,规格
+九.产品配置,规格
+工程名称,名称
+3.工程名称,名称
+总价(元),总价
+五、总价(元),总价
+名称,名称
+九.名称,名称
+规格/型号,型号;规格
+五.规格/型号,型号;规格
+项目预算,总价
+8.项目预算,总价
+品牌、规格,品牌;规格
+7、品牌、规格,品牌;规格
+设备参数要求,规格
+2.设备参数要求,规格
+硬件参数,规格
+6.硬件参数,规格
+金额,总价
+一、金额,总价
+投标价格(元),总价
+四.投标价格(元),总价
+中标单价,单价
+五.中标单价,单价
+参考单价,单价
+1.参考单价,单价
+型号规格,型号;规格
+三.型号规格,型号;规格
+商品名称,名称
+六、商品名称,名称
+标的物名称,名称
+五、标的物名称,名称
+1.标的物名称,名称
+四.1.标的物名称,名称
+1、标的物名称,名称
+8、1、标的物名称,名称
+制造商家及规格型号,型号;规格;品牌
+五、制造商家及规格型号,型号;规格;品牌
+合计(元),总价
+5、合计(元),总价
+合价(元),总价
+3、合价(元),总价
+规格配置,规格
+6、规格配置,规格
+预算总金额(万元),总价
+四、预算总金额(万元),总价
+数量及单位(套),计量单位
+四.数量及单位(套),计量单位
+主要中标货物的名称,名称
+3、主要中标货物的名称,名称
+采购预算金额(元),总价
+一、采购预算金额(元),总价
+设备配置,规格
+一、设备配置,规格
+合计,总价
+4.合计,总价
+分项名称,名称
+四、分项名称,名称
+预算总金额(元),总价
+2、预算总金额(元),总价
+采购预算(万元),总价
+4、采购预算(万元),总价
+品牌、型号,品牌
+4、品牌、型号,品牌
+主要中标内容,名称
+7.主要中标内容,名称
+采购预算(元),总价
+二.采购预算(元),总价
+采购预算 (人民币),总价
+7、采购预算 (人民币),总价
+货物名称品牌,品牌;名称
+六.货物名称品牌,品牌;名称
+投标产品技术参数,规格
+2.投标产品技术参数,规格
+备注说明,备注
+二.备注说明,备注
+预计采购时间,预计采购时间
+六、预计采购时间,预计采购时间
+采购项目,采购项目名称
+七、采购项目,采购项目名称
+品名,名称
+四.品名,名称
+成交单价(元),单价
+二、成交单价(元),单价
+物项名称,名称
+4.物项名称,名称
+品牌型号规格,品牌;型号;规格
+1、品牌型号规格,品牌;型号;规格
+采购项目名称,采购项目名称
+六、采购项目名称,采购项目名称
+设备/耗材名称:,名称
+9.设备/耗材名称:,名称
+报价(元),总价
+六、报价(元),总价
+中标金额,总价
+8、中标金额,总价
+品牌和型号,品牌;型号
+八.品牌和型号,品牌;型号
+成交单 价(元),单价
+八、成交单 价(元),单价
+设备(项目)名称,名称
+2.设备(项目)名称,名称
+中标核心产品名称,名称
+七.中标核心产品名称,名称
+预算金额(元),总价
+九、预算金额(元),总价
+中标价格,总价
+八、中标价格,总价
+项目业主,采购单位
+8、项目业主,采购单位
+主要成交、成交标的名称,名称
+八.主要成交、成交标的名称,名称
+响应型号及配置,型号;规格
+5、响应型号及配置,型号;规格
+产品描述,名称
+七、产品描述,名称
+单价(元),单价
+四、单价(元),单价
+中标金额(元),总价
+5.中标金额(元),总价
+主要技术参数,规格
+六、主要技术参数,规格
+数量(件),数量
+8、数量(件),数量
+项目,采购项目名称
+单项价格(元),单价
+1.单项价格(元),单价
+中标价(元),总价
+五、中标价(元),总价
+规格型号/主要特征,型号;规格
+8、规格型号/主要特征,型号;规格
+品牌、型号(规格),品牌;型号;规格
+八.品牌、型号(规格),品牌;型号;规格
+品 名,名称
+一、品 名,名称
+预算金额(元),总价
+一、预算金额(元),总价
+数量(台),数量
+4、数量(台),数量
+参考品牌,品牌
+三、参考品牌,品牌
+产品规格,规格
+二、产品规格,规格
+单价(元),单价
+四、单价(元),单价
+型号和规格,型号;规格
+9、型号和规格,型号;规格
+主要成交标的的名称,名称
+六.主要成交标的的名称,名称
+投标报价(元),总价
+五.投标报价(元),总价
+中标总价(人民币:万元),总价
+1.中标总价(人民币:万元),总价
+金额(元),总价
+1、金额(元),总价
+采购单位,采购单位
+2、采购单位,采购单位
+采购预算价(元),总价
+九.采购预算价(元),总价
+4.采购项目名称,采购项目名称
+小计(单价×数量),总价
+8.小计(单价×数量),总价
+项目(产品)名称,名称
+5.项目(产品)名称,名称
+上限控制价(万元),总价
+四.上限控制价(万元),总价
+成交金额(万元),总价
+三.成交金额(万元),总价
+规格 型号,型号;规格
+七、规格 型号,型号;规格
+项目服务内容,采购需求;名称
+八.项目服务内容,采购需求;名称
+技术指标,规格
+3、技术指标,规格
+服务期限(月),数量
+9.服务期限(月),数量
+货物、服务和工程名称,名称
+一、货物、服务和工程名称,名称
+参考主要技术参数及性能(配置)要求,规格
+七、参考主要技术参数及性能(配置)要求,规格
+材料规格,规格
+8.材料规格,规格
+合计(万元),总价
+五.合计(万元),总价
+产品(项目)名称及简要参数,名称;规格
+七、产品(项目)名称及简要参数,名称;规格
+产 品(项目)名称,名称
+六、产 品(项目)名称,名称
+投标报价,总价
+6、投标报价,总价
+合计报价(元),总价
+7.合计报价(元),总价
+数量及计量单位,计量单位;数量
+四、数量及计量单位,计量单位;数量
+品目/品牌,品牌;名称;采购品目
+2、品目/品牌,品牌;名称;采购品目
+采购货物名称,名称
+五.采购货物名称,名称
+服务要求,规格
+5、服务要求,规格
+关键、主要内容描述,如品牌、产地等,品牌;规格
+4.关键、主要内容描述,如品牌、产地等,品牌;规格
+品牌型号、规格及主要技术参数,品牌;型号;规格
+四、品牌型号、规格及主要技术参数,品牌;型号;规格
+规格/型号,型号;规格
+7.规格/型号,型号;规格
+货物品牌及型号,品牌;型号
+6.货物品牌及型号,品牌;型号
+合计金额(元),总价
+6.合计金额(元),总价
+中标金额(元),总价
+八.中标金额(元),总价
+品牌规格型号,品牌;型号;规格
+6、品牌规格型号,品牌;型号;规格
+包含内容,名称
+1.包含内容,名称
+标项内容,名称
+9、标项内容,名称
+项目预算(金额:万元),总价
+五.项目预算(金额:万元),总价
+品牌、规格、型号,品牌;型号;规格
+1.品牌、规格、型号,品牌;型号;规格
+服务名称,名称
+七.服务名称,名称
+中标(成交)供应商、中标金额及地址,总价
+八.中标(成交)供应商、中标金额及地址,总价
+物资名称,名称
+九.物资名称,名称
+计量 单位,计量单位
+4、计量 单位,计量单位
+预算金额(人民币),总价
+7、预算金额(人民币),总价
+总金额(元),总价
+九.总金额(元),总价
+服务标准,规格
+2.服务标准,规格
+主要采购产品名称,名称
+七、主要采购产品名称,名称
+产品型号,型号
+九、产品型号,型号
+产品型号、规格配置,型号;规格
+三.产品型号、规格配置,型号;规格
+合同包,总价
+二、合同包,总价
+产品(设备)名称,名称
+一.产品(设备)名称,名称
+价格,单价
+二、价格,单价
+服务期限,数量
+2.服务期限,数量
+未中标人名称,名称
+5、未中标人名称,名称
+数量及单位,计量单位;数量
+6、数量及单位,计量单位;数量
+条目名称,名称
+3、条目名称,名称
+采购计划项目名称,采购项目名称
+一.采购计划项目名称,采购项目名称
+厂家(品牌),品牌
+一、厂家(品牌),品牌
+品目名称,名称;采购品目
+八、品目名称,名称;采购品目
+型号技术指标等,型号;规格
+八.型号技术指标等,型号;规格
+招标内容名称,名称;采购需求
+九、招标内容名称,名称;采购需求
+服务内容,采购需求;名称
+3.服务内容,采购需求;名称
+投标总价,总价
+1.投标总价,总价
+型号,型号
+6、型号,型号
+技术规格及要求,规格
+2、技术规格及要求,规格
+参考型号:,型号
+9.参考型号:,型号
+规格型号及配置要求,型号;规格
+7、规格型号及配置要求,型号;规格
+规格,规格
+二、规格,规格
+品牌、规格型号,品牌;型号;规格
+6.品牌、规格型号,品牌;型号;规格
+数量(单位)①,数量
+五.数量(单位)①,数量
+主要技术参数及性能(配置)要求,规格
+5.主要技术参数及性能(配置)要求,规格
+品目编号,采购品目
+8、品目编号,采购品目
+预算控制价,总价
+9.预算控制价,总价
+型号规格、技术参数、性能配置,型号;规格
+4.型号规格、技术参数、性能配置,型号;规格
+合价,总价
+2、合价,总价
+品牌及型号,品牌;型号
+7、品牌及型号,品牌;型号
+预算金额 (万元),总价
+八、预算金额 (万元),总价
+中标标的名称,名称
+二、中标标的名称,名称
+合价(元),总价
+5、合价(元),总价
+金额(万元),总价
+2.金额(万元),总价
+单价:元,单价
+二、单价:元,单价
+价格 (元),单价
+7、价格 (元),单价
+品牌/产地,品牌
+七、品牌/产地,品牌
+商品品牌,品牌
+九、商品品牌,品牌
+标项总金额(元),总价
+8、标项总金额(元),总价
+设备名称,名称
+三.设备名称,名称
+制造厂商名称及产地,品牌
+七.制造厂商名称及产地,品牌
+标项名称,名称
+二.标项名称,名称
+单价(万元),单价
+七、单价(万元),单价
+制造商/生产厂商名称,品牌
+五、制造商/生产厂商名称,品牌
+软件版本/设备型号,型号
+8.软件版本/设备型号,型号
+设备型号,型号
+八、设备型号,型号
+政府采购品目代码,采购品目
+2、政府采购品目代码,采购品目
+最高限价(元),总价
+5、最高限价(元),总价
+计量单位,计量单位
+7.计量单位,计量单位
+报价(元),总价
+7、报价(元),总价
+生产制造商,品牌
+9.生产制造商,品牌
+物品名称,名称
+七、物品名称,名称
+主要成交的名称,名称
+一、主要成交的名称,名称
+成交价(元),总价
+九、成交价(元),总价
+小计(元),总价
+9、小计(元),总价
+采购预算(元),总价
+八、采购预算(元),总价
+产地及生产厂家,品牌
+七.产地及生产厂家,品牌
+货物名称,名称
+六.货物名称,名称
+规格型号,型号;规格
+五.规格型号,型号;规格
+规格、型号,型号;规格
+八、规格、型号,型号;规格
+数量(台/套),数量
+七.数量(台/套),数量
+品牌规格,品牌;规格
+8、品牌规格,品牌;规格
+品牌及规格型号,品牌;型号;规格
+5、品牌及规格型号,品牌;型号;规格
+设备类型,型号
+1.设备类型,型号
+数量单位,数量;计量单位
+九.数量单位,数量;计量单位
+金额合计(元),总价
+七、金额合计(元),总价
+规格(技术参数、性能要求),规格
+5.规格(技术参数、性能要求),规格
+预算单价,单价
+6.预算单价,单价
+品牌型号及主要配置,品牌;型号;规格
+7.品牌型号及主要配置,品牌;型号;规格
+中标(成交)价格(元),总价
+3.中标(成交)价格(元),总价
+制造商名称(全称),品牌
+一、制造商名称(全称),品牌
+单位,计量单位
+2.单位,计量单位
+采购预算单价(元),单价
+7.采购预算单价(元),单价
+采购名称,名称
+七、采购名称,名称
+参数、规格,型号;规格
+四、参数、规格,型号;规格
+制造商/品牌,品牌
+九、制造商/品牌,品牌
+商品详情,名称
+8、商品详情,名称
+成交金额,总价
+2、成交金额,总价
+采购条目名称,名称
+三.采购条目名称,名称
+产品全称,名称
+4.产品全称,名称
+投标产品全称,名称
+2.投标产品全称,名称
+费用小计,总价
+四.费用小计,总价
+主要标的名称,名称
+2、主要标的名称,名称
+预算,总价
+一、预算,总价
+中标金额(万元),总价
+3、中标金额(万元),总价
+总金额(元),总价
+8.总金额(元),总价
+主要成交标的名称,名称
+4.主要成交标的名称,名称
+开发商/制造商,品牌
+8、开发商/制造商,品牌
+8、配置要求,规格
+报价产品技术参数,规格
+8、报价产品技术参数,规格
+报价(万元),总价
+7、报价(万元),总价
+简要规格描述,规格
+四.简要规格描述,规格
+系统名称,名称
+2、系统名称,名称
+中标金额(万元),总价
+2.中标金额(万元),总价
+技术要求及性能(配置)要求,规格
+5、技术要求及性能(配置)要求,规格
+采购数量,数量
+六.采购数量,数量
+投标产品名称,名称
+9.投标产品名称,名称
+数量(台/套),数量
+七、数量(台/套),数量
+成交金额(元),总价
+7、成交金额(元),总价
+数量(人),数量
+八、数量(人),数量
+数量/台,数量
+9.数量/台,数量
+中标单价(人民币),单价
+一、中标单价(人民币),单价
+货物内容,名称
+一.货物内容,名称
+采购品目,名称;采购品目
+5.采购品目,名称;采购品目
+预算(万元),总价
+四.预算(万元),总价
+品牌或规格、型号,品牌;型号;规格
+五、品牌或规格、型号,品牌;型号;规格
+投标单价,单价
+一、投标单价,单价
+规格/型号/配置及要求,型号;规格
+五.规格/型号/配置及要求,型号;规格
+设备/服务名称,名称
+4.设备/服务名称,名称
+预算资金(元),总价
+五、预算资金(元),总价
+价格(元),单价
+4、价格(元),单价
+主要投标标的名称,名称
+九.主要投标标的名称,名称
+九、采购条目名称,名称
+8.费用小计,总价
+七、主要标的名称,名称
+数目(台),数量
+六.数目(台),数量
+6、预算,总价
+6.中标金额(万元),总价
+一、总金额(元),总价
+六.开发商/制造商,品牌
+五、配置要求,规格
+采购目录,名称
+6、采购目录,名称
+二、品名,名称
+7、报价产品技术参数,规格
+技术参数或配置要求,规格
+1、技术参数或配置要求,规格
+6.报价(万元),总价
+4.系统名称,名称
+参数,规格
+八、参数,规格
+9、中标金额(万元),总价
+4、技术要求及性能(配置)要求,规格
+8、采购数量,数量
+五、投标产品名称,名称
+9、数量(台/套),数量
+成交数量,数量
+三、成交数量,数量
+4.成交金额(元),总价
+九.数量(人),数量
+七.数量/台,数量
+8.中标单价(人民币),单价
+品牌型号,品牌;型号
+3.品牌型号,品牌;型号
+4、货物内容,名称
+规格型号技术参数,型号;规格
+八、规格型号技术参数,型号;规格
+6.采购品目,名称;采购品目
+五.预算(万元),总价
+9.品牌或规格、型号,品牌;型号;规格
+1.投标单价,单价
+五、规格/型号/配置及要求,型号;规格
+7.设备/服务名称,名称
+2、预算资金(元),总价
+价格(元),总价
+5.价格(元),总价
+九、主要投标标的名称,名称
+品牌、规格及型号,品牌;型号;规格
+8、品牌、规格及型号,品牌;型号;规格
+七.投标报价,总价
+工程量,数量
+九、工程量,数量
+中标价格(元),总价
+7、中标价格(元),总价
+物料名称,名称
+6.物料名称,名称
+物料描述,名称;规格
+八、物料描述,名称;规格
+采购量,数量
+一.采购量,数量
+计划名称,名称
+九.计划名称,名称
+标包名称,名称
+三、标包名称,名称
+二、标包名称,名称
+3、计划名称,名称
+中标/成交标的名称:,名称
+9、中标/成交标的名称:,名称
+采购项目名称:,采购项目名称
+六.采购项目名称:,采购项目名称
+服务要求:,规格
+1.服务要求:,规格
+六.品目编号,采购品目
+3.品目名称,名称;采购品目
+九.商品名称,名称
+八、品牌,品牌
+产品属性,规格
+四.产品属性,规格
+一、型号技术指标等,型号;规格
+物料描述,规格;名称
+9、物料描述,规格;名称
+物料组描述,名称
+六.物料组描述,名称
+四、数量,数量
+八、计量单位,计量单位
+标段或设备名称、规格型号,名称;型号;规格
+五.标段或设备名称、规格型号,名称;型号;规格
+计划采购时间,预计采购时间
+三.计划采购时间,预计采购时间
+成交金额(万元/人民币),总价
+四、成交金额(万元/人民币),总价
+成交项目,名称
+2、成交项目,名称
+六.成交项目,名称
+成交金额(元人民币),总价
+7.成交金额(元人民币),总价
+采购报价,总价
+四、采购报价,总价
+项目名称,采购项目名称
+六、项目名称,采购项目名称
+租赁单价,单价
+8.租赁单价,单价
+年租金,总价
+八.年租金,总价
+项目特征描述,规格
+九、项目特征描述,规格
+商城展示价(元),单价
+三.商城展示价(元),单价
+7、物料描述,规格;名称
+标段或设备名称、规格型号,型号;规格;名称
+7、标段或设备名称、规格型号,型号;规格;名称
+品目,名称;采购品目
+一.品目,名称;采购品目
+九.品牌,品牌
+商城展示价(元),总价
+八.商城展示价(元),总价
+二、计划名称,名称
+9.需求单位,采购单位
+本包预算金额(最高限价,单位:万元),总价
+八.本包预算金额(最高限价,单位:万元),总价
+计量单位描述,计量单位
+1.计量单位描述,计量单位
+二、物料组描述,名称
+五、物料描述,规格;名称
+2.规格型号,型号;规格
+五、单位,计量单位
+三.计划名称,名称
+5.采购数量,数量
+服务的范围、内容及主要技术要求,规格
+4.服务的范围、内容及主要技术要求,规格
+需求单位,采购单位
+最高限价(人民币),总价
+9.最高限价(人民币),总价
+采购预算(人民币),总价
+六.采购预算(人民币),总价
+四.项目名称,采购项目名称
+推荐品牌范围,品牌
+7.推荐品牌范围,品牌
+一、项目名称,采购项目名称
+一、一、项目名称,采购项目名称
+招标工作内容,名称;采购需求
+四.招标工作内容,名称;采购需求
+五.产品描述,名称
+8.采购量,数量
+采购内容,名称;采购需求
+9.采购内容,名称;采购需求
+5、服务名称,名称
+采购人,采购单位
+七.采购人,采购单位
+6.物资名称,名称
+规格品种,规格
+9.规格品种,规格
+包件数量,数量
+3.包件数量,数量
+需求类型,名称
+三.需求类型,名称
+描述,规格
+四.描述,规格
+维修项目名称,采购项目名称
+五.维修项目名称,采购项目名称
+服务项目,名称
+二.服务项目,名称
+规格描述,规格
+一.规格描述,规格
+品牌(如有),品牌
+二.品牌(如有),品牌
+规格型号(如有),型号;规格
+三、规格型号(如有),型号;规格
+品牌及规格型号(如有),品牌;型号;规格
+六.品牌及规格型号(如有),品牌;型号;规格
+采购船型,名称
+四.采购船型,名称
+主尺度,规格
+三.主尺度,规格
+分项或子目名称,名称
+6.分项或子目名称,名称
+主要工作内容,规格;采购需求
+9、主要工作内容,规格;采购需求
+专业工程名称,名称
+1、专业工程名称,名称
+机械设备名称,名称
+三、机械设备名称,名称
+包名称,名称
+1、包名称,名称
+包名,名称
+1.包名,名称
+分包名称,名称
+2、分包名称,名称
+7.标项名称,名称
+六、服务名称,名称
+采购标的,名称
+五.采购标的,名称
+品目编号及品目名称,名称;采购品目
+九.品目编号及品目名称,名称;采购品目
+三、设备名称,名称
+产品大类,名称
+一、产品大类,名称
+采购标的技术要求,规格
+七.采购标的技术要求,规格
+要素,名称
+三、要素,名称
+规格参数要求,规格
+九、规格参数要求,规格
+印刷品名称,名称
+九.印刷品名称,名称
+材料名称,名称
+一、材料名称,名称
+投标确认品牌,品牌
+二、投标确认品牌,品牌
+标准名称,名称
+八.标准名称,名称
+试验项目,名称
+七.试验项目,名称
+标准参数值,型号;规格
+八.标准参数值,型号;规格
+采购医疗设备名称,名称
+三、采购医疗设备名称,名称
+三、品名,名称
+涉及产品,名称
+五.涉及产品,名称
+预估数量(件),数量
+7、预估数量(件),数量
+租赁单价(元/件),单价
+一、租赁单价(元/件),单价
+分项工程材料名称,名称
+六.分项工程材料名称,名称
+产品类别,名称;采购品目
+一.产品类别,名称;采购品目
+项目内容,名称;采购需求
+四.项目内容,名称;采购需求
+所投产品,名称
+七.所投产品,名称
+货物数量,数量
+9、货物数量,数量
+货物品牌,品牌
+七.货物品牌,品牌
+货物单价(元),单价
+六、货物单价(元),单价
+货物总价(元),总价
+三.货物总价(元),总价
+货物型号,型号
+四.货物型号,型号
+五.货物名称,名称
+货物总价,总价
+八、货物总价,总价
+货物单价,单价
+2、货物单价,单价
+投标产品,名称
+9.投标产品,名称
+采购项目预算(元人民币),总价
+二、采购项目预算(元人民币),总价
+采购需求概况,采购需求
+5、采购需求概况,采购需求
+3、预计采购时间,预计采购时间
+备注,备注
+五、备注,备注
+项目名称,采购项目名称
+七、项目名称,采购项目名称
+预计实施采购月份,预计采购时间
+三、预计实施采购月份,预计采购时间
+是否专门面向中小企业采购,预留面向中小企业采购金额
+4.是否专门面向中小企业采购,预留面向中小企业采购金额
+采购单位:,采购单位
+二、采购单位:,采购单位
+采购需求概况:,采购需求
+2.采购需求概况:,采购需求
+预计采购时间:,预计采购时间
+5.预计采购时间:,预计采购时间
+预计采购时间(填写到月),预计采购时间
+4.预计采购时间(填写到月),预计采购时间
+线路名称,名称
+8、线路名称,名称
+桩号及位置,采购需求
+2.桩号及位置,采购需求
+设备类别,型号
+九.设备类别,型号
+9.产品名称,名称
+主要维护内容,采购需求;名称
+五.主要维护内容,采购需求;名称
+采购需求情况,采购需求
+6.采购需求情况,采购需求
+预计采购日期,预计采购时间
+3.预计采购日期,预计采购时间
+是否适宜中小企业采购预算预留,预留面向中小企业采购金额
+2.是否适宜中小企业采购预算预留,预留面向中小企业采购金额
+3、采购预算(万元),总价
+预留面向中小企业采购金额(万元),预留面向中小企业采购金额
+8.预留面向中小企业采购金额(万元),预留面向中小企业采购金额
+九、采购人,采购单位
+采购单位名称,采购单位
+4.采购单位名称,采购单位
+采购预算金额(万元),总价
+4、采购预算金额(万元),总价
+采购标的名称,名称
+4.采购标的名称,名称
+采购标的数量,数量
+七.采购标的数量,数量
+是否专门面向中小企业,预留面向中小企业采购金额
+8、是否专门面向中小企业,预留面向中小企业采购金额
+9.预算金额,总价
+2、是否适宜中小企业采购预算预留,预留面向中小企业采购金额
+两年费用总计(元),总价
+2.两年费用总计(元),总价
+采购预算(万元),总价
+4.采购预算(万元),总价
+*采购项目名称,采购项目名称
+六、*采购项目名称,采购项目名称
+*采购需求概况,采购需求
+3.*采购需求概况,采购需求
+*预算金额(元)【格式:number】,总价
+四、*预算金额(元)【格式:number】,总价
+*预计采购时间(填写到月)【格式:yyyy年MM月】,预计采购时间
+9、*预计采购时间(填写到月)【格式:yyyy年MM月】,预计采购时间
+*是否专门面向中小企业采购,预留面向中小企业采购金额
+一、*是否专门面向中小企业采购,预留面向中小企业采购金额
+预算金额()万元,总价
+9.预算金额()万元,总价
+四、采购标的,名称
+拟采购实施月份,预计采购时间
+6.拟采购实施月份,预计采购时间
+采购需求概述,采购需求
+五.采购需求概述,采购需求
+预计采购月份,预计采购时间
+1.预计采购月份,预计采购时间
+预计采购时,预计采购时间
+2、预计采购时,预计采购时间
+采购项目概况,采购需求
+4.采购项目概况,采购需求
+是否面向中小企业采购,预留面向中小企业采购金额
+3、是否面向中小企业采购,预留面向中小企业采购金额
+项目需求,采购需求
+六.项目需求,采购需求
+调研品目,采购品目;名称
+9.调研品目,采购品目;名称
+*采购标的名称,名称
+5.*采购标的名称,名称
+*采购标的数量【格式:number】,数量
+5、*采购标的数量【格式:number】,数量
+*是否专门面向中小企业,预留面向中小企业采购金额
+7、*是否专门面向中小企业,预留面向中小企业采购金额
+采购需求名称,名称
+4.采购需求名称,名称
+采购需求内容,采购需求;名称
+7.采购需求内容,采购需求;名称
+9.预计采购时间(填写到月),预计采购时间
+采购项目名称,采购项目名称
+五.采购项目名称,采购项目名称
+预计采购时间(填写到月,预计采购时间
+三.预计采购时间(填写到月,预计采购时间
+预计采购时间(填写到月),预计采购时间
+8、预计采购时间(填写到月),预计采购时间
+1.采购项目名称,采购项目名称
+六、采购需求概况,采购需求
+7、预计采购日期,预计采购时间
+预计采购时间备(填写到月)注,预计采购时间
+一.预计采购时间备(填写到月)注,预计采购时间
+是面向中小企业采购,预留面向中小企业采购金额
+1、是面向中小企业采购,预留面向中小企业采购金额
+采购预算金额,总价
+7、采购预算金额,总价
+采购内容及需求概况,采购需求;名称
+一.采购内容及需求概况,采购需求;名称
+采购需之概况,采购需求
+三、采购需之概况,采购需求
+预采购间,预计采购时间
+3、预采购间,预计采购时间
+销售物资、副产品名称,名称
+4、销售物资、副产品名称,名称
+顶预计采购时间【(填写到月),预计采购时间
+三、顶预计采购时间【(填写到月),预计采购时间
+预算价(万元),总价
+九、预算价(万元),总价
+七.投标总价,总价
+备注:自有或租赁,备注
+4.备注:自有或租赁,备注
+采需求购概况,采购需求
+1.采需求购概况,采购需求
+预算采购时间,预计采购时间
+3、预算采购时间,预计采购时间
+拟实施采购月份,预计采购时间
+3.拟实施采购月份,预计采购时间
+采购需求及概况,采购需求
+九.采购需求及概况,采购需求
+采购品名,名称
+二.采购品名,名称
+主要内容,采购需求;名称
+7、主要内容,采购需求;名称
+5.服务要求,规格
+品目名称,采购品目;名称
+1、品目名称,采购品目;名称
+采购需求,采购需求;名称
+8、采购需求,采购需求;名称
+三、预计采购时间,预计采购时间
+品目,采购品目;名称
+8、品目,采购品目;名称
+招标项目,采购项目名称
+六.招标项目,采购项目名称
+品种,型号
+三.品种,型号
+主要需求,采购需求
+三.主要需求,采购需求
+功能,采购需求
+6.功能,采购需求
+4、服务名称,名称
+主要建设内容,采购需求
+三.主要建设内容,采购需求
+采购需求概括,采购需求
+7.采购需求概括,采购需求
+其他需求的公开内容,采购需求
+4、其他需求的公开内容,采购需求
+品名用途,名称
+四.品名用途,名称
+主要树种,采购品目;名称
+3、主要树种,采购品目;名称
+建设内容,采购需求
+三.建设内容,采购需求
+概算(万元),总价
+四、概算(万元),总价
+所含内容,采购需求;名称
+二、所含内容,采购需求;名称
+采购品目采购,采购品目;名称
+8、采购品目采购,采购品目;名称
+具体项目内容,采购需求
+六.具体项目内容,采购需求
+需求概况,采购需求
+五.需求概况,采购需求
+预计采购时间(年月),预计采购时间
+4、预计采购时间(年月),预计采购时间
+服务内容,采购需求;名称
+六、服务内容,采购需求;名称
+采购企业,采购单位
+一.采购企业,采购单位
+采购学校,采购单位
+二、采购学校,采购单位
+包件名称,名称
+8、包件名称,名称
+一.包名称,名称
+最高限价(万元),总价
+七.最高限价(万元),总价
+项数,数量
+八.项数,数量
+包内容,名称
+1.包内容,名称
+采购需求,名称;采购需求
+七.采购需求,名称;采购需求
+八.计量单位,计量单位
+细项内容,名称
+2.细项内容,名称
+所需服务类型,采购品目
+4、所需服务类型,采购品目
+6、分包名称,名称
+5、采购数量,数量
+服务金额,总价
+5.服务金额,总价
+中选金额,总价
+一.中选金额,总价
+任务书总投资(万元),总价
+6.任务书总投资(万元),总价
+四、采购品目名称,名称;采购品目
+6、四、采购品目名称,名称;采购品目
+五、采购预算金额(元),总价
+8.五、采购预算金额(元),总价
+材质/品牌,品牌
+七、材质/品牌,品牌
+产品配置名称,名称
+七.产品配置名称,名称
+八、产品型号,型号
+五、采购数量,数量
+五.计量单位,计量单位
+采购品目:,名称;采购品目
+四、采购品目:,名称;采购品目
+三.包名称,名称
+本包预算金额(单位:万元),总价
+五.本包预算金额(单位:万元),总价
+供应商报价(元),总价
+七.供应商报价(元),总价
+标段名称,名称
+8、标段名称,名称
+八.项目名称,采购项目名称
+九.标项名称,名称
+采购品目名称,名称;采购品目
+6、采购品目名称,名称;采购品目
+七、采购预算金额(元),总价
+物资,名称
+二.物资,名称
+一、数量,数量
+维修更换材料名称,名称
+6.维修更换材料名称,名称
+六.产品描述,名称
+四.采购数量,数量
+一、服务内容,采购需求;名称
+验收数量,数量
+六、验收数量,数量
+验收金额(元),总价
+4、验收金额(元),总价
+验收标准\规格型号\技术标准,规格;型号
+8、验收标准\规格型号\技术标准,规格;型号
+项目种类,名称
+5、项目种类,名称
+物品种类,名称
+五、物品种类,名称
+设备(材料)名称,名称
+九、设备(材料)名称,名称
+7、物资名称,名称
+需用数量,数量
+3、需用数量,数量
+招标人名称,采购单位
+4、招标人名称,采购单位
+6、标的类型,采购品目
+2、服务期限,数量
+采购项目,采购项目名称
+八.采购项目,采购项目名称
+三.标包名称,名称
+成交价格(人民币万元),总价
+六.成交价格(人民币万元),总价
+标段(包)名称,名称
+6.标段(包)名称,名称
+需求描述,规格
+1.需求描述,规格
+服务描述,名称
+五、服务描述,名称
+六、物料描述,名称;规格
+三.物料组描述,名称
+合同包预算,总价
+二、合同包预算,总价
+品目号预算,总价
+一、品目号预算,总价
+三、本包预算金额(单位:万元),总价
+品牌/来源/规格型号,品牌;规格;型号
+3、品牌/来源/规格型号,品牌;规格;型号
+质量要求/技术指标,规格
+九、质量要求/技术指标,规格
+质量要求/规格型号,规格;型号
+1、质量要求/规格型号,规格;型号
+质量要求/技术指标/品牌/来源/规格型号,品牌;规格;型号
+二、质量要求/技术指标/品牌/来源/规格型号,品牌;规格;型号
+物资名称及数量,名称;数量
+1.物资名称及数量,名称;数量
+5、合价,总价
+主要标的数量,数量
+三.主要标的数量,数量
+预估工作量,数量
+8.预估工作量,数量
+规格型号(或服务要求),规格;型号
+9.规格型号(或服务要求),规格;型号
+主要标的单价(万元),单价
+三、主要标的单价(万元),单价
+合同金额(万元),总价
+3、合同金额(万元),总价
+工作内容,名称;名称
+3.工作内容,名称;名称
+6.采购品目名称,名称;采购品目
+六、供应商报价(元),总价
+体检项目,名称
+1、体检项目,名称
+项目,采购项目名称
+5.项目,采购项目名称
+六、服务内容,采购需求;名称
+药品名称,名称
+3.药品名称,名称
+八、采购预算金额(元),总价
+六、采购项目预算(元人民币),总价
+预算金额:,总价
+一、预算金额:,总价
+通用名,名称
+二、通用名,名称
+剂型,型号
+2、剂型,型号
+包装单位,计量单位
+五.包装单位,计量单位
+三、服务内容,采购需求;名称
+保障内容,名称;名称
+七、保障内容,名称;名称
+计划采购量,数量
+六.计划采购量,数量
+四.标段(包)名称,名称
+中标价(人民币),总价
+二、中标价(人民币),总价
+8、服务要求,规格
+项目需求,名称;采购需求
+七、项目需求,名称;采购需求
+品目编码及品目名称,采购品目;名称
+8、品目编码及品目名称,采购品目;名称
+5、工程名称,名称
+最高限定单价(元),单价
+七.最高限定单价(元),单价
+成交总金额(元),总价
+九.成交总金额(元),总价
+七.服务时间,数量
+7.服务要求,规格
+服务范围,采购需求
+5、服务范围,采购需求
+2、服务标准,规格
+三.成交总金额(元),总价
+经费预算,总价
+2.经费预算,总价
+3.最高限价(万元),总价
+估算金额(万元),总价
+3.估算金额(万元),总价
+产品单位,计量单位
+五.产品单位,计量单位
+产品数量,数量
+3、产品数量,数量
+1.服务名称,名称
+6、标的名称,名称
+施工范围,规格
+4、施工范围,规格
+施工工期,规格
+3.施工工期,规格
+采购明细,名称
+7、采购明细,名称
+四.物料描述,名称;规格
+5、主要标的数量,数量
+主要标的单价,单价
+七.主要标的单价,单价
+合同金额,总价
+3.合同金额,总价
+九.主要标的名称,名称
+8.名称,名称
+9.采购单位,采购单位
+九.采购项目名称,采购项目名称
+采购品目,采购品目
+二、采购品目,采购品目
+3、采购需求概况,采购需求
+2、备注,备注
+七.预计实施采购月份,预计采购时间
+2、是否专门面向中小企业采购,预留面向中小企业采购金额
+5、采购单位:,采购单位
+3.采购项目名称:,采购项目名称
+采购品目:,采购品目
+6.采购品目:,采购品目
+2、采购需求概况:,采购需求
+二、预计采购时间:,预计采购时间
+3.预计采购时间(填写到月),预计采购时间
+线路名称,采购品目
+8、线路名称,采购品目
+9、桩号及位置,采购需求
+设备类别,规格;型号
+六.设备类别,规格;型号
+三、产品名称,名称
+主要维护内容,采购品目
+四.主要维护内容,采购品目
+3、采购需求情况,采购需求
+2、预计采购日期,预计采购时间
+三、是否适宜中小企业采购预算预留,预留面向中小企业采购金额
+1、采购预算(万元),总价
+5、预留面向中小企业采购金额(万元),预留面向中小企业采购金额
+9、采购人,采购单位
+四、采购单位名称,采购单位
+七、采购预算金额(万元),总价
+采购标的名称,采购品目
+四、采购标的名称,采购品目
+4、采购标的数量,数量
+5、是否专门面向中小企业,预留面向中小企业采购金额
+二.预算金额,总价
+六.是否适宜中小企业采购预算预留,预留面向中小企业采购金额
+7、两年费用总计(元),总价
+*采购项目名称,采购项目名称
+3.*采购项目名称,采购项目名称
+九、*采购需求概况,采购需求
+六、*预算金额(元)【格式:number】,总价
+四.*预计采购时间(填写到月)【格式:yyyy年MM月】,预计采购时间
+七、*是否专门面向中小企业采购,预留面向中小企业采购金额
+8、预算金额()万元,总价
+采购标的,采购品目
+5、采购标的,采购品目
+7、拟采购实施月份,预计采购时间
+3、采购需求概述,采购需求
+8.预计采购月份,预计采购时间
+1.预计采购时,预计采购时间
+9.采购项目概况,采购需求
+七.是否面向中小企业采购,预留面向中小企业采购金额
+五.项目需求,采购需求
+调研品目,采购品目
+六.调研品目,采购品目
+*采购标的名称,采购品目
+8.*采购标的名称,采购品目
+九.*采购标的数量【格式:number】,数量
+八、*是否专门面向中小企业,预留面向中小企业采购金额
+采购需求名称,采购品目;名称
+9、采购需求名称,采购品目;名称
+采购需求内容,采购需求;名称
+一.采购需求内容,采购需求;名称
+6、预计采购时间(填写到月),预计采购时间
+3、预计采购时间(填写到月,预计采购时间
+四.预计采购时间(填写到月),预计采购时间
+六、采购项目名称,采购项目名称
+一.采购需求概况,采购需求
+1、预计采购日期,预计采购时间
+六、预计采购时间备(填写到月)注,预计采购时间
+7、是面向中小企业采购,预留面向中小企业采购金额
+8、采购预算金额,总价
+采购内容及需求概况,采购需求
+4.采购内容及需求概况,采购需求
+六.采购需之概况,采购需求
+六.预采购间,预计采购时间
+销售物资、副产品名称,采购品目
+一.销售物资、副产品名称,采购品目
+4.顶预计采购时间【(填写到月),预计采购时间
+采购内容,采购需求;名称
+九.采购内容,采购需求;名称
+4、预算价(万元),总价
+7、投标总价,总价
+2、备注:自有或租赁,备注
+8.采需求购概况,采购需求
+五.预算采购时间,预计采购时间
+九.拟实施采购月份,预计采购时间
+2.采购需求及概况,采购需求
+采购品名,采购品目;名称
+二、采购品名,采购品目;名称
+主要内容,采购需求;名称
+1、主要内容,采购需求;名称
+9、服务要求,规格
+采购需求,采购需求;名称
+3、采购需求,采购需求;名称
+九.预计采购时间,预计采购时间
+品目,采购品目
+九.品目,采购品目
+招标项目,采购项目名称
+6.招标项目,采购项目名称
+品种,规格型号
+6.品种,规格型号
+主要需求,采购需求;名称
+1、主要需求,采购需求;名称
+2、功能,采购需求
+五、服务名称,名称
+八.主要建设内容,采购需求
+2、采购需求概括,采购需求
+四、其他需求的公开内容,采购需求
+品名用途,采购品目
+9.品名用途,采购品目
+主要树种,采购品目
+七、主要树种,采购品目
+7.建设内容,采购需求
+4、概算(万元),总价
+8、所含内容,采购需求
+采购品目采购,采购品目
+6、采购品目采购,采购品目
+6、具体项目内容,采购需求
+四、需求概况,采购需求
+5.预计采购时间(年月),预计采购时间
+服务内容,采购需求;名称
+一、服务内容,采购需求;名称
+四、采购数量,数量
+采购 数量,数量
+一、采购 数量,数量
+采购单价,单价
+3.采购单价,单价
+采购 单价,单价
+八.采购 单价,单价
+采购总价,总价
+4、采购总价,总价
+采购 总价,总价
+6.采购 总价,总价
+采购 型号,型号
+4.采购 型号,型号
+采购 规格,规格
+8.采购 规格,规格
+采购规格,规格
+三、采购规格,规格
+采购品牌,品牌
+3、采购品牌,品牌
+采购 品牌,品牌
+九、采购 品牌,品牌
+服务需求,名称;采购需求
+五.服务需求,名称;采购需求
+五.需求单位,采购单位
+采购人预算(单价),单价
+5.采购人预算(单价),单价
+计量单位名称,计量单位
+二、计量单位名称,计量单位
+数量(单位),数量;计量单位
+一、数量(单位),数量;计量单位
+建议品牌及型号,品牌;型号
+六、建议品牌及型号,品牌;型号
+实际成交 单价,单价
+8.实际成交 单价,单价
+规格、型号,规格;型号
+3.规格、型号,规格;型号
+六.备注,备注
+品目预算(元),总价
+九、品目预算(元),总价
+最高限价(元),总价
+七.最高限价(元),总价
+9.招标人名称,采购单位
+具体要求,规格
+1、具体要求,规格
+4、采购需求单位,采购单位
+七、需求单位,采购单位
+六、采购单位,采购单位
+采购项目技术参数要求,规格
+六、采购项目技术参数要求,规格
+单项名称,名称
+7.单项名称,名称
+8、规格,规格
+二、型号,型号
+1.剂型,型号
+二.通用名,名称
+保障金额,规格
+八.保障金额,规格
+六、计量单位描述,计量单位
+物资规格,规格
+5.物资规格,规格
+物资数量,数量
+2、物资数量,数量
+物资型号,数量
+1、物资型号,数量
+招标人,采购单位
+9.招标人,采购单位
+采购目录/需求描述,名称
+6、采购目录/需求描述,名称
+七.采购标的,名称
+二、招标人,采购单位
+8、二、招标人,采购单位
+流量m3/h,规格
+7.流量m3/h,规格
+采购商品,名称
+2.采购商品,名称
+采购服务,名称
+5、采购服务,名称
+主要标的信息,名称
+三.主要标的信息,名称
+本次采购预计量,数量
+采购项,名称
+采购物品,名称
+成交总额,总价
+采购需求,采购需求;名称
+需求内容,名称
+物品,名称
+需求预算,总价
+采购预算,总价
+货物类,名称
+施工标段控制价,总价
+预计发布招标公告时间,预计采购时间
+预计发布招标公告时间,预计采购时间
+型号规格,型号;规格
+规格品牌,型号;规格
+品牌规格,型号;规格
+采购需求单位,采购单位
+需求单位名称,采购单位
+采购单位名称,采购单位
+招标项目,采购项目名称
+采购人名称,采购单位
+交易标的名称:,名称
+标的转让底价:,总价
+标的成交价格:,总价
+标的成交总额:,总价
+单价(包含人材机)(元),单价
+货物品牌,品牌
+报价,总价
+标的成交总额,总价
+服务期,数量
+服务金额,总价
+已选配件/规格,规格
+数量(个),数量
+预算单位名称,采购单位
+招标文件计划发布时间,预计采购时间
+采购计划发布时间,预计采购时间
+项目计划发布时间,预计采购时间
+发布招标文件的计划时间,预计采购时间
+招标文件发布时间计划,预计采购时间
+招标公告计划发布时间,预计采购时间
+招标文件发布预计时间,预计采购时间
+预计发布招标文件的时间计划,预计采购时间
+项目发布预计时间,预计采购时间
+采购发布预计时间,预计采购时间
+合同预估金额(元),总价
+项目预估金额,总价
+预估总价,总价
+预估合同金额,总价
+合同预计金额,总价
+预计合同金额,总价
+合同估算金额,总价
+预估合同总金额,总价
+合同金额预计值,总价
+估算合同金额数目,总价
+是否适宜中小企业采购预算预留,预留面向中小企业采购金额
+预计发布招标公告时间,预计采购时间
+招标项目概况,采购需求
+招标内容与范围,名称;采购需求
+投资估算价,总价
+估算价,总价
+投资估算,总价
+预计招标时间,预计采购时间
+招标人名称,采购单位
+招标(采购)人名称,采购单位
+招标人(采购人),采购单位
+建设单位业主,采购单位
+采购业主单位,采购单位
+建设(业主)单位,采购单位
+项目发起单位,采购单位
+招标人,采购单位
+招标人,采购单位
+采购单位,采购单位
+发包单位,采购单位
+询价单位,采购单位
+采购人信息,采购单位
+采购人信息名称,采购单位
+采购人信息名称,采购单位
+采购业主,采购单位
+采购人,采购单位
+采购人,采购单位
+采购人单位名称,采购单位
+釆购人名称单位,采购单位
+招标人,采购单位
+采购人(甲方),采购单位
+甲方(采购人),采购单位
+甲方(需方),采购单位
+采购人名称,采购单位
+采购方名称,采购单位
+采购人单位,采购单位
+采购方,采购单位
+业主单位,采购单位
+招标组织方,采购单位
+拟定采购单位,采购单位
+招标方,采购单位
+比选人,采购单位
+招标单位,采购单位
+报名地点招标人,采购单位
+联系人及联系电话采购人,采购单位
+采购项目的名称招标人,采购单位
+联系事项采购人,采购单位
+采购单位名称,采购单位
+采购人单位*,采购单位
+招标人,采购单位
+采购人/招标代理机构,采购单位
+招标人/招标代理机构,采购单位
+联系方式招标人,采购单位
+备注招标人,采购单位
+招标人招标人,采购单位
+招标联系事项采购人,采购单位
+采购医院,采购单位
+项目单位,采购单位
+项目法人单位,采购单位
+项目业主,采购单位
+业主,采购单位
+委托人,采购单位
+委托方,采购单位
+委托人名称,采购单位
+主办单位,采购单位
+业主方,采购单位
+招商人,采购单位
+发包人名称,采购单位
+发包人,采购单位
+采购实施单位,采购单位
+甲方,采购单位
+甲方单位,采购单位
+甲方单位名称,采购单位
+合同甲方名称,采购单位
+合同甲方,采购单位
+使用单位,采购单位
+联系方式单位,采购单位
+询价人,采购单位
+采购执行方,采购单位
+申请单位,采购单位
+招标人名称/招标代理机构,采购单位
+项目实施机构,采购单位
+委托单位,采购单位
+需求单位,采购单位
+采购商,采购单位
+招标人(盖章),采购单位
+项目业主(盖章),采购单位
+建设单位,采购单位
+建设单位名称,采购单位
+招租人,采购单位
+招租方,采购单位
+招租人名称,采购单位
+招租方名称,采购单位
+询价方,采购单位
+发布单位,采购单位
+出租方名称,采购单位
+组织单位,采购单位
+邀请人,采购单位
+招标采购单位,采购单位
+采购部门,采购单位
+采购部门名称,采购单位
+采购需求单位,采购单位
+采购组织单位,采购单位
+询价业主单位,采购单位
+招标发布单位名称,采购单位
+招标单位名称,采购单位
+招标部门,采购单位
+发布公司,采购单位
+发起单位,采购单位
+招采组织单位,采购单位
+招标业主,采购单位
+竞标人(名称),采购单位
+项目业主单位,采购单位
+业主名称,采购单位
+项目申请人,采购单位
+采购需求人,采购单位
+调研单位,采购单位
+项目委托单位,采购单位
+采购组织机构,采购单位
+采购公司,采购单位
+甄选人,采购单位
+交易发起人,采购单位
+中标人单位名称,中标单位
+中标企业名称,中标单位
+承包商,中标单位
+意向供应商为,中标单位
+承包单位,中标单位
+承包单位名称,中标单位
+承包方名称,中标单位
+承包企业名称,中标单位
+中标人(公司名称),中标单位
+乙方(供应商公章)名称,中标单位
+供应方(乙方),中标单位
+代建单位,中标单位
+第一承包候选人,中标单位
+第一成交候选商,中标单位
+第一成交人,中标单位
+中标候选人第1名,中标单位
+单一来源供应商名称,中标单位
+中标单位名称,中标单位
+签约单位,中标单位
+推荐中选候选人,中标单位
+推荐承包候选人,中标单位
+投标人名称,中标单位
+投标人,中标单位
+投标商名称,中标单位
+自报价厂商,中标单位
+报价人名称,中标单位
+报价人,中标单位
+中标公司,中标单位
+中标人(公司名称),中标单位
+拟中标公司,中标单位
+预中标公司,中标单位
+预中标企业,中标单位
+中标商名称,中标单位
+成交供应商名称,中标单位
+拟定供应商名称,中标单位
+竞得人名称,中标单位
+中签单位名称,中标单位
+中标单位,中标单位
+中标商家,中标单位
+第一名中标人,中标单位
+第一中标候选人,中标单位
+中标信息中标人,中标单位
+中标供应商,中标单位
+中标定点施工单位,中标单位
+中标人代码,中标单位
+中标人名称,中标单位
+中标/成交人名称,中标单位
+中标人/成交人,中标单位
+中标人,中标单位
+中标方,中标单位
+中标人名单,中标单位
+中标人候选人,中标单位
+第一中标候选人名称,中标单位
+第一中标候选人名称,中标单位
+第一中标名称,中标单位
+第一中标候选人名称,中标单位
+中标候选人第一名,中标单位
+中标侯选人,中标单位
+中标候选人名称,中标单位
+成交候选人名称,中标单位
+中选人,中标单位
+入围中标人,中标单位
+成交人,中标单位
+成交方,中标单位
+成交人及地址,中标单位
+确定成交结果单位,中标单位
+预成交单位,中标单位
+成交人名,中标单位
+成交信息成交人,中标单位
+拟确定中标人,中标单位
+拟中标人,中标单位
+拟中标单位,中标单位
+拟定中标人,中标单位
+成交单位,中标单位
+成交人单位,中标单位
+成交人单位名称,中标单位
+成交供应商,中标单位
+成交供货商名称,中标单位
+成交供应商是,中标单位
+供货商名称,中标单位
+预成交供应商,中标单位
+中标商,中标单位
+供应商,中标单位
+被邀请供应商,中标单位
+供货方,中标单位
+预中标人,中标单位
+预中标单位,中标单位
+中标供应商名称,中标单位
+中标供应商名称地址,中标单位
+拟中标供应商,中标单位
+唯一供应商名称,中标单位
+推荐的第一入围候选供应商,中标单位
+第一推荐中标候选人为,中标单位
+拟定唯一供应商名称,中标单位
+拟定唯一供应商的名称,中标单位
+预中标供应商,中标单位
+采购人拟推荐供应商,中标单位
+询价成交供应商,中标单位
+磋商成交供应商,中标单位
+确定预成交供应商,中标单位
+单来源供应商,中标单位
+拟定的单来源供应商,中标单位
+中标/成交供应商,中标单位
+中标推荐单位,中标单位
+中标候选人,中标单位
+中标候选人名,中标单位
+成交单位名称,中标单位
+成交单位名称1,中标单位
+成交企业,中标单位
+成交候选人,中标单位
+拟成交单位,中标单位
+谈判成交单位,中标单位
+拟定的供应商,中标单位
+拟成交供应商,中标单位
+拟中标候选人,中标单位
+拟定中标单位,中标单位
+供应商名单,中标单位
+入围成交供应商,中标单位
+第一候选成交人,中标单位
+第一名中选候选人,中标单位
+中标侯选单位,中标单位
+第一中标候选人,中标单位
+第一中标候选人单位名称,中标单位
+第一中标候选人投标人名称,中标单位
+第一中标候选供应商,中标单位
+第一中选候选人,中标单位
+施工标段中标候选人,中标单位
+第一投标候选人,中标单位
+第一名成交供应商,中标单位
+第一成交供应商,中标单位
+第一中标人,中标单位
+第一中标供应商,中标单位
+第一合格中标候选人,中标单位
+成交人供应商,中标单位
+中标供应商名称及中标金额,中标单位
+中标信息单位,中标单位
+中标内容单位,中标单位
+中标结果单位,中标单位
+中签单位,中标单位
+中选单位,中标单位
+中选机构名称,中标单位
+中选代理机构,中标单位
+项目成交单位,中标单位
+中标内容及结果单位,中标单位
+中标单位单位,中标单位
+候选人,中标单位
+中标单位名称及中标金额,中标单位
+中选供应商,中标单位
+中标候选供应商,中标单位
+中选候选人第一名,中标单位
+中选候选人,中标单位
+中候选人,中标单位
+中标备选人,中标单位
+中标投标单位,中标单位
+中标投标方名称,中标单位
+投标单位,中标单位
+入围资格供应商,中标单位
+拟定成交供应商,中标单位
+标段拟中标人,中标单位
+预选中标单位,中标单位
+拟中标人成交人,中标单位
+拟中选公司,中标单位
+第一中标人候选人,中标单位
+第一中标侯选人,中标单位
+第一预中标人,中标单位
+第一预成交供应商,中标单位
+第一顺序中标供应商,中标单位
+第一成交候选人,中标单位
+第一成交\\n候选人,中标单位
+第一成交候选供应商,中标单位
+第一包中标供应商,中标单位
+第一包中标人,中标单位
+第一中标排序单位,中标单位
+第一排序人,中标单位
+第1中标候选人,中标单位
+第1中标单位,中标单位
+第一中标候选单位,中标单位
+第一后备中标候选人,中标单位
+第一候选人,中标单位
+第一入围候选人,中标单位
+第一名中标候选人,中标单位
+第一名,中标单位
+入围供应商,中标单位
+磋商入围供应商,中标单位
+拟定供应商,中标单位
+拟定的唯一供应商,中标单位
+拟成交人,中标单位
+拟成交人名称,中标单位
+拟推荐中标候选人,中标单位
+推荐中标候选人,中标单位
+第一标段预中标人,中标单位
+预成交供应商名称更正,中标单位
+一标段预中标单位,中标单位
+一标段中标人,中标单位
+主体单位,中标单位
+中包候选人,中标单位
+中标候选单位1,中标单位
+中标候选单位,中标单位
+最终供应商,中标单位
+预入围单位,中标单位
+候选成交人,中标单位
+入围单位,中标单位
+成交商,中标单位
+成交响应人,中标单位
+成交响应方名称,中标单位
+投标商,中标单位
+报价单位,中标单位
+供货单位,中标单位
+本项目拟供货单位,中标单位
+首年供货单位名称,中标单位
+承包人名称,中标单位
+乙方,中标单位
+乙方单位,中标单位
+乙方单位名称,中标单位
+乙方为,中标单位
+卖方,中标单位
+供应商,中标单位
+中标投标人名称,中标单位
+中标服务商名称,中标单位
+中标投标人,中标单位
+中标服务商,中标单位
+中选企业,中标单位
+中选机构,中标单位
+合同乙方名称,中标单位
+中标供应商名称及中标价格,中标单位
+中标候选人1,中标单位
+成交候选人如下,中标单位
+拟定的唯一供货商,中标单位
+第一中选人,中标单位
+中标供应商及地址,中标单位
+中标成交供应商,中标单位
+标段中标供应商,中标单位
+中标企业,中标单位
+中标候选人单位名称,中标单位
+中标/成交供应商名称,中标单位
+成交候选供应商,中标单位
+成交候选供应商名称,中标单位
+中标候选供应商名称,中标单位
+单一来源供应商,中标单位
+单一来源供货商,中标单位
+候选单位名称,中标单位
+第1候选人,中标单位
+成交单位名称(联合体牵头人),中标单位
+供应商(乙方),中标单位
+询价中标结果,中标单位
+成交电商,中标单位
+成交服务商,中标单位
+供货服务商,中标单位
+成交参选人,中标单位
+承接单位,中标单位
+入围供应商名称,中标单位
+入围供应商名称,中标单位
+竞得人,中标单位
+中标意向单位,中标单位
+中标(成交)供应商,中标单位
+拟承包人,中标单位
+谈判结果,中标单位
+中选人单位名称,中标单位
+自报价厂商,中标单位
+成交名称,中标单位
+中标结果,中标单位
+第一成交供应商名称,中标单位
+入围供应商候选人,中标单位
+承包人,中标单位
+中标候选单位名称,中标单位
+候选人排序单位名称,中标单位
+中标人名称及地址,中标单位
+拟定的唯一供应商名称及其地址,中标单位
+成交供应商名称及地址,中标单位
+成交人名称及地址,中标单位
+终选定,中标单位
+成交合作商,中标单位
+合作伙伴,中标单位
+合作公司,中标单位
+成交合作伙伴,中标单位
+排名单位名称,中标单位
+成交单位/地址,中标单位
+标包名称单位名称,中标单位
+中选候选人名称,中标单位
+中标方案的单位名称及地址,中标单位
+中标供货商,中标单位
+第一备选供应商,中标单位
+拟单一来源供应商名称,中标单位
+确定的中标人,中标单位
+第一候选单位,中标单位
+确定中标供应商为,中标单位
+第一入围供应商名称,中标单位
+预中标人单位,中标单位
+意向供应商,中标单位
+成交中介机构,中标单位
+第1中选候选人,中标单位
+中标候逃人第1名,中标单位
+第一中标排序人,中标单位
+中选人名称,中标单位
+中标信息第1名,中标单位
+中选单位名称,中标单位
+首选中标人,中标单位
+中标供应商信息供应商名称,中标单位
+中标厂商为,中标单位
+拟定的唯一供应商名称,中标单位
+成交人名称,中标单位
+成交人的名称,中标单位
+拟采购供应商,中标单位
+成交商家,中标单位
+中标单位单位名称,中标单位
+中标成交供应商名称,中标单位
+首选成交供应商,中标单位
+供应商名称,中标单位
+供应商(乙方),中标单位
+供应厂商,中标单位
+报价公司,中标单位
+配送企业,中标单位
+中选中介机构名称,中标单位
+中选中介机构,中标单位
+中选的中介机构为,中标单位
+中选企业名称,中标单位
+交易结果候选人名称,中标单位
+成交服务商名称,中标单位
+成交候选供应商及委托代理人,中标单位
+第一中标排序单位名称,中标单位
+公示推荐候选人,中标单位
+拟定单一来源采购供应商的名称,中标单位
+单一来源采购供应商,中标单位
+本次单一来源采购拟选供应商为,中标单位
+预中标社会资本方,中标单位
+确定本项目的合作商为,中标单位
+中包单位名称,中标单位
+第一询价结果候选人,中标单位
+推荐候选人名称,中标单位
+询比候选人,中标单位
+入围投标人,中标单位
+受让方名称,中标单位
+中标竞买人名称,中标单位
+拟中选公司,中标单位
+中商人,中标单位
+中商候选人,中标单位
+定标候选人,中标单位
+施工单位,中标单位

+ 128 - 0
docs/table_head_doc/general_label.csv

@@ -0,0 +1,128 @@
+"采购计划任务"
+"采购公告"
+"招标文件预公示"
+"招标预公告"
+"计划招标公告"
+"调研公告"
+"预申公告"
+"预审文件"
+"预审公告更正公告"
+"预审结果"
+"预审结果公示"
+"预审结果"
+"预审结果的公示"
+"预审结果变更"
+"论证意见公示"
+"需求论证公示"
+"征求意见公告"
+"进口产品公示"
+"需求公告"
+"直接采购公告"
+"需求公示"
+"采购公告"
+"采购项目"
+"项目公告"
+"招标公告"
+"意向公开"
+"比选公告"
+"邀请公告"
+"采购邀请"
+"邀请书"
+"邀请函"
+"询价采购"
+"询价公告"
+"比价公告"
+"比价项目公告"
+"建设项目"
+"中标(成交)公告"
+"服务"
+"项目"
+"合同公告"
+"比价项目公告"
+"比质比价"
+"比质比价公告"
+"询价采购公告"
+"询价书"
+"询价单"
+"询价采购"
+"公开询价"
+"询价邀请书"
+"竞价交易公告"
+"竞价公告"
+"竞价项目"
+"竞价的公告"
+"竞价采购公告"
+"变更公告"
+"更正公告"
+"暂停公告"
+"候选人公示"
+"候选人公示"
+"结果公告"
+"结果公示"
+"服务项目"
+"成交公告"
+"中选人公示"
+"中选结果公示"
+"中标公示"
+"中标公告"
+"成交公示"
+"废标公告"
+"终止公告"
+"异常公告"
+"流标公告"
+"失败公告"
+"合同公告"
+"合同信息"
+"采购合同"
+"销售合同"
+"集成合同"
+"项目合同"
+"合同公示"
+"服务合同"
+"验收公告"
+"验收单公示"
+"标段"
+"单一来源采购公示"
+"考试培训"
+"比价单"
+"项目询价"
+"采购项目"
+"询价"
+"竞争性谈判"
+"竞争性磋商"
+"单一来源"
+"竞价处置公告"
+"网上竞价"
+"结果公告"
+"结果公示"
+"中标公示"
+"中标公告"
+"公告"
+"合同"
+"评审失败"
+"招标失败"
+"比选失败"
+"采购失败"
+"流标公示"
+"项目合同"
+"验收结果"
+"验收公告"
+"行政处罚"
+"违约行为"
+"投诉"
+"不良行为"
+"协议书"
+"候选人"
+"购置"
+"公示"
+"建设"
+"中标"
+"招标"
+"工程"
+"采购"
+"成交通知书"
+"公告公告"
+"项目项目"
+"合同合同"
+"nbsp"
+"..."

+ 119 - 0
docs/table_head_doc/projectcode.csv

@@ -0,0 +1,119 @@
+"项目编码"
+"项目编号"
+"采购项目编号"
+"招标项目编号"
+"招标编号"
+"采购编号"
+"招标项目编码"
+"本项目招标编号"
+"本项目编号为"
+"采购编码"
+"公告编号"
+"公告编码"
+"交易项目编号"
+"政府采购编号"
+"项目名称及项目编号"
+"工程项目编号"
+"项目招标编号"
+"采购项目编码"
+"招标工程项目编号"
+"招标文件编号"
+"招标编码"
+"招标公告编号"
+"采购公示编号"
+"采购代理机构编号"
+"询价书编号"
+"询价采购编号"
+"询介公示编码"
+"询价编号"
+"网上询价编号"
+"询价单号"
+"询价单编号"
+"项目名称及编号"
+"采购项目名称及编号"
+"采购项目编号、包号"
+"招标编号/包号"
+"标段编号"
+"标段编码"
+"采购项目编号/包号"
+"标包编号"
+"项目包编号"
+"项目标号"
+"标段(包)编号"
+"采购项目子包编号"
+"比选编号"
+"网上竞价编号"
+"竞价编号"
+"单一来源编号"
+"采购单号"
+"电商订单编号"
+"采购清单编号"
+"招募代理编号"
+"委托代理编号"
+"比选代理编码"
+"采购代理机构编号"
+"工程编号"
+"工程名称编号"
+"建设工程交易编号"
+"成交公告编号"
+"中标公告编号"
+"采购项目编号(采购计划编号)"
+"采购项目编号(建议书编号)"
+"报建编号"
+"招募项目编号"
+"交易编号"
+"进场交易编号"
+"机构项目编码"
+"项目标书编号"
+"意见征询编号"
+"谈判文件编号"
+"项目名称及谈判文件编号"
+"采购文件编号"
+"文件编号"
+"采购文件序号"
+"磋商文件编号"
+"采购项目编号(采购计划编号)"
+"项目代码"
+"项目编号(或招标编号、政府采购计划编号、采购计划备案文号等,如有)"
+"包件编码"
+"采购计划备案编号"
+"竞价项目编号"
+"招标备案号"
+"财政委托编号"
+"本项目备案号"
+"采购项目标书编号"
+"项目基本情况项目编号"
+"采购计划备案文号"
+"招标项目标段编号"
+"订购单编号"
+"招投标编码"
+"投资项目统一代码"
+"采购单编号"
+"计划文号"
+"事项编号"
+"采购计划号"
+"备案编号"
+"立项批准文号"
+"公共资源编号"
+"包件编号"
+"项目号项目号"
+"公共资源交易编号"
+"(包)编号"
+"包件编码"
+"公示编号"
+"包组编号"
+"采购执行编号"
+"备案项目编号"
+"采购条目编号"
+"政府采购计划编号"
+"政府采购计划备案编号"
+"政府采购计划备案号"
+"采购计划编号"
+"计划编号"
+"任务书编号"
+"批复文号"
+"包件号"
+"采购计划文号"
+"采购代理编号"
+"招标代理编号"
+"询价文件编号"

二进制
docs/table_head_doc/table_head_clf_model


二进制
docs/table_head_doc/table_head_le


二进制
docs/table_head_doc/table_head_vocab


二进制
docs/乡镇.xlsx


二进制
docs/区县.xlsx


二进制
docs/市.xlsx


二进制
docs/省份.xlsx


+ 75 - 0
quality_server.py

@@ -0,0 +1,75 @@
+# coding:utf-8
+
+from a2s.a2s_server import simple_params, watch
+from a2s.tools import json_deserialize, json_serialize
+from app import check
+from docs.config import ReluMongodb
+from util.mogodb_helper import MongoDBInterface
+import time
+
+ReluClient = MongoDBInterface(ReluMongodb)
+
+Rules = {}
+ClearTime = 0
+
+
+def clear_timeout_rules():
+    """
+    清理超时的规则
+    """
+    global Rules
+    p_clear = []
+    for rules_id, r in Rules.items():
+        if time.time() - r["time"] > 1800:
+            p_clear.append(rules_id)
+    for rules_id in p_clear:
+        Rules.pop(rules_id)
+
+
+def get_rule(rules_id):
+    """
+    获取规则
+    """
+    global Rules
+    global ClearTime
+    if time.time() - ClearTime > 1800:
+        clear_timeout_rules()
+        ClearTime = time.time()
+    if rules_id in Rules:
+        return Rules[rules_id]["relus"]
+    else:
+        rule_row = ReluClient.find_relus(ReluMongodb["col"], rules_id)
+        if rule_row:
+            rules = rule_row.get("rules", {})
+            Rules[rules_id] = {}
+            Rules[rules_id]["time"] = int(time.time())
+            Rules[rules_id]["relus"] = rules
+            return rules
+    return None
+
+
+@simple_params
+@watch
+def server_start(data: bytes, *args, **kwargs):
+    data = json_deserialize(data)
+    row = data.get("data", {})
+    rules_id = data.get("rules_id", None)
+    rules = get_rule(rules_id)
+    if not rules or not row:
+        data = {
+            "code": 500,
+            "msg": "失败:规则与检测数据不能为空",
+            "data": {}
+        }
+    else:
+        result = check(row, rules)
+        data = {
+            "code": 200,
+            "msg": "成功",
+            "data": result
+        }
+    return json_serialize(data)
+
+
+if __name__ == '__main__':
+    server_start()

+ 38 - 0
score.py

@@ -0,0 +1,38 @@
+from pymongo import MongoClient
+from bson import ObjectId
+
+def bid_score():
+    db = MongoClient('192.168.3.167', 27080, unicode_decode_error_handler="ignore").jyqyfw_historyData2023_1
+    coll_user = db["20230921Ssk_endo"]
+    # db = MongoClient('192.168.3.166', 27082, unicode_decode_error_handler="ignore").yantianlei
+    # coll_user = db["20230920Zglt_9_1"]
+    # db = MongoClient('192.168.3.166', 27082, unicode_decode_error_handler="ignore").zhaoxiuzhen
+    # coll_user = db["20230917LT_ycl"]
+    count=0
+    score=100
+    # for item in coll_user.find({"_id":ObjectId("64dc2bea5b7b9126edac6845")}):
+    for item in coll_user.find().sort("_id",1):
+        # if item['title_qa']:
+        #      score-=10
+        if item['projectname_qa']:
+            score-=10
+        if item['area_qa']:
+            score-=10
+        if item['projectcode_qa']:
+            score-=10
+        # if item['bidopentime_qa']:
+        #     score-=10
+        if item['buyer_qa']:
+            score-=10
+        if item['winner_qa']:
+            score-=10
+        if item['budget_qa']:
+            score-=10
+        if item['bidamount_qa']:
+            score-=10
+        if item["multipackage_qa"]:
+            score -= 10
+        print(score)
+        coll_user.update_one({"_id": item["_id"]}, {"$set": {"score": score}})
+        score = 100
+bid_score()

+ 90 - 0
tables/__init__.py

@@ -0,0 +1,90 @@
+# coding:utf-8
+
+from docs.config import ai2config
+from tables.ai.table_field_category import TableFieldCategoryModel
+from tables.ai import fields_ner
+from util.info_preprocess import Preprocess
+from util.fs_client import FileServeClient
+import re
+from util.mogodb_helper import MongoDBInterface
+
+# 初始化
+fsc = FileServeClient()   # oss客户端
+preprocess = Preprocess()  # 文本预处理程序(html,attach)
+tfc_object = TableFieldCategoryModel(ai2config["table_field_config"])  # 表格字段识别模型实例
+
+
+class CatchContentObject(object):
+    """
+    缓存
+    """
+
+    def __init__(self):
+        self.catch = {}
+
+    def public_attachment_catch(self, content, platform, document_id):
+        if document_id in self.catch:
+            return self.catch[document_id]
+        contents = preprocess.get_preprocess(platform).preprocess(content)
+        contents=contents.replace("(","(").replace(")",")")
+        contents = contents.split("\n")
+        contents = [c for c in contents if c.strip()]
+        self.catch[document_id] = contents
+        return contents
+
+    def initialize(self):
+        self.catch = {}
+
+
+def match_company_index(companies: list, content: str):
+    """
+    获取公司所在文本位置
+    :param companies:公司列表
+    :param content:文本
+    :return:
+    """
+    companies.sort(key=lambda x: len(x), reverse=True)
+    match_index = []
+    pattern = r"|".join(companies)
+    repatten = pattern.replace(")", "\)").replace("(", "\(").replace(".", "\.").replace("*", "\*")
+    for company in re.finditer(repatten, content):
+        start_index = company.start()
+        company_name = company.group()
+        end_index = company.end()
+        match_index.append((start_index, end_index, company_name))  # (start_index,company_name)
+    return match_index
+
+
+def key_value_header(content):
+    """
+    获取content中的键值
+    :param content:文本
+    :return:
+    """
+    head = []
+    ret = fields_ner(text=content)
+    result = ret.get("result", [])
+    if result:
+        head = result[0].get("HEAD", [])
+    return head
+
+
+def clear_spacing(data_list):
+    '''
+    清理二维列表中的空值、空格
+    :param data_list: 待处理的二维列表
+    :return: 处理后的二维列表
+    '''
+    new_data_list = []
+    # 遍历原始列表的每一行
+    for row in data_list:
+        new_row = []
+        for elem in row:
+            # 如果元素为None,则将其转换为空字符串
+            new_row.append("") if not elem else new_row.append(elem.replace(" ", ""))
+        new_data_list.append(new_row)
+    return new_data_list
+
+if __name__ == '__main__':
+    ret = match_company_index("中标单位:xxxx公司")
+    print(ret)

二进制
tables/__pycache__/__init__.cpython-37.pyc


+ 83 - 0
tables/ai/__init__.py

@@ -0,0 +1,83 @@
+# coding:utf-8
+from a2s.a2s_client import a2s_execute
+from a2s.tools import json_serialize, json_deserialize
+from loguru import logger
+from docs.config import FieldServer, RecognitionServer, ProductServer
+
+
+def fields_ner(text):
+    """
+    抽取文本字段
+    :param text:
+    :return:
+    """
+    try:
+        if len(text) > 2000: return {}
+        request_body = {"text": text}
+        for r in range(FieldServer["retry_times"]):
+            bytes_data = json_serialize(request_body)
+            result = a2s_execute(FieldServer["a2s_ip"], FieldServer["topic"], FieldServer["timeout"], bytes_data)
+            if result is None:
+                continue
+            response_json = json_deserialize(result)
+            if response_json.get("ucode", 0) != 200:
+                return {}
+            return response_json
+    except Exception as e:
+        logger.info(str(e))
+        return {}
+
+
+def org_ner(text):
+    """
+    抽取物品
+    :param text:
+    :return:
+    """
+    try:
+        companies = []
+        if len(text) > 2000:
+            return companies
+        request_body = {"text": text}
+        bytes_data = json_serialize(request_body)
+        for r in range(RecognitionServer["retry_times"]):
+            result = a2s_execute(RecognitionServer["a2s_ip"], RecognitionServer["topic"], RecognitionServer["timeout"],
+                                 bytes_data)
+            if result is None:
+                continue
+            response_json = json_deserialize(result)
+            if response_json.get("ucode", 0) != 200:
+                return companies
+            output = response_json.get("output", [])
+            for text in output:
+                text_type = text.get("type", "")
+                if text_type == "ORG":
+                    companies.append(text.get("span", ""))
+            return companies
+    except Exception as e:
+        logger.info(str(e))
+        return {}
+
+
+def product_detail_server(text):
+    """
+    物品
+    :param text:
+    :return:
+    """
+    try:
+        ret = a2s_execute(ProductServer["a2s_ip"], ProductServer["topic"], ProductServer["timeout"],
+                          bytes_data=json_serialize({"text": text}))
+        model_dict = json_deserialize(ret)
+        model_dict = model_dict if isinstance(model_dict, dict) else {}
+        return model_dict
+    except Exception as e:
+        print(e)
+        return {}
+
+
+if __name__ == '__main__':
+    data = "型号:清廉长沙水350ml"
+    # result = org_ner(data)
+    result = product_detail_server(data)
+    print(result)

二进制
tables/ai/__pycache__/__init__.cpython-37.pyc


二进制
tables/ai/__pycache__/table_field_category.cpython-37.pyc


+ 181 - 0
tables/ai/table_field_category.py

@@ -0,0 +1,181 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# 文本分类 (多元分类)
+import pandas as pd
+from sklearn.utils import shuffle
+import torch as t
+from util.dictionary import Dictionary
+import jieba
+import os
+import joblib
+from docs.config import ai2config
+
+table_field_config = ai2config["table_field_config"]
+jieba.add_word('型号')
+jieba.add_word('规格')
+jieba.add_word('设备')
+jieba.add_word('名称')
+
+EMBED_DIM = 300
+vocab_file = table_field_config['vocab_file']
+
+ct = Dictionary(stopwords=[])
+
+
+class TableFieldCategoryModel(object):
+    def __init__(self, config):
+        self._corpus_path = config.get("corpus_path")
+        self._epochs = config.get("epochs", 500)
+        self._lr = config.get("lr", 1e-3)
+        self._momentum = config.get("momentum", 0.5)
+        self._output = config.get("output", 2)
+        self._vocab_file = config.get("vocab_file")
+        self._model_path = config.get("model_path")
+        self._vocab_label = config.get("vocab_label")
+        self._model = ""
+        self.label2decode = ""
+
+    def create_train_data(self):
+        """
+        训练数据生成
+        :return:
+        """
+        if not os.path.exists(self._corpus_path):
+            raise FileExistsError("文件不存在")
+        label_data = pd.read_csv(self._corpus_path)
+        label_data.drop_duplicates(['corpus'], inplace=True)
+        label_data = shuffle(label_data)
+        corpus = label_data['corpus'].values
+        category = label_data['label'].values
+        ct.append_vocab(text=corpus, need_cut=True)
+        ct.build_dictionary(tfidf_limit=1e-6, vocab_file=vocab_file)
+        # 查验数据
+        print('词量:', len(ct.dictionary))
+        global EMBED_DIM
+        EMBED_DIM = len(ct.dictionary)
+
+        x_vector = ct.vector_corpus(corpus=corpus, dim=EMBED_DIM, use_tfidf=False, return_type='one_hot')
+        label2encode, label2decode = {}, {}
+        category = [str(c).split(';') for c in category]
+        for c in category:
+            for w in c:
+                if not (w in label2encode):
+                    label2encode[w] = len(label2encode)
+        label2decode = dict(list(zip(label2encode.values(), label2encode.keys())))
+        y = []
+        label_len = len(label2encode)
+        print('classes::', label_len)
+        for c in category:
+            y1 = [0] * label_len
+            for w in c:
+                y1[label2encode[w]] = 1
+            y.append(y1)
+
+        joblib.dump((label2encode, label2decode), self._vocab_label)
+        return x_vector, y, label2encode, label2decode
+
+    @staticmethod
+    def make_nn(input_size, output_size):
+        return t.nn.Sequential(
+            t.nn.Linear(input_size, input_size // 2),
+            t.nn.ReLU(inplace=True),
+            t.nn.Linear(input_size // 2, input_size // 4),
+            t.nn.ReLU(inplace=True),
+            t.nn.Linear(input_size // 4, output_size),
+            t.nn.Sigmoid() if output_size == 2 else t.nn.Softmax(dim=1),
+        )
+
+    def train(self):
+        x_vector, y, le, _ = self.create_train_data()
+        print('classes:', len(le))
+        mlp = self.make_nn(EMBED_DIM, len(le))
+        optimizer = t.optim.SGD(mlp.parameters(), lr=self._lr, momentum=self._momentum)
+        lossfunc = t.nn.BCELoss()
+
+        x_vector = t.autograd.Variable(t.tensor(x_vector).float())
+        y = t.autograd.Variable(t.tensor(y).float())
+
+        for epoch in range(self._epochs):
+            outputs = mlp(x_vector)
+            optimizer.zero_grad()
+            acc(outputs, y)
+            loss = lossfunc(outputs, y)
+            loss.backward()
+            optimizer.step()
+            print('epoch:', epoch, 'loss:', loss.data.numpy())
+            if loss.data.numpy() < 0.01:
+                print('提前结束训练')
+                break
+        t.save(mlp.state_dict(), self._model_path)
+
+    def predict(self, corups):
+        global EMBED_DIM
+        if not self._model:
+            ct.load_dictionary(vocab_file=vocab_file)
+            EMBED_DIM = len(ct.dictionary)
+            le, self.label2decode = joblib.load(self._vocab_label)
+            self._model = self.make_nn(EMBED_DIM, len(self.label2decode))
+            self._model.load_state_dict(t.load(self._model_path))
+        x_vector = ct.vector_corpus(corups, dim=EMBED_DIM, return_type='one_hot', use_tfidf=False)
+        x = t.tensor(x_vector).float()
+        x = x.view(x.size()[0], -1)
+        x = t.autograd.Variable(x)
+        y = self._model(x)
+        ret = []
+        for r in y.data.numpy():
+            row_label = []
+            for i, w in enumerate(r):
+                if w >= 0.20:
+                    row_label.append(self.label2decode[i])
+            ret.append(row_label)
+        return ret
+
+    def val(self):
+        global EMBED_DIM
+        ct.load_dictionary(vocab_file=vocab_file)
+        EMBED_DIM = len(ct.dictionary)
+        le, de = joblib.load(self._vocab_file)
+        label_data = pd.read_csv(self._corpus_path)
+        label_data.drop_duplicates(['corpus'], inplace=True)
+        label_data = shuffle(label_data)
+        corpus = label_data['corpus'].values
+        category = label_data['label'].values
+        x_vector = ct.vector_corpus(corpus, dim=EMBED_DIM, return_type='one_hot', use_tfidf=False)
+        mlp = self.make_nn(EMBED_DIM, len(de))
+        mlp.load_state_dict(t.load(self._model_path))
+        x = t.tensor(x_vector).float()
+        x = x.view(x.size()[0], -1)
+        x = t.autograd.Variable(x)
+        y = mlp(x)
+        ret = []
+        for r in y.data.numpy():
+            row_label = []
+            for i, w in enumerate(r):
+                if w >= 0.35:
+                    row_label.append(de[i])
+            ret.append(row_label)
+        print(list(zip(category, ret)))
+        count = 0
+        for i in list(zip(category, ret)):
+            if len(i[1]) == 1:
+                if i[0] == i[1][0]:
+                    count += 1
+            else:
+                print(i)
+                if i[0].split(';') == i[1]:
+                    count += 1
+        print(count / len(category))
+
+
+def acc(outputs, y):
+    b = outputs > 0.25
+    b = b.data.numpy()
+    a = y > 0.5
+    a = a.data.numpy()
+    count = 0
+    print(len(a))
+    for i in range(len(a)):
+        if (a[i] == b[i]).all():
+            count += 1
+    print("**********************************", count / len(a))
+

+ 244 - 0
tables/fields/NoField.py

@@ -0,0 +1,244 @@
+# coding:utf-8
+
+from tables import CatchContentObject, fsc
+from util.sensitive_word import AcAutomation
+from docs.config import amount_config
+from docs.config import budget_config
+from docs.config import DEBUG
+from docs.config import abnormal_config
+import csv
+
+class NoFieldChecker(object):
+    """
+        无字段或空值检查
+    """
+    def __init__(self):
+        self.errors_tables = {
+            "title": self.check_title,
+            "projectname": self.check_projectname,
+            "buyer":self.check_buyer,
+            "winner": self.check_winner,
+            "budget": self.check_budget,
+            "bidamount": self.check_bidamount,
+            "area":self.check_region,
+            "projectcode": self.check_projectcode,
+            "multipackage":self.check_subpackage,
+        }
+
+    def check_bidamount(self,obj,catch_content: CatchContentObject) -> bool:
+        """
+        中标金额为空检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        self.check_bidamount_ac = AcAutomation()
+        with open(amount_config["table_field_config"]["path"], "r") as f:
+            reads = csv.reader(f)
+            [self.check_bidamount_ac.add_word(w[0]) for w in reads]
+
+        detail = obj.get("detail", "")
+        attach_text = obj.get("attach_text", {})
+        subtype = obj.get("subtype", "")
+        if subtype in ["中标", "成交","合同","验收"]:
+            contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告") #返回值是字典
+            content = "\n".join(contents) #字典处理成字符串
+            if self.check_bidamount_ac.search(content):
+                return True
+
+            for attach_index, attach_content in attach_text.items():
+                if attach_content:
+                    for topic_index, topic_detail in attach_content.items():
+                        # oss地址
+                        attach_url = topic_detail.get("attach_url", "")
+                        if attach_url:
+                            # 获取附件内容
+                            st, content = fsc.download_text_content(attach_url)
+
+                            # 下载成功
+                            # 超长文本不处理,暂定30万字
+                            if st and content.strip():
+                                if len(content) > 300000:
+                                    continue
+                            # 开始检测
+                            contents = catch_content.public_attachment_catch(content, platform="attach",document_id=attach_url)
+                            content = "\n".join(contents)
+                            if self.check_bidamount_ac.search(content):
+                                    return True
+            return False
+        return False
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+    def check_winner(self,obj, catch_content: CatchContentObject) -> bool:
+        """
+        中标单位名称为空检测,除中标类型的标讯,其他类型标讯不检查这个字段是否为空
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        subtype = obj.get("subtype", "")
+        if subtype in ["中标", "成交", "合同", "验收"]:
+            winner = obj.get("winner", "")
+            if winner:
+                return False
+            return True
+        return  False
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+    def check_buyer(self,obj,catch_content: CatchContentObject) -> bool:
+        """
+        采购单位名称是否为空检测
+        :param buyer:采购单位,多个逗号分割
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        buyer = obj.get("buyer", "")
+        if buyer :
+            return False
+        return True
+
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+    def check_budget(self,obj, catch_content: CatchContentObject) -> bool:
+        """
+        预算为空检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        self.check_budget_ac = AcAutomation()
+        with open(budget_config["table_field_config"]["path"],"r") as f :
+            reads=csv.reader(f)
+            [self.check_budget_ac.add_word(w[0]) for w in reads ]
+
+        detail = obj.get("detail", "")
+        attach_text = obj.get("attach_text", {})
+        subtype = obj.get("subtype", "")
+        if subtype not in ["中标", "成交", "合同", "验收"]:
+            contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告")  # 返回值是字典
+            content = "\n".join(contents)  # 字典处理成字符串
+            if self.check_budget_ac.search(content):
+                return True
+
+            for attach_index, attach_content in attach_text.items():
+                if attach_content:
+                    for topic_index, topic_detail in attach_content.items():
+                        # oss地址
+                        attach_url = topic_detail.get("attach_url", "")
+                        if attach_url:
+                            # 获取附件内容
+                            st, content = fsc.download_text_content(attach_url)
+
+                            # 下载成功
+                            # 超长文本不处理,暂定30万字
+                            if st and content.strip():
+                                if len(content) > 300000:
+                                    continue
+                            # 开始检测
+                            contents = catch_content.public_attachment_catch(content, platform="attach",
+                                                                             document_id=attach_url)
+                            content = "\n".join(contents)
+                            if self.check_budget_ac.search(content):
+                                return True
+            return False
+        return False
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+    def check_region(self,obj, catch_content: CatchContentObject) -> bool:
+        """
+        区域为空检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        pass
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+    def check_title(self,obj, catch_content: CatchContentObject) -> bool:
+        """
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        title = obj.get("title", "")
+        if title :
+            return False
+        return True
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+    def check_projectname(self,obj, catch_content: CatchContentObject) -> bool:
+        """
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        projectname = obj.get("projectname", "")
+        if projectname :
+            return False
+        return True
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+    def check_projectcode(self,obj, catch_content: CatchContentObject) -> bool:
+        """
+        项目编号为空检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        self.check_projectcode_ac = AcAutomation()
+        with open(abnormal_config["table_field_config"]["path4"], "r") as f:
+            reads = csv.reader(f)
+            [self.check_projectcode_ac.add_word(w[0]) for w in reads]
+
+        projectcode = obj.get("projectcode", "")
+        detail = obj.get("detail", "")
+        attach_text = obj.get("attach_text", {})
+        if projectcode == "":
+            contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告") #返回值是字典
+            content = "\n".join(contents) #字典处理成字符串
+            if self.check_projectcode_ac.search(content):
+                return True
+
+            for attach_index, attach_content in attach_text.items():
+                if attach_content:
+                    for topic_index, topic_detail in attach_content.items():
+                        # oss地址
+                        attach_url = topic_detail.get("attach_url", "")
+                        if attach_url:
+                            # 获取附件内容
+                            st, content = fsc.download_text_content(attach_url)
+
+                            # 下载成功
+                            # 超长文本不处理,暂定30万字
+                            if st and content.strip():
+                                if len(content) > 300000:
+                                    continue
+                            # 开始检测
+                            contents = catch_content.public_attachment_catch(content, platform="attach",document_id=attach_url)
+                            content = "\n".join(contents)
+                            if self.check_projectcode_ac.search(content):
+                                    return True
+            return False
+        return False
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+    def check_subpackage(self,obj, catch_content: CatchContentObject) -> bool:
+        """
+        公司名称检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        pass
+        # 处理正文
+        # 检查因素
+        # 是否返回 0000
+
+

+ 15 - 0
tables/fields/__init__.py

@@ -0,0 +1,15 @@
+# coding:utf-8
+from tables.fields.bidamount import BidAmountChecker
+from tables.fields.budget import BudgetChecker
+
+
+class Preprocess(object):
+    """
+    预处理接口
+    """
+
+    def __init__(self):
+        self.__pool = dict(bidamount=BidAmountChecker, budget=BudgetChecker)
+
+
+__all__ = [Preprocess]

二进制
tables/fields/__pycache__/NoField.cpython-37.pyc


二进制
tables/fields/__pycache__/__init__.cpython-37.pyc


二进制
tables/fields/__pycache__/area.cpython-37.pyc


二进制
tables/fields/__pycache__/bidamount.cpython-37.pyc


二进制
tables/fields/__pycache__/budget.cpython-37.pyc


二进制
tables/fields/__pycache__/buyer.cpython-37.pyc


二进制
tables/fields/__pycache__/fieldtype.cpython-37.pyc


二进制
tables/fields/__pycache__/projectcode.cpython-37.pyc


二进制
tables/fields/__pycache__/projectname.cpython-37.pyc


二进制
tables/fields/__pycache__/purchasing.cpython-37.pyc


二进制
tables/fields/__pycache__/subpackage.cpython-37.pyc


二进制
tables/fields/__pycache__/title.cpython-37.pyc


二进制
tables/fields/__pycache__/winner.cpython-37.pyc


+ 80 - 0
tables/fields/area.py

@@ -0,0 +1,80 @@
+import re
+import pandas as pd
+
+class AreaChecker(object):
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "全国类数据",
+                "parent_name": "全国类型",
+                "parent_code": "01",
+                "checkFn": self.check0101
+            },
+            "0201": {
+                "name": "没有市县正文中有",
+                "parent_name": "市县类型",
+                "parent_code": "01",
+                "checkFn": self.check0201
+            }
+        }
+
+    def check0101(self, area: str) -> bool:
+        return area == "全国"
+
+    def check0201(self, area, city, district, detail) -> bool:
+        def find_city_info(query):
+            for index, row in df.iterrows():
+                if query in str(row["地市"]) or query in str(row["地区代码"]):
+                    return {
+                        "省份": row["省份"],
+                        "地市": row["地市"],
+                        "区县": row["区县"],
+                        "父级地区代码": row["父级地区代码"],
+                        "地区代码": row["地区代码"]
+                    }
+            return None
+
+        # 加载地区代码的XLS文件
+        xls_file = "C:\\Users\\25503\\PycharmProjects\\data_quality\\docs\\table_head_doc\\aera.xls"
+        df = pd.read_excel(xls_file)
+
+        detail = re.sub(r"<.*?>", "", detail)
+        # 提取采购单位名称
+        unit_name_pattern = r"采购单位名称:([\s\S]+?)\n"
+        unit_name_match = re.search(unit_name_pattern, detail)
+        purchase_unit_name = unit_name_match.group(1) if unit_name_match else None
+
+        # 提取采购单位地址
+        purchase_unit_address = r"采购单位地址:([\s\S]+?)\n"
+        address_match = re.search(purchase_unit_address, detail)
+        city_from_unit_address = address_match.group(1) if address_match else None
+
+        # 提取项目所在行政区划编码
+        project_district_code = r"项目所在行政区划编码:(\d+)"
+        district_code_match = re.search(project_district_code, detail)
+        district = district_code_match.group(1) if district_code_match else None
+
+        print(f"提取到的区县: {district}")
+        print(f"提取到的地市: {city}")
+        print(f"提取到的省份: {area}")
+
+        if not district:
+            if purchase_unit_name:
+                city_info = find_city_info(purchase_unit_name)
+                print(f"根据单位名称找到的城市信息: {city_info}")
+            if city_info is None and city_from_unit_address:
+                city_info = find_city_info(city_from_unit_address)
+
+            if city_info:
+                if city_info["省份"] == area and city_info["地市"] == city:
+                    print("省份与区域一致,地市与城市一致,不做处理")
+                else:
+                    print("省份或地市与区域不一致,标记为true")
+                    return True
+            else:
+                print("未找到匹配的城市信息,返回true")
+                return True
+
+        else:
+            print("district不为空,保持原有标记")
+            return False   # 保持原有的标记

+ 53 - 0
tables/fields/bidamount.py

@@ -0,0 +1,53 @@
+"""
+    中标金额字段检查
+"""
+
+
+class BidAmountChecker(object):
+    """
+        中标字段检查
+    """
+
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "互相校验(预算和中标金额的比例)",
+                "parent_name": "金额错误",
+                "parent_code": "01",
+                "checkFn": self.check0101
+            },
+            "0102": {
+                "name": "过大过小[100,10亿]",
+                "parent_name": "金额错误",
+                "parent_code": "01",
+                "checkFn": self.check0102
+            }
+        }
+
+    @staticmethod
+    def check0101(budget: float, bidamount: float) -> bool:
+        """
+        预算和中标金额的比例
+        :param budget:
+        :param amount:
+        :return:返回true 代表异常
+        """
+        if budget and bidamount:
+            if 0.7 < budget / bidamount < 1.3:
+                return False
+            else:
+                return True
+        else:
+            # 两者中有一方为空不判断
+            return False
+
+    @staticmethod
+    def check0102(bidamount: float) -> bool:
+        """
+        中标金额过大过小[100,10亿]
+        :param price:
+        :return: 返回true 代表异常
+        """
+        if 100 < bidamount < 1000000000:
+            return False
+        return True

+ 53 - 0
tables/fields/budget.py

@@ -0,0 +1,53 @@
+"""
+    中标金额字段检查
+"""
+
+
+class BudgetChecker(object):
+    """
+        中标字段检查
+    """
+
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "互相校验(预算和中标金额的比例)",
+                "parent_name": "金额错误",
+                "parent_code": "01",
+                "checkFn": self.check0101
+            },
+            "0102": {
+                "name": "过大过小[100,10亿]",
+                "parent_name": "金额错误",
+                "parent_code": "01",
+                "checkFn": self.check0102
+            }
+        }
+
+    @staticmethod
+    def check0101(budget: float, bidamount: float) -> bool:
+        """
+        预算和中标金额的比例
+        :param budget:
+        :param amount:
+        :return:返回true 代表异常
+        """
+        if budget and bidamount:
+            if 0.7 < budget / bidamount < 1.3:
+                return False
+            else:
+                return True
+        else:
+            # 两者中有一方为空不判断
+            return False
+
+    @staticmethod
+    def check0102(budget: float) -> bool:
+        """
+        中标金额过大过小[100,10亿]
+        :param price:
+        :return: 返回true 代表异常
+        """
+        if 100 < budget < 1000000000:
+            return False
+        return True

+ 312 - 0
tables/fields/buyer.py

@@ -0,0 +1,312 @@
+# coding:utf-8
+from tables.ai import org_ner
+from tables import clear_spacing
+from html_table_extractor.extractor import Extractor
+from tables import CatchContentObject, fsc
+from util.sensitive_word import AcAutomation
+from tables import match_company_index, key_value_header
+from tables import tfc_object
+from docs.config import ai2config
+from docs.config import DEBUG
+from util.get_region import get_city_info
+import csv
+import re
+from docs.config import abnormal_config
+
+pattern = r',|。|\?|!|;'
+
+
+class BuyerChecker(object):
+    """
+        中标字段检查
+    """
+
+    def __init__(self):
+        """
+        采购单位0101判断不准确,备用
+        """
+        self.errors_tables = {
+            "0101": {
+                "name": "实体识别",
+                "parent_name": "名称错误",
+                "parent_code": "01",
+                "checkFn": self.check0101
+            },
+            "0201": {
+                "name": "看数据的标签是不是采购单位",
+                "parent_name": "数据标签错误",
+                "parent_code": "02",
+                "checkFn": self.check0201
+            },
+            "0103": {
+                "name": "包含叠词,异常词汇,特殊词汇",
+                "parent_name": "名称错误",
+                "parent_code": "01",
+                "checkFn": self.check0103
+            },
+            "0104": {
+                "name": "名称不完整",
+                "parent_name": "名称错误",
+                "parent_code": "01",
+                "checkFn": self.check0104
+            }
+
+        }
+        #
+        self.buyer_ac = AcAutomation()
+        with open(ai2config["table_field_config"]["corpus_path"], "r") as f:
+            reads = csv.reader(f)
+            [self.buyer_ac.add_word(d[0].strip()) for d in reads if "采购单位" in d[1] and d[0].strip()]
+
+    def intention_check(self, header):
+        """
+        意图结果检测
+        :param header:
+        :return:
+        """
+        if header in self.buyer_ac.catch:
+            if DEBUG:
+                print(f"采购单位意图:::>>   **{header}**==>    [采购单位]")
+            return True
+        tags = tfc_object.predict([header])
+        if tags:
+            if "采购单位" in tags[0]:
+                if DEBUG:
+                    print(f"采购单位意图:::>>   **{header}**==>    {tags}")
+                return True
+
+    def buyer_intention_table(self, tables: list, companies):
+        """
+        表格意图检测
+        :param tables:
+        :param companies:
+        :return:
+        """
+
+        for row_ind, row in enumerate(tables):
+            for col_ind, column in enumerate(row):
+                extract_companies = re.findall("|".join(companies), column)
+                if extract_companies:
+                    if col_ind > 0:
+                        status = self.intention_check(row[col_ind - 1])
+                        if status:
+                            for company in companies:
+                                companies.remove(company)
+                            if not companies:
+                                return False
+                    if row_ind > 0 and len(tables[row_ind - 1]) > col_ind:
+                        status = self.intention_check(tables[row_ind - 1][col_ind])
+                        if status:
+                            for company in companies:
+                                companies.remove(company)
+                            if not companies:
+                                return False
+                    if self.buyer_ac.search(column):
+                        companies = self.buyer_intention_content(companies, column)
+                    if not companies:
+                        return False
+        return companies
+
+    def buyer_intention_content(self, companies, column):
+        """
+        文本意图检测
+        :param companies:
+        :param column:
+        :return:
+        """
+        # 公司名称的下标
+        indexes = match_company_index(companies, column)
+        if not indexes:
+            return companies
+
+        # 实体提取的head字段
+        start_ind = 0
+        for r in indexes:
+            start, end, company_name = r
+            if company_name not in companies:
+                start_ind = end
+                continue
+            start_ind = start_ind if start_ind > start - 10 else start - 10
+            text_ = column[start_ind:end + 10]
+            start_ind = end
+            head = key_value_header(text_)
+            for val, ind in head:
+                if self.intention_check(val):
+                    if company_name in companies:
+                        companies.pop(company_name)
+                if not companies:
+                    return False
+        return companies
+
+    @staticmethod
+    def check_company_name(contents: list, companies: list):
+        """
+        公司名称检测
+        :param contents:正文段落分割后
+        :param companies: 公司list
+        :return:返回False结束流程,list继续流程
+        """
+        new_content_list = []
+        # 合并文本
+        for ind, con in enumerate(contents):
+            if "<table" in con:
+                table = Extractor(con).parse()
+                _tables = table.return_list()
+                _tables = clear_spacing(_tables)
+                for text in _tables:
+                    new_content_list.extend(text)
+            else:
+                # 一段文本
+                new_content_list.append(con.replace(" ", ""))
+
+        # 开始判断公司名称
+        for text in new_content_list:
+            p = r"|".join(companies)
+            repatten = p.replace(")", "\)").replace("(", "\(").replace(".", "\.")
+            s = re.split(pattern, text)
+            for t in s:
+                if re.search(repatten, t):
+                    al_result = org_ner(t)
+                    for company in al_result:
+                        if company in companies:
+                            if DEBUG:
+                                print(f"采购单位实体识别:::>>    **{text}**==>    {company}")
+                            companies.remove(company)
+                if not companies:
+                    return False
+        return companies
+
+    def check_intention(self, contents: list, companies: list):
+        """
+        意图检测
+        :param contents:正文段落分割后
+        :param companies: 公司list
+        :return:返回False结束流程,list继续流程
+        """
+        for ind, content in enumerate(contents):
+            if "<table" in content:
+                # 表格处理
+                table = Extractor(content).parse()
+                _tables = table.return_list()
+                _tables = clear_spacing(_tables)
+                _table_str = str(_tables)
+                if re.search("|".join(companies), _table_str):
+                    companies = self.buyer_intention_table(_tables, companies)
+                if not companies:
+                    return False
+                continue
+            # 非表格处理
+            companies = self.buyer_intention_content(companies, content)
+            if not companies:
+                return False
+        return companies
+
+    def check0101(self, buyer: str, detail: str, attach_text: dict, catch_content: CatchContentObject) -> bool:
+        """
+        公司名称检测
+        :param buyer:采购单位
+        :param detail: 公告
+        :param attach_text: 附件解析结果
+        :param catch_content: 单挑数据缓存
+        :return:返回true 代表异常
+        """
+        try:
+            companies = [buyer]
+            contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告")
+            companies = self.check_company_name(contents, companies)
+            if not companies:
+                return False
+            for attach_index, attach_content in attach_text.items():
+                if attach_content:
+                    for topic_index, topic_detail in attach_content.items():
+                        # oss地址
+                        attach_url = topic_detail.get("attach_url", "")
+                        if attach_url:
+                            # 获取附件内容
+                            st, content = fsc.download_text_content(attach_url)
+
+                            # 下载成功
+                            # 超长文本不处理,暂定30万字
+                            if st and content.strip():
+                                if len(content) > 300000:
+                                    continue
+                            # 开始检测
+                            contents = catch_content.public_attachment_catch(content, platform="attach",
+                                                                             document_id=attach_url)
+                            companies = self.check_company_name(contents, companies)
+                            if not companies:
+                                return False
+        except Exception as e:
+            print(e)
+        return True
+
+    def check0201(self, buyer: str, detail: str, attach_text: dict, catch_content: CatchContentObject) -> bool:
+        """
+        公司名称检测
+        :param buyer:采购单位
+        :param detail: 公告
+        :param attach_text: 附件解析结果
+        :param catch_content: 单挑数据缓存
+        :return:返回true 代表异常
+        """
+        companies = [buyer]  # 多中标人
+
+        # 公告意图检测
+        contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告")
+        companies = self.check_intention(contents, companies)
+        if not companies:
+            return False
+
+        # 附件意图检测
+        for attach_index, attach_content in attach_text.items():
+            if attach_content:
+                for topic_index, topic_detail in attach_content.items():
+                    # oss地址
+                    attach_url = topic_detail.get("attach_url", "")
+                    if attach_url:
+                        # 获取附件内容
+                        st, content = fsc.download_text_content(attach_url)
+
+                        # 下载成功
+                        # 超长文本不处理,暂定30万字
+                        if st and content.strip():
+                            if len(content) > 300000:
+                                continue
+                        # 开始检测
+                        contents = catch_content.public_attachment_catch(content, platform="attach",
+                                                                         document_id=attach_url)
+                        companies = self.check_intention(contents, companies)
+                        if not companies:
+                            return False
+        return True
+
+    def check0103(self, buyer: str):
+
+        with open(abnormal_config["table_field_config"]["path1"], "r") as f:
+            reads = csv.reader(f)
+            for n in reads:
+                p1 = re.compile("^" + n[0])
+                if p1.match(buyer):
+                    return True
+
+        # 包含词 使用敏感词检验方法
+        self.check_abnormal_ac = AcAutomation()
+        with open(abnormal_config["table_field_config"]["path2"], "r") as f:
+            reads = csv.reader(f)
+            [self.check_abnormal_ac.add_word(w[0]) for w in reads]
+        if self.check_abnormal_ac.search(buyer):
+            return True
+
+        with open(abnormal_config["table_field_config"]["path3"], "r") as f:
+            reads = csv.reader(f)
+            for m in reads:
+                p2 = re.compile(".*$" + m[0])
+                if p2.match(buyer):
+                    return True
+        return False
+
+    def check0104(self, buyer: str, buyerclass: str):
+        if buyerclass in ("学校", "教育", "卫健委", "医疗", "政府办", "政务中心"):
+            if get_city_info(buyer) == [None, None, None]:
+                return True
+        return False

+ 43 - 0
tables/fields/content.py

@@ -0,0 +1,43 @@
+"""
+正文字段检查
+"""
+
+
+class ContentChecker(object):
+    """
+    正文检查
+    """
+    errors_tables = {
+        "01": {"name": "正文长度异常",
+               "code": "01",
+               "rules": {
+                   "01": {
+                       "name": "低于200字",
+                       "code": "01",
+                       "checkFn": "lt200",
+                   },
+               },
+               },
+        "02": {"name": "中文占比异常",
+               "code": "02",
+               "rules": {
+                   "01": {
+                       "name": "中文字符占比低于30%",
+                       "code": "01",
+                       "checkFn": "chineseCharLt30",
+                   },
+               },
+               },
+    }
+
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def lt200(content: str) -> bool:
+        return len(content) < 200
+
+    @staticmethod
+    def chineseCharLt30(content: str) -> bool:
+        chinese_char_count = sum(list(map(lambda x: 1 if '\u4e00' <= x <= '\u9fef' else 0, content)))
+        return float(chinese_char_count) / float(len(content)) < 0.3

+ 106 - 0
tables/fields/fieldtype.py

@@ -0,0 +1,106 @@
+# coding:utf-8
+
+class FieldTypeChecker(object):
+    """
+        有值,类型判断
+    """
+    def __init__(self):
+        self.errors_tables = {
+            "title": self.check_title_type,
+            "projectname": self.check_projectname_type,
+            "buyer":self.check_buyer_type,
+            "winner": self.check_winner_type,
+            "budget": self.check_budget_type,
+            "bidamount": self.check_bidamount_type,
+            "area":self.check_region_type,
+            "projectcode": self.check_projectcode_type,
+            "multipackage":self.check_multipackage_type,
+            "purchasinglist":self.check_purchasinglist_type,
+        }
+
+    def check_bidamount_type(self,value) -> bool:
+        """
+        中标金额类型检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        if isinstance(value,(int,float)):
+            return False
+        return True
+
+    def check_budget_type(self,value) -> bool:
+        """
+        预算类型检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        if isinstance(value,(int,float)):
+            return False
+        return True
+
+    def check_winner_type(self,value):
+        """
+        中标单位类型检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        if isinstance(value, str):
+            value=value.replace("(","(").replace(")",")")
+            return value
+        return True
+
+    def check_buyer_type(self,value):
+        """
+        采购单位类型检测
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        if isinstance(value, str):
+            value=value.replace("(","(").replace(")",")")
+            return value
+        return True
+
+    def check_region_type(self,value):
+        if isinstance(value, str):
+            value=value.replace("(","(").replace(")",")")
+            return value
+        return True
+
+    def check_title_type(self,value):
+        """
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        if isinstance(value, str):
+            value=value.replace("(","(").replace(")",")")
+            return value
+        return True
+
+    def check_projectname_type(self,value):
+        """
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        if isinstance(value, str):
+            value=value.replace("(","(").replace(")",")")
+            return value
+        return True
+
+    def check_projectcode_type(self,value):
+        """
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        if isinstance(value, str):
+            value=value.replace("(","(").replace(")",")")
+            return value
+        return True
+    def check_multipackage_type(self,value) -> bool:
+        """
+        :param obj:代表一个item
+        :return:返回true 代表异常
+        """
+        pass
+
+    def check_purchasinglist_type(self,value):
+        pass

+ 132 - 0
tables/fields/projectcode.py

@@ -0,0 +1,132 @@
+import re
+
+from docs.config import general_config
+from util.sensitive_word import AcAutomation
+import csv
+from docs.config import abnormal_config
+from tables import CatchContentObject, fsc
+
+class ProjectcodeChecker(object):
+    """
+        项目编号字段检查
+    """
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "项目编号字段无值但是正文疑似有值",
+                "parent_name": "数值检测",
+                "parent_code": "01",
+                "checkFn": self.check0101
+            },
+            "0102": {
+                "name": "长度大于2小于等于4",
+                "parent_name": "长度类型",
+                "parent_code": "02",
+                "checkFn": self.check0102
+            },
+            "0103": {
+                "name": "长度大于50",
+                "parent_name": "长度类型",
+                "parent_code": "03",
+                "checkFn": self.check0103
+            },
+            "0201": {
+                "name": "检查日期格式",
+                "parent_name": "日期格式",
+                "parent_code": "01",
+                "checkFn": self.check0201
+            },
+            "0202": {
+                "name": "包含异常关键字",
+                "parent_name": "异常关键字",
+                "parent_code": "02",
+                "checkFn": self.check0202
+            },
+            "0203": {
+                "name": "不包含数字字母",
+                "parent_name": "不包含数字字母",
+                "parent_code": "03",
+                "checkFn": self.check0203
+            },
+            "0301":{
+                "name": "汉字占比>60%且不包含中国电信",
+                "parent_name": "汉字占比",
+                "parent_code": "01",
+                "checkFn": self.check0301
+            },
+
+            "0302": {
+                "name": "连续汉字超过9个",
+                "parent_name": "汉字占比",
+                "parent_code": "03",
+                "checkFn": self.check0302
+            }
+        }
+
+    def check0101(self,projectcode,detail,catch_content,attach_text) -> bool:
+        '''
+        :return:返回true 代表异常
+        '''
+
+        self.check_projectcode_ac = AcAutomation()
+        with open(abnormal_config["table_field_config"]["path4"], "r") as f:
+            reads = csv.reader(f)
+            [self.check_projectcode_ac.add_word(w[0]) for w in reads]
+
+        if projectcode == "":
+            contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告") #返回值是字典
+            content = "\n".join(contents) #字典处理成字符串
+            if self.check_projectcode_ac.search(content):
+                return True
+
+            for attach_index, attach_content in attach_text.items():
+                if attach_content:
+                    for topic_index, topic_detail in attach_content.items():
+                        # oss地址
+                        attach_url = topic_detail.get("attach_url", "")
+                        if attach_url:
+                            # 获取附件内容
+                            st, content = fsc.download_text_content(attach_url)
+
+                            # 下载成功
+                            # 超长文本不处理,暂定30万字
+                            if st and content.strip():
+                                if len(content) > 300000:
+                                    continue
+                            # 开始检测
+                            contents = catch_content.public_attachment_catch(content, platform="attach",document_id=attach_url)
+                            content = "\n".join(contents)
+                            if self.check_projectcode_ac.search(content):
+                                    return True
+            return False
+
+    # 检查projectcode长度小于等于4大于2
+    def check0102(self,projectcode: str) -> bool:
+        return 2 < len(projectcode) <= 4
+
+    @staticmethod
+    # 检查projectcode长度大于50
+    def check0103( projectcode: str) -> bool:
+        return len(projectcode) > 50
+
+    def check0201(self, projectcode: str) -> bool:
+        def is_valid_date_format(s):
+            date_format_regex = r'^\d{4}/\d{2}/\d{2}$'
+            return re.match(date_format_regex, s) is not None
+
+        return is_valid_date_format(projectcode)
+
+    def check0202(self, projectcode: str) -> bool:
+        codeUnConReg = re.compile(r"(null|勘察|测试|设计|监理|范围|分包|日)")
+        return bool(codeUnConReg.search(projectcode))
+
+    def check0203(self, projectcode: str) -> bool:
+        return not any(char.isalnum() for char in projectcode)
+
+    def check0301(self, projectcode: str) -> bool:
+        chinese_chars = [char for char in projectcode if '\u4e00' <= char <= '\u9fff']
+        chinese_chars_ratio = len(chinese_chars) / len(projectcode)
+        return chinese_chars_ratio > 0.6 and "中国电信" not in projectcode
+
+    def check0302(self, projectcode: str) -> bool:
+        return len(re.findall(r'[\u4e00-\u9fa5]{9,}', projectcode)) > 0

+ 90 - 0
tables/fields/projectname.py

@@ -0,0 +1,90 @@
+"""
+    项目名称字段检查
+"""
+import re
+from docs.config import general_config
+from util.sensitive_word import AcAutomation
+import csv
+class ProjectnameChecker(object):
+    """
+        项目名称字段检查
+    """
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "项目名称长度小于等于5",
+                "parent_name": "长度类型",
+                "parent_code": "01",
+                "checkFn": self.lt5
+            },
+            "0102": {
+                "name": "长度大于等于100",
+                "parent_name": "长度类型",
+                "parent_code": "01",
+                "checkFn": self.gt100
+            },
+            "0201":{
+                "name": "非汉字占比>55%",
+                "parent_name": "汉字占比",
+                "parent_code": "02",
+                "checkFn": self.check0201
+            },
+            "0302": {
+                "name": "不包含通用词汇(中标公告)",
+                "parent_name": "语义表述不完整",
+                "parent_code": "03",
+                "checkFn": self.check0302
+            }
+        }
+
+    @staticmethod
+    def gt100(projectname: str) -> bool:
+        """
+        标题长度大于80
+        :param title:
+        :return:返回true 代表异常
+        """
+        return len(projectname) >= 100
+
+    @staticmethod
+    def lt5(projectname: str) -> bool:
+        """
+        标题长度小于5
+        :param title:
+        :return:返回true 代表异常
+        """
+        return len(projectname) <= 5
+
+    def check0201(self,projectname: str) -> bool:
+        """
+        标题非汉字占比 >55%
+        :param title:
+        :return:返回true 代表异常
+        """
+        # chinese_chars = [char for char in title if '\u4e00' <= char <= '\u9fff']  # 匹配汉字
+        non_chinese_chars = [char for char in projectname if not ('\u4e00' <= char <= '\u9fff')]  # 匹配非汉字和非字母数字字符
+        non_chinese_chars_radio = len(non_chinese_chars) / len(projectname)
+        if non_chinese_chars_radio > 0.5:
+            return True
+        return False
+    def check0302(self,projectname: str) -> bool:
+        """
+        没有通用后缀
+        :param title:
+        :return:返回true 代表异常
+        """
+        self.check_general_ac = AcAutomation()
+        with open(general_config["table_field_config"]["path"], "r") as f:
+            reads = csv.reader(f)
+            [self.check_general_ac.add_word(w[0]) for w in reads]
+        p1 = re.compile(r"^[3|6|7|8|0|\.]")
+        p2 = re.compile(".*--")
+        if p1.match(projectname):
+            # print(11111)
+            return True
+        if p2.match(projectname):
+            # print(2222)
+            return True
+        if self.check_general_ac.search(projectname):
+            return False
+        return True

+ 369 - 0
tables/fields/purchasing.py

@@ -0,0 +1,369 @@
+# coding:utf-8
+from sklearn.preprocessing import Normalizer
+from tables.ai import product_detail_server
+import numpy as np
+import json
+
+Scaler = Normalizer()
+
+
+def softmax(x):
+    # 对输入向量进行指数运算
+    exp_values = np.exp(x)
+
+    # 计算指数值的和
+    sum_exp_values = np.sum(exp_values)
+
+    # 计算每个元素的softmax概率值
+    softmax_values = exp_values / sum_exp_values
+
+    return softmax_values
+
+
+def calculate_score(score_list):
+    '''
+    最终得分计算
+    :param score_list:
+    :return:
+    '''
+    if not score_list:
+        return 0
+    global Scaler
+    # 适应并转换数据
+    score_np = np.array(score_list)
+    scaled_data = Scaler.fit_transform([score_list])
+    soft_ret = softmax(scaled_data[0])
+    return sum(score_np * soft_ret)
+
+
+class SourceEvaluate(object):
+    def __init__(self):
+        """
+        初始化
+        """
+        self.step = {}
+        self.direction_step = {"h": 1, "v": 0.75, "h/v": 0.5, "无": 0.25}
+        self.table_type_step = {"识别": 1, "推断": 0.8, "字段": 0.6, "标题": 0.4, "物品": 0.2}
+        self.verify_step = {"确定": 1, "不确定": 0.7}
+        self.file_name_step = {"公告": 1, "标题": 0.4}
+
+    def calculate_score(self, file_name, table):
+        """
+        计算得分
+        :return:
+        """
+        verify = table.get("verify", "")
+        direction = table.get("direction", "")
+        table_type = table.get("type", "")
+        direction_score = self.direction_step.get(direction, 0)
+        table_type_score = self.table_type_step.get(table_type, 0)
+        verify_step_score = self.verify_step.get(verify, 0)
+        file_name_step_score = self.file_name_step.get(file_name, 0.8)
+        return (direction_score + table_type_score + verify_step_score + file_name_step_score) / 4
+
+
+class ItemNameClassify(object):
+    def __init__(self):
+        self.step = []
+
+    @staticmethod
+    def calculate_score(name_score):
+        """
+        计算得分
+        :return:
+        """
+        if name_score > 0.98:
+            return 0.99
+        elif name_score > 0.86:
+            return 0.94
+        else:
+            return 0.68
+
+
+def item_name_evaluate(item_score, header):
+    '''
+    名称
+    :param item_score:
+    :param header:
+    :return:
+    '''
+    item_name_field = header.get("itemname", "")
+    if not item_name_field:
+        return 0.3
+    if [w for w in ["产品", "设备", "货物", "商品", "标的", "物资", "材料", "服务", "物料", "印刷品", "医疗设备"] if
+        w in item_name_field] and "名称" in item_name_field:
+        return item_score
+    else:
+        return item_score * 0.9
+
+
+def number_price_verify(target):
+    """
+    数量价格验证
+    :param target:
+    :return:
+    """
+    number = target.get("number", 0)
+    unit_price = target.get("unitprice", 0)
+    total_price = target.get("totalprice", 0)
+    if number and unit_price and total_price:
+        if number * unit_price == total_price:
+            return 1, 1, 1
+        else:
+            return 0, 0, 0
+    return 1, 1, 1
+
+
+def number_unit_evaluate(header, target):
+    '''
+    数量单位
+    :param header:
+    :param target:
+    :return:
+    '''
+    number_header = header.get("number", "")
+    number = target.get("number", "")
+    unit_header = header.get("unitname", "")
+    unitname = target.get("unitname", "")
+    number_score, unit_score = 0, 0
+    if number:
+        number_score = 1 if "数量" in number_header or "数量" in unit_header else 0.5
+    if unitname:
+        unit_score = 1 if "单位" in number_header or "单位" in unit_header else 0.8
+    return number_score, unit_score
+
+
+def total_unit_price_evaluate(header, target):
+    '''
+    单价、总价
+    :param header:
+    :param target:
+    :return:
+    '''
+    total_price_header = header.get("totalprice", "")
+    unit_price_header = header.get("unitprice", "")
+    unit_price = target.get("unitprice", "")
+    total_price = target.get("totalprice", "")
+    unit_price_score, total_price_score = 0, 0
+    if total_price:
+        if not total_price_header:
+            total_price_score = 0.5
+        else:
+            total_price_score = 1 if "总价" in total_price_header else 0.8
+    if unit_price:
+        if not unit_price_header:
+            unit_price_score = 0.5
+        else:
+            unit_price_score = 1 if "单价" in unit_price_header else 0.8
+    return unit_price_score, total_price_score
+
+
+def entity_model_server(text, prefix=""):
+    """
+    品牌、规格、型号的实体识别模型
+    :param text:
+    :param prefix:
+    :return:
+    """
+    brands = []  # 品牌
+    models = []  # 型号
+    specs = []  # 规格
+    product = []  # 产品
+    if text:
+        text = prefix + text
+        model_dict = product_detail_server(text)
+        output = model_dict.get('output', [])
+        for row in output:
+            _type = row.get("type", "")
+            span = row.get("span", "")
+            if _type == "品牌":
+                brands.append(span)
+            elif _type == "型号":
+                models.append(span)
+            elif _type == "规格":
+                specs.append(span)
+            elif "产品" in _type:
+                product.append(span)
+        return {"brands": brands, "models": models, "specs": specs, "product": product}
+    else:
+        return {"brands": [], "models": [], "specs": [], "product": []}
+
+
+def get_brand_model(target, title_result):
+    """
+    获取品牌和规格
+    :param target:
+    :return:
+    """
+    # 关注的字段
+    brand = target.get("brandname", "")
+    model = target.get("model", "")
+
+    # 实体识别
+    brand_result = entity_model_server(brand, "品牌:")
+    model_result = entity_model_server(model, "型号:")
+    # 品牌
+    if brand_result.get("brands", []):
+        brands = [brand_result.get("brands", []), "brandname", 1]
+    elif model_result.get("brands", []):
+        brands = [model_result.get("brands", []), "model", 0.8]
+    elif title_result.get("brands", []):
+        brands = [title_result.get("brands", []), "itemname", 0.5]
+    else:
+        brands = [[], "", 0]
+
+    # 型号
+    if model_result.get("models", []):
+        models = [model_result.get("models", []), "model", 1]
+    elif brand_result.get("models", []):
+        models = [brand_result.get("models", []), "brandname", 0.8]
+    else:
+        if model_result.get("specs", []):
+            models = [model_result.get("specs", []), "model", 1]
+        elif brand_result.get("specs", []):
+            models = [brand_result.get("specs", []), "brandname", 0.8]
+        elif title_result.get("models", []) or title_result.get("specs", []):
+            models = [title_result.get("models", []), "itemname", 0.5]
+        else:
+            models = [[], "", 0]
+
+    # 规格
+    # if model_result.get("specs", []):
+    #     specs = [model_result.get("specs", []), "model", 1]
+    # elif brand_result.get("brands", []):
+    #     specs = [brand_result.get("specs", []), "brand", 0.8]
+    # else:
+    #     specs = [title_result.get("specs", []), "itemname", 0.5]
+
+    return brands, models
+
+
+def brand_model_evaluate(header, target, title_ner):
+    '''
+    品牌规格型号
+    :param target:
+    :return:
+    '''
+    model_score, brand_score, model, brand = 0, 0, "", ""
+    brands, models = get_brand_model(target, title_ner)
+    if brands:
+        brand_score = brands[-1]
+        brand = ";".join(brands[0])
+    if models:
+        model_score = models[-1]
+        model = ";".join(models[0])
+    model_header = header.get("model", "")
+    brand_header = header.get("brandname", "")
+    if target.get("brandname") and "品牌" in brand_header:
+        brand_score = brand_score if brand_score * 1.1 > 1 else brand_score * 1.1
+    if target.get("model") and "型号" in model_header or "规格" in model_header:
+        model_score = model_score if model_score * 1.1 > 1 else model_score * 1.1
+    print(brand)
+    return brand_score, model_score, brand, model
+
+
+source = SourceEvaluate()
+
+
+# ['名称': 'itemname','品牌': 'brandname','型号': 'model','数量': 'number','计量单位': 'unitname','单价': 'unitprice','总价': 'totalprice']
+def evaluate(target, table):
+    '''
+    标的物评估
+    :param target:
+    :return:
+    '''
+    file_name = target.get("file_name", "")
+    header = table.get("header", {})
+    item_name_score = target.get("score", 0)
+    source_score = source.calculate_score(file_name, table)
+    if not header:
+        return [source_score, 0, 0, 0, 0, 0, 0, 0], {"table_score": round(source_score, 2)}
+
+    # 名称
+    itemname = target.get("itemname", "")
+    item_name_score = item_name_evaluate(item_name_score, header)
+    title_ner = entity_model_server(itemname, "")
+
+    # 品牌型号
+    brand_score, model_score, brand, model = brand_model_evaluate(header, target, title_ner)
+
+    # 数量单位
+    number_score, unit_score = number_unit_evaluate(header, target)
+
+    # 单价、总价
+    unit_price_score, total_price_score = total_unit_price_evaluate(header, target)
+
+    # 校验
+    number_price_weight = number_price_verify(target)
+
+    # 生成最终的成绩
+    if number_price_weight[0] == 0:
+        number_score, unit_price_score, total_price_score = 0, 0, 0
+
+    score_list = [source_score, item_name_score, brand_score, model_score, number_score, unit_score, unit_price_score,
+                  total_price_score]
+    # result_score = calculate_score(score_list)
+    score_dict = {
+        "table_score": round(source_score, 2),
+        "itemname_score": round(item_name_score, 2),
+        "brand_score": round(brand_score, 2),
+        "model_score": round(model_score, 2),
+        "number_score": round(number_score, 2),
+        "unit_score": round(unit_score, 2),
+        "unitprice_score": round(unit_price_score, 2),
+        "totalpricescore": round(total_price_score, 2)
+    }
+    return score_list, score_dict
+
+
+def purchasing_evaluate_start(targets, tables):
+    '''
+    标的物评估函数
+    :param targets:
+    :return:
+    '''
+    purchasing_score_list = []
+    purchasing_evaluate_list = []
+    tables = json.loads(tables) if tables else []
+    for target in targets:
+        table_ind = target.get("table", -1)
+        table_ind = int(table_ind)
+        table = tables[table_ind] if table_ind > -1 else {}
+        score, score_dict = evaluate(target, table)
+        purchasing_score_list.append(score)
+        purchasing_evaluate_list.append(score_dict)
+    score_list = []
+    for score in purchasing_score_list:
+        result_score = calculate_score(score)
+        score_list.append(result_score)
+    merge_score = calculate_score(score_list)
+    return purchasing_evaluate_list, round(merge_score, 2)
+
+
+class PurchasingChecker(object):
+    """
+        中标字段检查
+    """
+
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "标的物评估",
+                "parent_name": "标的物",
+                "parent_code": "01",
+                "checkFn": self.check0101
+            }
+        }
+
+    def check0101(self, purchasinglist, purchasingsource):
+        """
+        意图结果检测
+        :param header:
+        :return:
+        """
+        purchasing_evaluate_list, score = purchasing_evaluate_start(purchasinglist, purchasingsource)
+        print(score)
+        if score < 0.85:
+            return True
+        else:
+            return False

+ 24 - 0
tables/fields/subpackage.py

@@ -0,0 +1,24 @@
+'''
+分包,分标段类型的数据,直接打标签1000
+'''
+class SubpackageChecker(object):
+    """
+        分包字段检查
+    """
+    def __init__(self):
+        self.errors_tables = {
+            "1000": {
+                "name": "分包类数据",
+                "parent_name": "分包类型",
+                "parent_code": "01",
+                "checkFn": self.check1000
+            }
+        }
+
+    def check1000(self,multipackage: str) -> bool:
+        """
+        全国类数据
+        :param title:
+        :return:返回true 代表异常
+        """
+        return multipackage == 1

+ 92 - 0
tables/fields/title.py

@@ -0,0 +1,92 @@
+"""
+    标题字段检查
+"""
+import re
+
+from docs.config import general_config
+from util.sensitive_word import AcAutomation
+import csv
+class TitleChecker(object):
+    """
+        标题字段检查
+    """
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "标题长度小于等于5",
+                "parent_name": "长度类型",
+                "parent_code": "01",
+                "checkFn": self.lt5
+            },
+            "0102": {
+                "name": "长度大于等于100",
+                "parent_name": "长度类型",
+                "parent_code": "01",
+                "checkFn": self.gt100
+            },
+            "0201":{
+                "name": "非汉字占比>55%",
+                "parent_name": "汉字占比",
+                "parent_code": "02",
+                "checkFn": self.check0201
+            },
+            "0302": {
+                "name": "不包含通用词汇(中标公告)",
+                "parent_name": "语义表述不完整",
+                "parent_code": "03",
+                "checkFn": self.check0302
+            }
+        }
+
+    @staticmethod
+    def gt100(title: str) -> bool:
+        """
+        标题长度大于80
+        :param title:
+        :return:返回true 代表异常
+        """
+        return len(title) >= 100
+
+    @staticmethod
+    def lt5(title: str) -> bool:
+        """
+        标题长度小于5
+        :param title:
+        :return:返回true 代表异常
+        """
+        return len(title) <= 5
+
+    def check0201(self,title: str) -> bool:
+        """
+        self参数实例方法要写,静态类方法不用写
+        标题非汉字占比 >55%
+        :param title:
+        :return:返回true 代表异常
+        """
+        # chinese_chars = [char for char in title if '\u4e00' <= char <= '\u9fff']  # 匹配汉字
+        non_chinese_chars = [char for char in title if not ('\u4e00' <= char <= '\u9fff')]  # 匹配非汉字和非字母数字字符
+        non_chinese_chars_radio = len(non_chinese_chars) / len(title)
+        if non_chinese_chars_radio > 0.5:
+            return True
+        return False
+    def check0302(self,title: str) -> bool:
+        """
+        没有通用后缀
+        :param title:
+        :return:返回true 代表异常
+        """
+        self.check_general_ac = AcAutomation()
+        with open(general_config["table_field_config"]["path"], "r") as f:
+            reads = csv.reader(f)
+            [self.check_general_ac.add_word(w[0]) for w in reads]
+        p1 = re.compile(r"^[3|6|7|8|0|\.]")
+        p2 = re.compile(".*--")
+        if p1.match(title):
+            print(11111)
+            return True
+        if p2.match(title):
+            print(2222)
+            return True
+        if self.check_general_ac.search(title):
+            return False
+        return True

+ 290 - 0
tables/fields/winner.py

@@ -0,0 +1,290 @@
+# coding:utf-8
+from tables.ai import org_ner
+from tables import clear_spacing
+from html_table_extractor.extractor import Extractor
+from tables import CatchContentObject, fsc
+from util.sensitive_word import AcAutomation
+from tables import match_company_index, key_value_header
+from tables import tfc_object
+from docs.config import ai2config, abnormal_config
+from docs.config import DEBUG
+import csv
+import re
+
+pattern = r',|。|\?|!|;'
+
+
+class WinnerChecker(object):
+    """
+        中标字段检查
+    """
+
+    def __init__(self):
+        self.errors_tables = {
+            "0101": {
+                "name": "实体识别",
+                "parent_name": "名称错误",
+                "parent_code": "01",
+                "checkFn": self.check0101
+            },
+            "0201": {
+                "name": "看数据的标签是不是之中标单位",
+                "parent_name": "数据标签错误",
+                "parent_code": "02",
+                "checkFn": self.check0201
+            },
+            "0103": {
+                "name": "包含叠词,异常词汇,特殊词汇",
+                "parent_name": "名称错误",
+                "parent_code": "01",
+                "checkFn": self.check0103
+            }
+        }
+        #
+        self.winner_ac = AcAutomation()
+        with open(ai2config["table_field_config"]["corpus_path"], "r") as f:
+            reads = csv.reader(f)
+            [self.winner_ac.add_word(d[0].strip()) for d in reads if "中标单位" in d[1] and d[0].strip()]
+
+    def intention_check(self, header):
+        """
+        意图结果检测
+        :param header:
+        :return:
+        """
+        if header in self.winner_ac.catch:
+            if DEBUG:
+                print(f"中标单位意图:::>>   **{header}**==>    [中标单位]")
+            return True
+        tags = tfc_object.predict([header])
+        if tags:
+            if "中标单位" in tags[0]:
+                if DEBUG:
+                    print(f"中标单位意图:::>>   **{header}**==>    {tags}")
+                return True
+
+    def winner_intention_table(self, tables: list, companies):
+        """
+        表格意图检测
+        :param tables:
+        :param companies:
+        :return:
+        """
+
+        for row_ind, row in enumerate(tables):
+            for col_ind, column in enumerate(row):
+                extract_companies = re.findall("|".join(companies), column)
+                if extract_companies:
+                    if col_ind > 0:
+                        status = self.intention_check(row[col_ind - 1])
+                        if status:
+                            for company in companies:
+                                companies.remove(company)
+                            if not companies:
+                                return False
+                    if row_ind > 0 and len(tables[row_ind - 1]) > col_ind:
+                        status = self.intention_check(tables[row_ind - 1][col_ind])
+                        if status:
+                            for company in companies:
+                                companies.remove(company)
+                            if not companies:
+                                return False
+                    if self.winner_ac.search(column):
+                        companies = self.winner_intention_content(companies, column)
+                    if not companies:
+                        return False
+        return companies
+
+    def winner_intention_content(self, companies, column):
+        """
+        文本意图检测
+        :param companies:
+        :param column:
+        :return:
+        """
+        # 公司名称的下标
+        indexes = match_company_index(companies, column)
+        if not indexes:
+            return companies
+
+            # 实体提取的head字段
+        start_ind = 0
+        for r in indexes:
+            start, end, company_name = r
+            if company_name not in companies:
+                start_ind = end
+                continue
+            start_ind = start_ind if start_ind > start - 10 else start - 10
+            text_ = column[start_ind:end + 10]
+            start_ind = end
+            head = key_value_header(text_)
+            for val, ind in head:
+                if self.intention_check(val):
+                    if company_name in companies:
+                        companies.pop(company_name)
+                if not companies:
+                    return False
+        return companies
+
+    @staticmethod
+    def check_company_name(contents: list, companies: list):
+        """
+        公司名称检测
+        :param contents:正文段落分割后
+        :param companies: 公司list
+        :return:返回False结束流程,list继续流程
+        """
+        new_content_list = []
+        # 合并文本
+        for ind, con in enumerate(contents):
+            if "<table" in con:
+                table = Extractor(con).parse()
+                _tables = table.return_list()
+                _tables = clear_spacing(_tables)
+                for text in _tables:
+                    new_content_list.extend(text)
+            else:
+                # 一段文本
+                new_content_list.append(con.replace(" ", ""))
+
+        # 开始判断公司名称
+        for text in new_content_list:
+            p = r"|".join(companies)
+            repatten = p.replace(")", "\)").replace("(", "\(").replace(".", "\.")
+            s = re.split(pattern, text)
+            for t in s:
+                if re.search(repatten, t):
+                    al_result = org_ner(t)
+                    for company in al_result:
+                        if company in companies:
+                            if DEBUG:
+                                print(f"中标单位实体识别:::>>    **{text}**==>    {company}")
+                            companies.remove(company)
+                if not companies:
+                    return False
+        return companies
+
+    def check_intention(self, contents: list, companies: list):
+        """
+        意图检测
+        :param contents:正文段落分割后
+        :param companies: 公司list
+        :return:返回False结束流程,list继续流程
+        """
+        for ind, content in enumerate(contents):
+            if "<table" in content:
+                # 表格处理
+                table = Extractor(content).parse()
+                _tables = table.return_list()
+                _tables = clear_spacing(_tables)
+                _table_str = str(_tables)
+                if re.search("|".join(companies), _table_str):
+                    companies = self.winner_intention_table(_tables, companies)
+                if not companies:
+                    return False
+                continue
+            # 非表格处理
+            companies = self.winner_intention_content(companies, content)
+            if not companies:
+                return False
+        return companies
+
+    def check0101(self, winner: str, detail: str, attach_text: dict, catch_content: CatchContentObject) -> bool:
+        """
+        公司名称检测
+        :param winner:中标单位,多个逗号分割
+        :param detail: 公告
+        :param attach_text: 附件解析结果
+        :param catch_content: 单挑数据缓存
+        :return:返回true 代表异常
+        """
+        companies = [company for company in winner.split(",") if company]
+        contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告")
+        companies = self.check_company_name(contents, companies)
+        if not companies:
+            return False
+        for attach_index, attach_content in attach_text.items():
+            if attach_content:
+                for topic_index, topic_detail in attach_content.items():
+                    # oss地址
+                    attach_url = topic_detail.get("attach_url", "")
+                    if attach_url:
+                        # 获取附件内容
+                        st, content = fsc.download_text_content(attach_url)
+
+                        # 下载成功
+                        # 超长文本不处理,暂定30万字
+                        if st and content.strip():
+                            if len(content) > 300000:
+                                continue
+                        # 开始检测
+                        contents = catch_content.public_attachment_catch(content, platform="attach",
+                                                                         document_id=attach_url)
+                        companies = self.check_company_name(contents, companies)
+                        if not companies:
+                            return False
+        return True
+
+    def check0201(self, winner: str, detail: str, attach_text: dict, catch_content: CatchContentObject) -> bool:
+        """
+        公司名称检测
+        :param winner:中标单位,多个逗号分割
+        :param detail: 公告
+        :param attach_text: 附件解析结果
+        :param catch_content: 单挑数据缓存
+        :return:返回true 代表异常
+        """
+        companies = [company for company in winner.split(",") if company]  # 多中标人
+
+        # 公告意图检测
+        contents = catch_content.public_attachment_catch(detail, platform="html", document_id="公告")
+        companies = self.check_intention(contents, companies)
+        if not companies:
+            return False
+
+        # 附件意图检测
+        for attach_index, attach_content in attach_text.items():
+            if attach_content:
+                for topic_index, topic_detail in attach_content.items():
+                    # oss地址
+                    attach_url = topic_detail.get("attach_url", "")
+                    if attach_url:
+                        # 获取附件内容
+                        st, content = fsc.download_text_content(attach_url)
+
+                        # 下载成功
+                        # 超长文本不处理,暂定30万字
+                        if st and content.strip():
+                            if len(content) > 300000:
+                                continue
+                        # 开始检测
+                        contents = catch_content.public_attachment_catch(content, platform="attach",
+                                                                         document_id=attach_url)
+                        companies = self.check_intention(contents, companies)
+                        if not companies:
+                            return False
+        return True
+
+    def check0103(self, winner: str):
+        with open(abnormal_config["table_field_config"]["path1"], "r") as f:
+            reads = csv.reader(f)
+            for n in reads:
+                p1 = re.compile("^" + n[0])
+                if p1.match(winner):
+                    return True
+
+        # 包含词 使用敏感词检验方法
+        self.check_abnormal_ac = AcAutomation()
+        with open(abnormal_config["table_field_config"]["path2"], "r") as f:
+            reads = csv.reader(f)
+            [self.check_abnormal_ac.add_word(w[0]) for w in reads]
+        if self.check_abnormal_ac.search(winner):
+            return True
+
+        with open(abnormal_config["table_field_config"]["path3"], "r") as f:
+            reads = csv.reader(f)
+            for m in reads:
+                p2 = re.compile(".*$" + m[0])
+                if p2.match(winner):
+                    return True
+        return False

+ 31 - 0
test.py

@@ -0,0 +1,31 @@
+from docs.config import ReluMongodb
+from util.mogodb_helper import MongoDBInterface
+
+ReluClient = MongoDBInterface(ReluMongodb)
+
+data = {
+    "rules_id": 1,
+    "company_name":"拓普",
+    "version":"v1.0",
+    "rules": {
+        "budget": {"0101": {
+                "name": "互相校验(预算和中标金额的比例)",
+                "parent_name": "金额错误",
+                "parent_code": "01",
+            }, "0102":{
+                "name": "过大过小[100,10亿]",
+                "parent_name": "金额错误",
+                "parent_code": "01",
+            }},
+        "area": {"0101": {
+            "name": "全国类数据",
+            "parent_name": "全国类型",
+            "parent_code": "01",
+        }, },
+        "multipackage": {"1000": "haha",
+                         "0203": "yaya"},
+    }
+}
+
+ReluClient.db[ReluMongodb["col"]].insert_one(data)
+print()

+ 0 - 0
test.txt


+ 1 - 0
util/README.md

@@ -0,0 +1 @@
+工具包

二进制
util/__pycache__/dictionary.cpython-37.pyc


二进制
util/__pycache__/fs_client.cpython-37.pyc


二进制
util/__pycache__/get_region.cpython-37.pyc


二进制
util/__pycache__/htmltag.cpython-37.pyc


二进制
util/__pycache__/mogodb_helper.cpython-37.pyc


二进制
util/__pycache__/sensitive_word.cpython-37.pyc


+ 146 - 0
util/dictionary.py

@@ -0,0 +1,146 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+语料辅助工具词典、向量化辅助
+'''
+
+from typing import List
+from collections import defaultdict
+import jieba.posseg as psg
+class Dictionary():
+
+    def __init__(self,stopwords:List[str]):
+        self.word_ids = defaultdict(lambda :0)
+        self.word_docs = defaultdict(lambda :0)
+        self.corpus_size = 0
+        self.stopwords = dict(zip(stopwords,[0]*len(stopwords)))
+        self.dictionary=None
+        self.dictionary_words=None
+
+    # 切词
+    def cut(self, text):
+        return [w for w,x in psg.cut(text) if w not in self.stopwords and x not in ["m","x"]]
+
+
+    #往词典添加语料,支持更新添加
+    def append_vocab(self,text:List[str],need_cut=True):
+        for c in text:
+            cut_text = self.cut(c) if need_cut else text.split(' ')
+            for w in cut_text:
+                if not w in self.word_ids:
+                    self.word_ids[w] += 1
+
+            for w in  list(set(cut_text)):
+                self.word_docs[w]+=1
+            self.corpus_size+=1
+
+    #构建词典
+    def build_dictionary(self,tfidf_limit=1e-4,vocab_file='./data/vocab'):
+        import math,joblib
+        word_size = len(self.word_ids)
+        word_tf = dict([(w, c / word_size) for w, c in self.word_ids.items()])
+        word_idf = dict([(w, math.log(self.corpus_size / (c + 1))) for w, c in self.word_docs.items()])
+        word_tfidf = [(w, (pos+1,c * word_idf[w])) for pos,(w, c) in enumerate(word_tf.items())]
+        word_tfidf = sorted(word_tfidf, key=lambda x: x[1][1], reverse=True)
+        b_size = len(word_tfidf)
+        # 过滤小于1e-4的数据
+        print('舍弃词汇',list(filter(lambda x:x[1][1]<=tfidf_limit,word_tfidf)))
+        word_tfidf =list(filter(lambda x:x[1][1]>tfidf_limit,word_tfidf))
+        a_size = len(word_tfidf)
+        print('舍弃词汇量:',b_size-a_size)
+        self.dictionary = dict(word_tfidf)
+        self.dictionary['']=(0,0)
+        self.dictionary_words = list(self.dictionary.keys())
+        joblib.dump(self.dictionary,vocab_file)
+
+    #快速构建
+    def quick_build_by_mongo(self,host:str,port:int,db:str,col:str,fields:List[str],need_cut=False,maxsize=1000,tfidf_limit=1e-3,vocab_file=''):
+        import sys
+        mi = MyIterator(host=host,port=port,db=db,col=col,fields=fields,maxsize=maxsize)
+        for text in mi:
+            self.append_vocab(text,need_cut=need_cut)
+            print('>',end='')
+            sys.stdout.flush()
+
+        self.build_dictionary(tfidf_limit=tfidf_limit,vocab_file=vocab_file)
+
+    #
+    def load_dictionary(self,vocab_file='./data/vocab'):
+        import joblib
+        self.dictionary = joblib.load(vocab_file)
+        self.dictionary_words = list(self.dictionary.keys())
+
+    #语料向量化
+    def vector_corpus(self,corpus:List[str],dim=100,need_cut=True,return_type='one_hot',use_tfidf=False):
+        import numpy as np
+        ret = np.zeros((len(corpus),dim,2),dtype=np.float) if use_tfidf else np.zeros((len(corpus),dim),dtype=np.long)
+        for i,c in enumerate(corpus):
+            try:
+                text_cut = self.cut(c) if need_cut else c.split(' ')
+                text_cut_dict = dict(zip(text_cut, [0] * len(text_cut)))
+                if return_type == 'one_hot':
+                    vect = [self.dictionary[w][0] if w in text_cut_dict else 0 for w in self.dictionary_words[:dim]]
+                    ret[i,:len(vect)]=vect
+                else:#bow
+                    if use_tfidf:
+                        vect = [self.dictionary[w] if w in self.dictionary else (0,0) for w in text_cut ]
+                    else:
+                        vect = [self.dictionary[w][0] if w in self.dictionary else 0 for w in text_cut]
+                    #超出部分自动截断
+                    seg_len = len(vect) if len(vect)<dim else dim
+                    ret[i,:seg_len]=vect[:seg_len]
+            except Exception as e:
+                print('第%d条数据向量化出错:%s'%(i,e))
+        return ret
+
+'''
+使用mongo数据库快速构建词典
+'''
+from pymongo import MongoClient,ASCENDING
+from bson import ObjectId
+class MyIterator(object):
+    def __init__(self, host:str,port:int,db:str,col:str,fields:List[str],maxsize=1000):
+        self.col = MongoClient(host=host, port=port)[db][col]
+        self.fields = fields
+        self.fields_filter = dict(zip(self.fields,[1]*len(self.fields)))
+        self.maxid=ObjectId('0'*24)
+        self.size=0
+        self.maxsize=maxsize
+
+
+    # 取得迭代器
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        hasdata=False
+        ret = []
+        for row in self.col.find({'_id': {'$gt': self.maxid}}, \
+                                 self.fields_filter) \
+                .sort('_id', ASCENDING). \
+                limit(100):
+            self.size+=1
+            if self.size>=self.maxsize:
+                break
+
+            hasdata = True
+            self.maxid = row['_id']
+            ret.append(' '.join([row[f] for f in self.fields]))
+        if hasdata:
+            return ret
+        else:
+            raise StopIteration
+
+
+if __name__ == '__main__':
+    dic = Dictionary(stopwords=[])
+    dic.quick_build_by_mongo(host='192.168.3.207', port=27092, \
+                             db='re4art', col='bidding_china_4_9', \
+                             fields=['title','detail'], need_cut=True, \
+                             maxsize=50000, \
+                             tfidf_limit=1e-5, \
+                             vocab_file='vocab')
+    dic.load_dictionary(vocab_file='vocab')
+    print(dic.vector_corpus(corpus=['大连市竞争性谈判以下展示了使用 filter 函数的实例:'],use_tfidf=True,return_type='bow',dim=20))
+    # print(dic.vector_corpus(corpus=['大连市竞争性谈判以下展示了使用 filter 函数的实例:'],use_tfidf=False,return_type='bow',dim=20))
+    # print(dic.vector_corpus(corpus=['大连市竞争性谈判以下展示了使用 filter 函数的实例:'],return_type='one_hot',dim=20))

+ 87 - 0
util/fs_client.py

@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+'''
+文件存储服务客户端
+author:honbbo
+date:2020-2-29
+'''
+from itertools import islice
+import oss2
+
+class FileServeClient(object):
+    def __init__(self):
+        '''
+        抽象出来的文件存储客户端
+        目前使用阿里云OSS对象存储服务
+        如果更换SeaWeedFs,需要重写此文件
+        注意:文件读写,都是以object-name为索引,请保存object-name
+        '''
+        self.auth = None
+        self.bucket = None
+        self.do_auth()
+
+    def do_auth(self):
+        '''
+        身份验证,
+        注意:如果auth有时间限制,请在每一批次调用do_auth方法。
+        为了提高效率,不必要再每次读写文件时调用。
+        '''
+        auth = oss2.Auth('LTAI4G5x9aoZx8dDamQ7vfZi', 'Bk98FsbPYXcJe72n1bG3Ssf73acuNh')
+        bucket = oss2.Bucket(auth, 'http://oss-cn-beijing.aliyuncs.com', 'topjy')
+        self.auth = auth
+        self.bucket = bucket
+
+    def list(self):
+        '''
+        列举文件,仅测试用
+        '''
+        for b in islice(oss2.ObjectIterator(self.bucket), 10):
+            print(b.key)
+
+    def upload_text_file(self, object_name: str, file_content: str) -> (any, any):
+        '''
+        文件上传
+        '''
+        result = self.bucket.put_object(object_name, bytes(file_content, encoding='utf-8'))
+        status, request_id = result.status, result.request_id
+        return status, request_id
+
+    def download_text_content(self, object_name) -> (bool, str):
+        '''
+        下载文本内容
+        '''
+        object_stream = self.bucket.get_object(object_name)
+        content = object_stream.read()
+        if object_stream.client_crc == object_stream.server_crc:
+            return True, str(content, encoding='utf-8')
+        else:
+            return False, ''
+
+    def delete_object(self, object_name: str) -> (any, any):
+        '''
+        删除内容
+        '''
+        result = self.bucket.delete_object(object_name)
+        status, request_id = result.status, result.request_id
+        return status, request_id
+
+    def upload_bytes_file(self, object_name: str, file_content: bytes):
+        result = self.bucket.put_object(object_name, file_content)
+        status, request_id = result.status, result.request_id
+        return status, request_id
+
+    def download_file(self, object_name, save_path):
+        object_stream = self.bucket.get_object_to_file(object_name, save_path)
+        if object_stream.status == 200:
+            return True, save_path
+
+if __name__ == '__main__':
+    fsc = FileServeClient()
+    #fsc.list()
+    #st, id = fsc.upload_text_file('my-object-2', '这是测试的文件内容')
+    #print(st, id)
+    st, content = fsc.download_text_content('af4477ae-705e-11ed-9389-0242ac120002')
+    print(content)
+    # with open("text01.txt","w") as f:
+    #     f.write(content)
+    #st, id = fsc.delete_object('my-object-2')
+    #print(st, id)

+ 81 - 0
util/get_region.py

@@ -0,0 +1,81 @@
+import cpca
+import re
+import pandas as pd
+
+def get_city_info(text):
+    # 读取区县数据
+    df_county = pd.read_excel("//Users//miaobao//Documents//work//PycharmProjects//data_quality//docs//区县.xlsx")
+
+    # 读取乡镇数据
+    df_town = pd.read_excel("//Users//miaobao//Documents//work//PycharmProjects//data_quality//docs//乡镇.xlsx")
+
+    # 读取市级数据
+    df_city = pd.read_excel("//Users//miaobao//Documents//work//PycharmProjects//data_quality//docs//市.xlsx")
+
+    # 使用cpca库提取地名
+    df = cpca.transform([text])
+
+    province = None
+    city = None
+    district = None
+
+    if not df.empty:
+        province = df.iloc[0]['省']
+        city = df.iloc[0]['市']
+        district = df.iloc[0]['区']
+
+    if province is None and city is None and district is None:
+        # 使用正则表达式提取乡镇信息
+        towns = re.findall(r'[\u4e00-\u9fa5]+镇|[\u4e00-\u9fa5]+乡', text)
+        if towns:
+            for town in towns:
+                town_name = None
+                if town in df_town['乡镇名称'].values or town in df_town['乡镇简称'].values:
+                    town_name = town
+
+                    # 根据乡镇名查找对应的区县代码
+                    town_info = df_town[df_town['乡镇名称'] == town_name].iloc[0]
+                    county_code = town_info['区县代码']
+
+                    # 根据区县代码查找对应的区县名称
+                    county_info = df_county[df_county['区县代码'] == county_code].iloc[0]
+                    county_name = county_info['区县名称']
+
+                    # 将区县名称转换成对应的省份名称
+                    province = county_name
+
+                    # 尝试在市级数据中查找对应的市信息
+                    city_code = county_info['城市代码']
+                    city_info = df_city[df_city['城市代码'] == city_code]
+                    if not city_info.empty:
+                        city = city_info.iloc[0]['城市名称']
+
+                        # 将城市名称转换成对应的省份名称
+                        df_city_result = cpca.transform([city])
+                        province = df_city_result.iloc[0]['省']
+
+                    break# 找到乡镇信息后跳出循环
+
+            if not province and not city and not district and '区县代码' in df_county.columns:
+                county_code = df.iloc[0]['区县代码']
+                city_info = df_city[df_city['城市代码'] == county_code]
+                if not city_info.empty:
+                    city = city_info.iloc[0]['城市名称']
+
+                    # 将城市名称转换成对应的省份名称
+                    df_city_result = cpca.transform([city])
+                    province = df_city_result.iloc[0]['省']
+
+                county_info = df_county[df_county['区县代码'] == county_code].iloc[0]
+                district = county_info['区县名称']
+
+    return province, city, district
+
+if __name__ == '__main__':
+
+    # 使用方法示例
+    province, city, district = get_city_info("河南省开发的")
+    if get_city_info("电动蝶阀待开发的")==[None,None,None]:
+        print("44444")
+    print(province, city, district)
+

+ 78 - 0
util/htmltag.py

@@ -0,0 +1,78 @@
+# coding:utf-8
+import re
+
+br_reg = re.compile('<br[/]*>', re.I)
+table_reg = re.compile('<([/]*table[^>]*)>', re.I)
+tablebody_reg = re.compile('<([/]*tbody[^>]*)>', re.I)
+input_reg = re.compile(r'<[/]*input[^>].*?value="(.*?)"[/]>', re.I)
+tr_reg = re.compile('<([/]*tr[^>]*)>', re.I)
+th_reg = re.compile('<([/]*th[^>]*)>', re.I)
+td_reg = re.compile('<([/]*td[^>]*)>', re.I)
+p_reg = re.compile('<[/]?p>', re.I)
+othertag_reg = re.compile('<[^>]+>', re.I | re.M)
+other_symbol_reg = re.compile('[\t| ]*')
+seg_first_space_reg = re.compile('\n+\\s*', re.M)
+mul_crcf_reg = re.compile('\n+', re.M)
+brackets_reg = re.compile('\\s+')
+table_fk_reg = re.compile('(\\[table[^\\]]*\\])(.*?)(\\[/table\\])', re.M | re.S | re.I)
+zhushi_reg = re.compile('<!--.*?-->', re.I)
+
+##html标签清理
+def Clean(html: str):
+    html = br_reg.sub('\n', html)
+    html = table_reg.sub('', html)
+    html = tablebody_reg.sub('', html)
+    html = tr_reg.sub('\n', html)
+    html = td_reg.sub(' ', html)
+    html = p_reg.sub('\n', html)
+    html = othertag_reg.sub('', html)
+    html = other_symbol_reg.sub('', html)
+    html = seg_first_space_reg.sub('\n', html)
+    html = mul_crcf_reg.sub('\n', html)
+    return html
+
+
+def ClearSpace(txt: str):
+    return brackets_reg.sub('', txt)
+
+
+##html标签清理,但保留table表格
+def CleanKeepTable(html: str):
+    html = zhushi_reg.sub('', html)
+    html = br_reg.sub('\n', html)
+    html = table_reg.sub(subFunc4Match, html)
+    html = tablebody_reg.sub(subFunc4Match, html)
+    html = tr_reg.sub(subFunc4Match, html)
+    html = td_reg.sub(subFunc4Match, html)
+    html = th_reg.sub(subFunc4Match, html)
+    html = p_reg.sub('\n', html)
+    html = othertag_reg.sub('', html)
+    html = seg_first_space_reg.sub('\n', html)
+    # print("-->", html)
+    html = table_fk_reg.sub(lambda x: x.group(1) + mul_crcf_reg.sub(' ', x.group(2)) + x.group(3), html)
+    html = mul_crcf_reg.sub('\n', html)
+    # 清理table标签中的空格
+    html = html.replace('[', '<').replace(']', '>')
+    html = html.replace('<table', '\n<table').replace('</table>', '</table>\n')
+    return html
+
+
+def subFunc4Match(strmatch):
+    try:
+        if strmatch:
+            return '[%s]' % (strmatch.group(1))
+        else:
+            return ""
+    except Exception as e:
+        print(e)
+
+
+def extract_input_value(html):
+    input_reg = re.compile(r'<[/]*input[^>].*?value="(.*?)"[/]>', re.I)
+    input_r = re.compile(r'<[/]*input[^>].*?[/]>', re.I)
+    result = input_r.findall(html)
+    for input_detail in result:
+        ret = input_reg.findall(input_detail)
+        if ret:
+            html = html.replace(input_detail, f"</td><td>{ret[0]}")
+    return html

+ 26 - 0
util/info_preprocess/__init__.py

@@ -0,0 +1,26 @@
+# coding:utf-8
+from .html_preprocess import HtmlHelper
+from typing import AnyStr
+from .attach_preprocess import AttachHelper
+
+class Preprocess(object):
+    """
+    预处理接口
+    """
+
+    def __init__(self):
+        self.__pool = dict(html=HtmlHelper, attach=AttachHelper)
+
+    def get_preprocess(self, category_name: AnyStr):
+        """
+        获取处理接口
+        :param category_name: 处理接口名称
+        :return: 处理接口对象
+        """
+        if category_name in self.__pool:
+            return self.__pool[category_name]()
+        else:
+            raise ValueError(f"Preprocess doesn't have {category_name}")
+
+
+__all__ = [Preprocess]

二进制
util/info_preprocess/__pycache__/__init__.cpython-37.pyc


二进制
util/info_preprocess/__pycache__/attach_preprocess.cpython-37.pyc


二进制
util/info_preprocess/__pycache__/html_preprocess.cpython-37.pyc


+ 53 - 0
util/info_preprocess/attach_preprocess.py

@@ -0,0 +1,53 @@
+# coding:utf-8
+from util.htmltag import CleanKeepTable
+from typing import AnyStr
+from loguru import logger
+
+
+class AttachHelper(object):
+
+    @staticmethod
+    def __clear_tag(content: AnyStr) -> AnyStr:
+        """
+        清理标签
+        :param content:
+        :return:
+        """
+        try:
+            tag_html = CleanKeepTable(content)  # 保留 table标签
+        except Exception as e:
+            logger.warning(e)
+            return content
+        return tag_html
+
+    @staticmethod
+    def __add_space(content_html):
+        """
+        为表格添加空格
+        :param content_html:
+        :return:
+        """
+        if "<table" not in content_html:
+            return content_html
+        if "<thead>" in content_html:
+            content_html = content_html.replace('<thead>', '')
+        if "<br/" in content_html:
+            content_html = content_html.replace(r'<br/', '')
+        if "<table " in content_html and "<td " in content_html and "<tr " in content_html:
+            return content_html
+        content_html = content_html.replace('<tbody', '<tbody ')
+        content_html = content_html.replace('<table', '<table ')
+        content_html = content_html.replace('<th', '<th ')
+        content_html = content_html.replace('<tr', '<tr ')
+        content_html = content_html.replace('<td', '<td ')
+        return content_html
+
+    def preprocess(self, content: AnyStr) -> AnyStr:
+        """
+        处理开始
+        :param content:
+        :return:
+        """
+        content = self.__add_space(content)
+        content = self.__clear_tag(content)
+        return content

+ 91 - 0
util/info_preprocess/html_preprocess.py

@@ -0,0 +1,91 @@
+# coding:utf-8
+from bs4 import BeautifulSoup
+from util.htmltag import CleanKeepTable
+from typing import AnyStr
+from loguru import logger
+from util.htmltag import extract_input_value
+from lxml import etree
+
+
+class HtmlHelper(object):
+    @staticmethod
+    def __repair_label(content_html: AnyStr) -> AnyStr:
+        """
+        html标签修复
+        :param content_html: html内容
+        :return:
+        """
+        soup = BeautifulSoup(content_html, 'html5lib')
+        try:
+            fixed_html = soup.prettify()
+        except ValueError as e:
+            logger.warning(e)
+            fixed_html = content_html
+        return fixed_html
+
+    def __clean_script(self, Html):
+        '''
+        clear js/style
+        :param Html:
+        :return:
+        '''
+        html = etree.HTML(Html)
+        ele = html.xpath('//script | //noscript | //style')
+        for e in ele:
+            e.getparent().remove(e)
+        html_str = etree.tostring(html, encoding="utf-8").decode("utf-8")
+        return html_str
+
+    @staticmethod
+    def __clear_tag(content_html: AnyStr) -> AnyStr:
+        """
+        清理标签
+        :param content_html:
+        :return:
+        """
+        try:
+            content_html = content_html.replace("\n", " ").replace("\t", "").replace("\xa0", "")
+            tag_html = content_html.replace("&gt;", "")
+            tag_html = extract_input_value(tag_html)
+            tag_html = CleanKeepTable(tag_html)  # 保留 table标签
+            tag_html = tag_html.strip().replace(":", ":").replace("  ", " ")
+            tag_html = tag_html.replace("  ", " ").replace("▲", "")
+        except Exception as e:
+            logger.warning(e)
+            return content_html
+        return tag_html
+
+    @staticmethod
+    def __add_space(content_html):
+        """
+        为表格添加空格
+        :param content_html:
+        :return:
+        """
+        if "<table" not in content_html:
+            return content_html
+        if "<thead>" in content_html:
+            content_html = content_html.replace('<thead>', '')
+        # if "<br/" in content_html:
+            # content_html = content_html.replace(r'<br/', '')
+        if "<table " in content_html and "<td " in content_html and "<tr " in content_html:
+            return content_html
+        content_html = content_html.replace('<tbody', '<tbody ')
+        content_html = content_html.replace('<table', '<table ')
+        content_html = content_html.replace('<th', '<th ')
+        content_html = content_html.replace('<tr', '<tr ')
+        content_html = content_html.replace('<td', '<td ')
+        return content_html
+
+    def preprocess(self, content: AnyStr) -> AnyStr:
+        """
+        处理开始
+        :param content:
+        :return:
+        """
+        content = self.__add_space(content)
+        content = self.__repair_label(content)
+        if "script" in content:
+            content = self.__clean_script(content)
+        content = self.__clear_tag(content)
+        return content

+ 76 - 0
util/mogodb_helper.py

@@ -0,0 +1,76 @@
+# coding:utf-8
+from pymongo import MongoClient
+from pymongo.errors import AutoReconnect
+from bson import ObjectId
+import time
+import urllib.parse as parse
+
+
+class MongoDBInterface:
+    def __init__(self, config):
+        self.__host = config.get("ip_port", "")
+        self.__user = config.get("user", "")
+        self.__password = config.get("password", "")
+        self.__database = config.get("db", "")
+        self.connect()
+
+    def connect(self):
+        """
+        连接数据库
+        :return:
+        """
+        # 特殊符号转义
+        self.__user = parse.quote_plus(self.__user)
+        self.__password = parse.quote_plus(self.__password)
+
+        # 连接数据库
+        try:
+            if self.__user:
+                self.client = MongoClient(
+                    "mongodb://{}:{}@{}".format(self.__user, self.__password, self.__host),
+                    unicode_decode_error_handler='ignore')
+            else:
+                self.client = MongoClient("mongodb://{}".format(self.__host), unicode_decode_error_handler='ignore')
+            self.db = self.client[self.__database]
+        except AutoReconnect as e:
+            self.connect()
+
+    def disconnect(self):
+        self.client.close()
+
+    def find_by_id(self, collection_name, m_id):
+        try:
+            collection = self.db[collection_name]
+            if isinstance(m_id, str):
+                m_id = ObjectId(m_id)
+            documents = collection.find_one({"_id": m_id})
+            return documents
+        except AutoReconnect:
+            time.sleep(5)
+            print("Connection to MongoDB lost. Reconnecting...")
+            self.connect()  # 自动重连
+            return self.find_by_id(collection_name, m_id)
+
+    def update_by_id(self, collection_name, m_id, fields: dict):
+        try:
+            collection = self.db[collection_name]
+            if isinstance(m_id, str):
+                m_id = ObjectId(m_id)
+            documents = collection.update_one({"_id": m_id}, {"$set": fields})
+            return documents
+        except AutoReconnect:
+            print("Connection to MongoDB lost. Reconnecting...")
+            self.connect()  # 自动重连
+            return self.update_by_id(collection_name, m_id, fields)
+
+    def find_relus(self, collection_name, hash_id):
+        collection = self.db[collection_name]
+        row = collection.find_one({"hash_id": hash_id})
+        return row
+
+    def find_rule_by_company(self, collection_name, company, version):
+        collection = self.db[collection_name]
+        row = collection.find_one({"company_name": company, "version": version})
+        if not row:
+            return None
+        return row.get("rules_id")

+ 120 - 0
util/sensitive_word.py

@@ -0,0 +1,120 @@
+# coding:utf-8
+
+"""
+以AC自动机机制为基础,编写获取关键词程序,优点速度快
+"""
+
+
+class Node(object):
+    def __init__(self):
+        self.next = {}
+        self.fail = None
+        self.isWord = False
+        self.word = ""
+
+
+class AcAutomation(object):
+
+    def __init__(self):
+        self.root = Node()
+        self.catch=set()
+
+    # 添加敏感词函数
+    def add_word(self, word):
+        temp_root = self.root
+        self.catch.add(word)
+        for char in word:
+            if char not in temp_root.next:
+                temp_root.next[char] = Node()
+            temp_root = temp_root.next[char]
+        temp_root.isWord = True
+        temp_root.word = word
+
+    @staticmethod
+    def __check_word(cache_result: list, char: str):
+        """
+        获取keywords
+        :param cache_result:
+        :param char:
+        :return:
+        """
+        update_catch = []  # 更新之后的指针列表
+        words = []  # 获取关键词列表
+        for cache in cache_result:
+            if char in cache.next:
+                next_p = cache.next[char]
+                if next_p.isWord:
+                    words.append(next_p.word)
+                update_catch.append(next_p)
+        return update_catch, words
+
+    @staticmethod
+    def __check_word_position(cache_result: dict, char: str, position: int):
+        """
+        获取keywords包含位置信心
+        :param cache_result:
+        :param char:字符
+        :param position:位置
+        :return:
+        """
+        update_catch = {}  # 更新之后的指针列表
+        words = []  # 获取关键词列表
+        for d_key, (start, cache) in cache_result.items():
+            if char in cache.next:
+                next_p = cache.next[char]
+                if next_p.isWord:
+                    words.append((next_p.word, start, position))
+                update_catch[len(update_catch)] = (start, next_p)
+        return update_catch, words
+
+    # 查找关键词函数
+    def search(self, content):
+        """
+        关键词查找
+        :param content:
+        :return:
+        """
+        cache_result = []  # 缓存节点
+        words_result = []  # 关键词列表
+        position = 0  # 当前位置
+        while position < len(content):
+            p = self.root
+            char = content[position]
+            cache_result, words = self.__check_word(cache_result, char)
+            words_result.extend(words)
+            if char in p.next:
+                if p.next[char].isWord:
+                    words_result.append(p.next[char].word)
+                cache_result.append(p.next[char])
+            position += 1
+        return words_result
+
+    # 查找关键词函数并记录位置
+    def search_and_position(self, content):
+        """
+        关键词查找包含位置
+        :param content:
+        :return:
+        """
+        cache_result = {}  # 缓存节点
+        words_result = []  # 关键词列表
+        position = 0  # 当前位置
+        while position < len(content):
+            p = self.root
+            char = content[position]
+            cache_result, words = self.__check_word_position(cache_result, char, position)
+            words_result.extend(words)
+            if char in p.next:
+                if p.next[char].isWord:
+                    words_result.append((position, p.next[char].word))
+                cache_result[len(cache_result)] = (position, p.next[char])
+            position += 1
+        return words_result
+
+
+if __name__ == '__main__':
+    ah = AcAutomation()
+    for w in ["国", "国产", "产化", "国产化", "路由器123", "国产化路由器", "国产化+服务器", "国产化+防火墙", "国产化+无线"]:
+        ah.add_word(w)
+    result = ah.search_and_position("国产化路由器123")
+    print(result)

部分文件因为文件数量过多而无法显示