import json import re combined_data = { "基础信息": { "招标人/代理信息": { "招标人": "广水市公安局", "招标人联系方式": { "名称": "广水市公安局", "地址": "广水市应山办事处应十大道 189号", "联系电话": "未知" }, "招标代理机构": "湖北楚振捷工程项目管理有限公司", "招标代理机构联系方式": { "名称": "湖北楚振捷工程项目管理有限公司", "地址": "广水市永阳一路 41号", "联系方式": "0722-6256088" }, "项目联系方式":{ "名称":"张三", "联系电话":"11" } }, "项目信息": { "项目名称": "广水市公安局视频会议高清化改造项目", "项目编号": "HBCZJ-2021-CS12", "项目概况": "广水市公安局视频会议高清化改造项目", "项目基本情况": { "项目编号": "HBCZJ-2021-CS12", "采购计划备案号": "2021-04-000399", "项目名称": "广水市公安局视频会议高清化改造项目", "采购方式": "竞争性磋商", "预算金额": "192万元", "最高限价": "192万元", "采购需求": { "项目概况及内容": "广水市公安局视频会议高清化改造项目。", "招标范围": "广水市公安局视频会议高清化改造项目,具体内容见磋商文件第三章。", "项目地点": "具体以合同约定为准。" }, "合同履行期限": "以合同签订为准。", "本项目(是/否)接受联合体投标": "否", "是否可采购进口产品": "否" }, "招标控制价": "192万元", "投标竞争下浮率": "未知", "是否允许分包": "未知", "是否接受联合体投标": "否" }, "采购要求": { "技术要求": "未提供", "商务要求": "未提供", "服务要求": "未提供", "其他要求": "未提供" }, "关键时间/内容": { "投标文件递交截止日期": "2021年 6月 18日 15点 00分", "开标时间":"111", "开标地点":"哈哈", "澄清招标文件的截止时间": "未知", "投标有效期": "90日历天", "信息公示媒介": "中国湖北政府采购网:http://www.ccgp-hubei.gov.cn, 中国广水网:http://www.zggsw.gov.cn/", "投标文件递交地点": "广水市公共资源交易中心五楼 501号开标室" }, "保证金相关": { "质量保证金": "未知", "履约保证金": "不提交", "退还投标保证金": "/", "投标保证金": { "价格":"100,000,000.00 元" } }, "其他信息": { "是否退还投标文件": "否", "投标费用承担": "供应商应承担所有与准备和参加磋商有关的费用,不论磋商的结果如何,采购人和采购代理机构均无义务和责任承担这些费用。", "招标代理服务费": { "支付人": "成交供应商", "支付标准": "根据国家发展与改革委员会办公厅发改办价格【2003】857 号文的规定,经协商由成交供应商按国家发展和改革委员发改价格【2011】534号文规定货物类取费标准向采购代理机构支付招标代理服务费(包含“招标代理费、评标会务费、评标费”),如本项目各包服务费不足叁仟元则供应商按叁仟元支付服务费。", "支付方式": "成交服务费由成交供应商在领取成交通知书的同时向代理机构支付,可使用现金或电汇办理", "支付时间": "领取成交通知书的同时" }, "偏离": { "偏离项要求": "供应商需在响应文件中提供《采购需求响应、偏离说明表/导读表》,具体格式见第六章响应文件格式中的49页。供应商需对采购需求中的各项技术参数和服务要求进行逐项响应,明确表明无偏离、正偏离或负偏离的情况。对于负偏离项,需详细说明偏离的具体内容及原因。", "偏离项内容": "未知" }, "投标预备会": "不召开", "踏勘现场": "不组织" } }, "资格审查": { }, "商务评分": { }, "技术评分": { }, "zhes":"11111" # 其他键值对 } includes = ["基础信息", "资格审查", "商务评分", "技术评分", "无效标与废标项", "投标文件要求", "开评定标流程"] def post_processing(combined_data, includes): # 初始化结果字典,预设'其他'分类为空字典 processed_data = {"其他": {}} # 初始化提取的信息字典 extracted_info = {} # 定义一个辅助函数用于获取嵌套字典中的值 def get_nested(dic, keys, default=None): for key in keys: if isinstance(dic, dict): dic = dic.get(key, default) else: return default return dic # 定义一个辅助函数用于递归查找包含特定子字符串的键 def find_keys_containing(dic, substring): found_values = [] if isinstance(dic, dict): for key, value in dic.items(): if substring in key: found_values.append(value) if isinstance(value, dict): found_values.extend(find_keys_containing(value, substring)) elif isinstance(value, list): for item in value: if isinstance(item, dict): found_values.extend(find_keys_containing(item, substring)) return found_values # 定义一个辅助函数用于根据候选键列表提取值(部分匹配) def extract_field(contact_info, candidate_keys): for candidate in candidate_keys: for key, value in contact_info.items(): if candidate in key and value not in ["未知", ""]: return value return "" # 定义一个辅助函数用于提取 '投标保证金' def extract_bid_bond(guarantee_info): # 定义投标保证金的候选键 bid_bond_candidates = ["投标保证金", "磋商保证金"] # 第一步:查找包含 "投标保证金" 或 "磋商保证金" 的键 for candidate in bid_bond_candidates: for key, value in guarantee_info.items(): if candidate in key: if isinstance(value, dict): # 在嵌套字典中查找包含 "金额" 的键 for sub_key, sub_value in value.items(): if "金额" in sub_key and sub_value not in ["未知", ""]: return sub_value elif isinstance(value, str): if "金额" in key and value not in ["未知", ""]: return value else: # 如果 value 既不是 dict 也不是 str,忽略 continue # 第二步:如果没有找到包含 "金额" 的键,尝试在所有键值中查找符合模式的值 amount_pattern = re.compile(r'(?:\d{1,3}(?:[,,]\d{3})*(?:\.\d+)?|\d+(?:\.\d+)?|[\u4e00-\u9fff]+(?:\.\d+)?)\s*(?:元|万元)') for key, value in guarantee_info.items(): if isinstance(value, str): match = amount_pattern.search(value) if match: return match.group() elif isinstance(value, dict): # 递归查找嵌套字典中的金额 found_amount = extract_bid_bond(value) if found_amount: return found_amount # 如果都没有找到,则返回空字符串 return "" # 如果 '基础信息' 在 includes 中,则进行字段提取 if "基础信息" in includes: base_info = combined_data.get("基础信息", {}) # 定义所需字段的映射关系,暂时不包含'联系人'和'联系电话'以及'招标项目地点' mapping = { "招标项目名称": [["项目信息", "项目名称"], ["项目信息", "工程名称"]], "招标项目编号": [["项目信息", "项目编号"], ["项目信息", "招标编号"]], "开标时间": [["关键时间/内容", "开标时间"]], "报名截止日期": [["关键时间/内容", "投标文件递交截止日期"]], "招标项目预算": [["项目信息", "招标控制价"]], "招标单位名称": [["招标人/代理信息", "招标人"]], "招标公告地址": [["关键时间/内容", "信息公示媒介"], ["关键时间/内容", "评标结果公示媒介"]] } # 提取并映射字段 for new_key, paths in mapping.items(): value = None for path in paths: value = get_nested(base_info, path) if value: break extracted_info[new_key] = value if value else "" # 特殊处理 '招标项目地点' # 在 '项目信息' 下查找包含 "地点" 的键 project_info = base_info.get("项目信息", {}) location_candidates = find_keys_containing(project_info, "地点") if location_candidates: # 选择第一个找到的地点 extracted_info["招标项目地点"] = location_candidates[0] else: extracted_info["招标项目地点"] = "" # 特殊处理 '联系人' 和 '联系电话' # 提取 '项目联系方式' project_contact = get_nested(base_info, ["招标人/代理信息", "项目联系方式"], {}) # 提取 '招标人联系方式' bidder_contact = get_nested(base_info, ["招标人/代理信息", "招标人联系方式"], {}) # 定义候选键列表,按优先级排序 name_candidates = ["名称", "联系人", "招标"] phone_candidates = ["电话", "手机", "联系方式"] # 提取 '联系人' contact_names = [project_contact, bidder_contact] contact_name = "" for contact in contact_names: extracted_name = extract_field(contact, name_candidates) if extracted_name: contact_name = extracted_name break extracted_info["联系人"] = contact_name # 提取 '联系电话' contact_phones = [project_contact, bidder_contact] contact_phone = "" for contact in contact_phones: extracted_phone = extract_field(contact, phone_candidates) if extracted_phone: contact_phone = extracted_phone break extracted_info["联系电话"] = contact_phone # 特殊处理 '投标保证金' # 提取 '保证金相关' guarantee_info = get_nested(base_info, ["保证金相关"], {}) extracted_info["投标保证金"] = extract_bid_bond(guarantee_info) # 遍历原始字典的每一个键值对 for key, value in combined_data.items(): if key in includes: if key == "基础信息": # 已经处理 '基础信息',保留在处理后的数据中 processed_data[key] = value else: # 直接保留包含在 includes 列表中的键值对 processed_data[key] = value else: # 将不在 includes 列表中的键值对加入到 '其他' 分类中 processed_data["其他"][key] = value # 如果 '其他' 分类没有任何内容,可以选择删除这个键 if not processed_data["其他"]: del processed_data["其他"] return processed_data, extracted_info res1,res2=post_processing(combined_data,includes) print(json.dumps(res2,ensure_ascii=False,indent=4))