#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 构建9种中医体质数据库,并与大医网药膳/中药材/穴位数据建立交叉关联 基于中华中医药学会《中医体质分类与判定》标准 """ import json import os import glob import re from collections import defaultdict # ============================================================ # 第一部分:九种体质详细数据 # ============================================================ constitutions = [ { "名称": "平和质", "英文": "Balanced Constitution", "类型": "平和质", "总体特征": "阴阳气血调和,以体态适中、面色红润、精力充沛为主要特征", "形体特征": "体形匀称健壮", "常见表现": "面色红润,目光有神,精力充沛,睡眠良好,食欲好,二便正常,舌淡红苔薄白,脉和缓有力", "心理特征": "性格随和开朗", "发病倾向": "平素患病较少", "对外界环境适应能力": "对自然环境和社会环境适应能力较强", "调理原则": "维护平衡,预防为主,饮食有节,劳逸适度", "饮食宜": ["五谷杂粮", "蔬菜水果", "鱼肉蛋奶", "豆制品", "坚果", "绿茶"], "饮食忌": ["暴饮暴食", "过度偏食", "过量辛辣", "过量油腻"], "推荐药膳": ["山药红枣粥", "枸杞菊花茶", "银耳莲子羹", "百合绿豆汤", "茯苓糕"], "推荐穴位": ["足三里", "涌泉", "百会", "合谷", "三阴交"], "推荐功法": ["太极拳", "八段锦", "五禽戏", "散步"], "相关疾病": ["较少患病,以养生保健为主"], "关联关键字": ["平和", "平衡", "调和", "保健", "养生", "预防"] }, { "名称": "气虚质", "英文": "Qi Deficiency", "类型": "偏颇质", "总体特征": "元气不足,以疲乏、气短、自汗等气虚表现为主要特征", "形体特征": "肌肉松软不实", "常见表现": "平素语音低弱,气短懒言,容易疲乏,精神不振,易出汗,舌淡红,舌边有齿痕,脉弱", "心理特征": "性格内向,不喜冒险", "发病倾向": "易患感冒、内脏下垂等病;病后康复缓慢", "对外界环境适应能力": "不耐受风、寒、暑、湿邪", "调理原则": "补气益气,培元固本", "饮食宜": ["粳米", "糯米", "小米", "山药", "土豆", "大枣", "香菇", "鸡肉", "牛肉", "鳝鱼", "泥鳅", "蜂蜜", "黄豆", "扁豆", "豇豆", "南瓜", "胡萝卜"], "饮食忌": ["生冷", "油腻", "辛辣", "耗气食物"], "推荐药膳": ["黄芪炖鸡汤", "山药粥", "四君子汤", "参苓粥", "红枣桂圆茶"], "推荐穴位": ["足三里", "气海", "关元", "百会", "脾俞"], "推荐功法": ["八段锦", "五禽戏", "太极拳", "散步"], "相关疾病": ["感冒", "内脏下垂", "慢性疲劳", "自汗"], "关联关键字": ["气虚", "气短", "乏力", "自汗", "懒言", "神疲", "补气", "益气", "培元", "固本"] }, { "名称": "阳虚质", "英文": "Yang Deficiency", "类型": "偏颇质", "总体特征": "阳气不足,以畏寒怕冷、手足不温等虚寒表现为主要特征", "形体特征": "肌肉松软不实", "常见表现": "平素畏冷,手足不温,喜热饮食,精神不振,舌淡胖嫩,脉沉迟", "心理特征": "性格多沉静、内向", "发病倾向": "易患痰饮、肿胀、泄泻等病;感邪易从寒化", "对外界环境适应能力": "耐夏不耐冬;易感风、寒、湿邪", "调理原则": "温阳散寒,补肾壮阳", "饮食宜": ["羊肉", "牛肉", "韭菜", "生姜", "肉桂", "核桃", "栗子", "荔枝", "龙眼", "茴香", "丁香", "花椒", "小茴香"], "饮食忌": ["生冷", "寒凉", "冰冻", "苦寒食物"], "推荐药膳": ["当归生姜羊肉汤", "肉桂炖牛肉", "韭菜炒核桃", "附子炖狗肉", "干姜红糖茶"], "推荐穴位": ["关元", "命门", "肾俞", "神阙", "足三里"], "推荐功法": ["八段锦", "太极拳", "五禽戏", "站桩"], "相关疾病": ["痰饮", "肿胀", "泄泻", "阳痿", "宫寒"], "关联关键字": ["阳虚", "畏寒", "怕冷", "四肢不温", "寒凝", "温阳", "散寒", "壮阳", "肾阳", "脾阳"] }, { "名称": "阴虚质", "英文": "Yin Deficiency", "类型": "偏颇质", "总体特征": "阴液亏少,以口燥咽干、手足心热等虚热表现为主要特征", "形体特征": "体形偏瘦", "常见表现": "手足心热,口燥咽干,鼻微干,喜冷饮,大便干燥,舌红少津,脉细数", "心理特征": "性情急躁,外向好动,活泼", "发病倾向": "易患虚劳、失精、不寐等病;感邪易从热化", "对外界环境适应能力": "耐冬不耐夏;不耐受暑、热、燥邪", "调理原则": "滋阴降火,滋补肝肾", "饮食宜": ["百合", "银耳", "莲子", "枸杞", "黑芝麻", "鸭肉", "甲鱼", "龟肉", "海参", "牡蛎", "蜂蜜", "梨", "甘蔗", "枇杷", "桑葚", "黑木耳"], "饮食忌": ["辛辣", "燥热", "油炸", "烧烤", "羊肉"], "推荐药膳": ["百合银耳羹", "枸杞菊花茶", "冰糖炖雪梨", "沙参玉竹老鸭汤", "生地黄粥"], "推荐穴位": ["太溪", "三阴交", "涌泉", "照海", "肾俞"], "推荐功法": ["太极拳", "八段锦", "瑜伽", "静坐"], "相关疾病": ["虚劳", "不寐", "消渴", "便秘", "盗汗"], "关联关键字": ["阴虚", "口干", "咽干", "手足心热", "潮热", "盗汗", "滋阴", "降火", "生津", "润燥"] }, { "名称": "痰湿质", "英文": "Phlegm-Dampness Constitution", "类型": "偏颇质", "总体特征": "痰湿凝聚,以形体肥胖、腹部肥满、口黏苔腻等痰湿表现为主要特征", "形体特征": "体形肥胖,腹部肥满松软", "常见表现": "面部皮肤油脂较多,多汗且黏,胸闷,痰多,口黏腻或甜,喜食肥甘甜黏,苔腻,脉滑", "心理特征": "性格偏温和、稳重,多善于忍耐", "发病倾向": "易患消渴、中风、胸痹等病", "对外界环境适应能力": "对梅雨季节及湿重环境适应能力差", "调理原则": "健脾祛湿,化痰降浊", "饮食宜": ["薏苡仁", "冬瓜", "白萝卜", "赤小豆", "茯苓", "荷叶", "山楂", "陈皮", "燕麦", "荞麦", "海带", "紫菜", "生姜"], "饮食忌": ["肥甘厚味", "甜腻", "油炸", "生冷", "酒肉"], "推荐药膳": ["薏苡仁冬瓜汤", "茯苓粥", "陈皮茶", "山楂荷叶茶", "赤小豆鲤鱼汤"], "推荐穴位": ["丰隆", "足三里", "阴陵泉", "脾俞", "中脘"], "推荐功法": ["八段锦", "太极拳", "五禽戏", "散步", "快走"], "相关疾病": ["消渴", "中风", "胸痹", "肥胖", "高脂血症"], "关联关键字": ["痰湿", "肥胖", "痰多", "胸闷", "苔腻", "健脾", "祛湿", "化痰", "降浊", "利水"] }, { "名称": "湿热质", "英文": "Damp-Heat Constitution", "类型": "偏颇质", "总体特征": "湿热内蕴,以面垢油光、口苦、苔黄腻等湿热表现为主要特征", "形体特征": "形体中等或偏胖", "常见表现": "面垢油光,易生痤疮,口苦口干,身重困倦,大便黏滞不畅或燥结,小便短黄,男性易阴囊潮湿,女性易带下增多,舌质偏红,苔黄腻,脉滑数", "心理特征": "性格多急躁易怒", "发病倾向": "易患疮疖、黄疸、热淋等病", "对外界环境适应能力": "对夏末秋初湿热气候,湿重或气温偏高环境较难适应", "调理原则": "清热利湿,解毒化浊", "饮食宜": ["绿豆", "赤小豆", "薏苡仁", "冬瓜", "苦瓜", "黄瓜", "芹菜", "蒲公英", "马齿苋", "菊花", "金银花", "莲藕", "茭白"], "饮食忌": ["辛辣", "油腻", "甜腻", "温燥", "热性食物"], "推荐药膳": ["绿豆薏苡仁汤", "冬瓜赤小豆汤", "苦瓜排骨汤", "菊花茶", "金银花茶"], "推荐穴位": ["曲池", "合谷", "阴陵泉", "丰隆", "内庭"], "推荐功法": ["八段锦", "太极拳", "游泳", "慢跑"], "相关疾病": ["痤疮", "湿疹", "黄疸", "热淋", "带下病"], "关联关键字": ["湿热", "口苦", "苔黄腻", "痤疮", "湿疹", "清热", "利湿", "解毒", "化浊", "泻火"] }, { "名称": "血瘀质", "英文": "Blood Stasis Constitution", "类型": "偏颇质", "总体特征": "血行不畅,以肤色晦暗、舌质紫暗等血瘀表现为主要特征", "形体特征": "胖瘦均见", "常见表现": "肤色晦暗,色素沉着,容易出现瘀斑,口唇暗淡,舌暗或有瘀点,舌下络脉紫暗或增粗,脉涩", "心理特征": "易烦,健忘", "发病倾向": "易患癥瘕及痛证、血证等", "对外界环境适应能力": "不耐受寒邪", "调理原则": "活血化瘀,行气通络", "饮食宜": ["山楂", "黑豆", "黑木耳", "醋", "玫瑰花", "红糖", "红酒", "桃仁", "油菜", "茄子", "藕", "香菇", "海带"], "饮食忌": ["寒凉", "冰冻", "收敛", "酸涩食物"], "推荐药膳": ["山楂红糖水", "桃仁粥", "黑木耳红枣汤", "玫瑰花茶", "川芎炖鱼头"], "推荐穴位": ["血海", "合谷", "三阴交", "膈俞", "太冲"], "推荐功法": ["八段锦", "太极拳", "五禽戏", "舞蹈", "快走"], "相关疾病": ["癥瘕", "痛经", "闭经", "胸痹", "中风"], "关联关键字": ["血瘀", "瘀血", "面色晦暗", "瘀斑", "刺痛", "活血", "化瘀", "行气", "通络", "消癥"] }, { "名称": "气郁质", "英文": "Qi Depression Constitution", "类型": "偏颇质", "总体特征": "气机郁滞,以神情抑郁、忧虑脆弱等气郁表现为主要特征", "形体特征": "形体瘦者为多", "常见表现": "神情抑郁,情感脆弱,烦闷不乐,舌淡红,苔薄白,脉弦", "心理特征": "性格内向不稳定、敏感多虑", "发病倾向": "易患脏躁、梅核气、百合病及郁证等", "对外界环境适应能力": "对精神刺激适应能力较差;不适应阴雨天气", "调理原则": "疏肝解郁,理气调中", "饮食宜": ["柑橘", "佛手", "玫瑰花", "小麦", "大麦", "荞麦", "香橼", "橙子", "柚", "洋葱", "大蒜", "萝卜", "茴香"], "饮食忌": ["辛辣", "咖啡", "浓茶", "高糖", "高脂"], "推荐药膳": ["玫瑰花茶", "佛手炖瘦肉", "甘麦大枣汤", "橘皮粥", "陈皮柠檬茶"], "推荐穴位": ["太冲", "肝俞", "期门", "膻中", "内关"], "推荐功法": ["八段锦", "太极拳", "瑜伽", "散步", "舞蹈"], "相关疾病": ["郁证", "脏躁", "梅核气", "失眠", "月经不调"], "关联关键字": ["气郁", "抑郁", "焦虑", "胸闷", "胁痛", "疏肝", "解郁", "理气", "调中", "安神"] }, { "名称": "特禀质", "英文": "Intrinsic Constitution / Allergy Constitution", "类型": "偏颇质", "总体特征": "先天失常,以生理缺陷、过敏反应等为主要特征", "形体特征": "无特殊,或有畸形,或有先天生理缺陷", "常见表现": "过敏体质者常见哮喘、风团、咽痒、鼻塞、喷嚏等;患遗传性疾病者有垂直遗传、先天性、家族性特征", "心理特征": "随禀质不同情况各异", "发病倾向": "过敏体质者易患哮喘、荨麻疹、花粉症及药物过敏等;遗传性疾病如血友病、先天愚型等", "对外界环境适应能力": "适应能力差,如过敏体质者对易致过敏季节适应能力差,易引发宿疾", "调理原则": "益气固表,养血祛风", "饮食宜": ["黄芪", "白术", "防风", "红枣", "蜂蜜", "山药", "人参", "灵芝", "薏苡仁", "莲子", "糯米", "花生"], "饮食忌": ["海鲜", "虾蟹", "牛羊肉", "发物", "辛辣", "生冷", "过敏源食物"], "推荐药膳": ["黄芪防风茶", "灵芝红枣汤", "山药排骨汤", "玉屏风茶", "蜂蜜柠檬水"], "推荐穴位": ["足三里", "肺俞", "肾俞", "气海", "曲池"], "推荐功法": ["八段锦", "太极拳", "散步", "瑜伽"], "相关疾病": ["哮喘", "荨麻疹", "过敏性鼻炎", "花粉症", "湿疹", "食物过敏"], "关联关键字": ["过敏", "哮喘", "荨麻疹", "鼻炎", "风团", "益气", "固表", "祛风", "抗敏", "特禀"] } ] # ============================================================ # 第二部分:创建交叉关联 # ============================================================ BASE_DIR = "/home/songyi/Documents/ai_agent_scraper_study/data/大医网" def load_json_files(directory): """Load all JSON files from a directory.""" data = [] if not os.path.exists(directory): print(f"WARNING: Directory not found: {directory}") return data for fpath in sorted(glob.glob(os.path.join(directory, "*.json"))): try: with open(fpath, "r", encoding="utf-8") as f: d = json.load(f) data.append(d) except Exception as e: print(f"Error loading {fpath}: {e}") return data def match_keywords_in_text(keywords, text): """Count how many keywords appear in the text (case-insensitive).""" if not text: return 0 text_lower = text.lower() count = 0 for kw in keywords: if kw.lower() in text_lower: count += 1 return count def build_diet_association(constitutions_data): """体质↔药膳关联: match 功效 and 简介 fields with constitution keywords.""" diet_dir = os.path.join(BASE_DIR, "01_来源数据", "药膳食疗") diets = load_json_files(diet_dir) print(f"Loaded {len(diets)} diet entries") result = {} for const in constitutions_data: name = const["名称"] keywords = const["关联关键字"] matched = [] for d in diets: # Combine 功效 and 简介 fields for matching text = "" for field in ["功效", "简介", "名称"]: if field in d and d[field]: text += d[field] + " " score = match_keywords_in_text(keywords, text) if score > 0: matched.append({ "名称": d.get("名称", ""), "来源": d.get("来源", d.get("url", "")), "功效": d.get("功效", d.get("简介", "")), "得分": score }) # Sort by score descending matched.sort(key=lambda x: x["得分"], reverse=True) result[name] = matched print(f" {name}: matched {len(matched)} diet entries") return result def build_herb_association(constitutions_data): """体质↔药材关联: match 功效作用 field with constitution keywords. 药材名匹配使用最长前缀匹配. """ herb_dir = os.path.join(BASE_DIR, "01_来源数据", "中药材") herbs = load_json_files(herb_dir) print(f"Loaded {len(herbs)} herb entries") # Build a set of all herb names for longest-prefix matching all_herb_names = sorted([h.get("名称", "").strip() for h in herbs if h.get("名称")], key=len, reverse=True) result = {} for const in constitutions_data: name = const["名称"] keywords = const["关联关键字"] # Also include the 调理原则 keywords principle = const.get("调理原则", "") all_keywords = keywords + [principle] matched = [] for h in herbs: herb_name = h.get("名称", "") # Match in 功效作用 field (which contains 功能, 主治, 用法用量 etc.) text = "" eff = h.get("功效作用", {}) if isinstance(eff, dict): for v in eff.values(): if isinstance(v, str): text += v + " " elif isinstance(eff, str): text = eff # Also match in 简介 if "简介" in h: text += h["简介"] + " " score = match_keywords_in_text(all_keywords, text) if score > 0: matched.append({ "名称": herb_name, "来源": h.get("url", ""), "功效作用": text[:200] + ("..." if len(text) > 200 else ""), "得分": score }) matched.sort(key=lambda x: x["得分"], reverse=True) result[name] = matched print(f" {name}: matched {len(matched)} herb entries") return result def build_acupoint_association(constitutions_data): """体质↔穴位关联: match 主治 and 详细主治 fields with constitution disease/symptom keywords.""" acu_dir = os.path.join(BASE_DIR, "01_来源数据", "针灸穴位") acupoints = load_json_files(acu_dir) print(f"Loaded {len(acupoints)} acupoint entries") result = {} for const in constitutions_data: name = const["名称"] # Use disease keywords and symptom keywords from constitution keywords = const["关联关键字"] + const.get("相关疾病", []) matched = [] for a in acupoints: text = "" for field in ["主治", "详细主治", "功能", "功能作用", "简介", "名称"]: if field in a and a[field]: text += a[field] + " " score = match_keywords_in_text(keywords, text) if score > 0: matched.append({ "名称": a.get("名称", ""), "来源": a.get("url", ""), "主治": a.get("主治", a.get("详细主治", "")), "得分": score }) matched.sort(key=lambda x: x["得分"], reverse=True) result[name] = matched print(f" {name}: matched {len(matched)} acupoint entries") return result def main(): # Step 1: 保存九种体质详细数据 output_dir = os.path.join(BASE_DIR, "02_加工数据", "中医体质") os.makedirs(output_dir, exist_ok=True) constitutions_path = os.path.join(output_dir, "九种体质详细数据.json") with open(constitutions_path, "w", encoding="utf-8") as f: json.dump(constitutions, f, ensure_ascii=False, indent=2) print(f"Saved constitution data to {constitutions_path}") # Step 2: 构建交叉关联 print("\n=== Building Diet Associations ===") diet_assoc = build_diet_association(constitutions) print("\n=== Building Herb Associations ===") herb_assoc = build_herb_association(constitutions) print("\n=== Building Acupoint Associations ===") acu_assoc = build_acupoint_association(constitutions) # 计算统计 total_diet = sum(len(v) for v in diet_assoc.values()) total_herb = sum(len(v) for v in herb_assoc.values()) total_acu = sum(len(v) for v in acu_assoc.values()) cross_ref = { "体质-药膳关联": diet_assoc, "体质-药材关联": herb_assoc, "体质-穴位关联": acu_assoc, "总结统计": { "体质数": 9, "总关联药膳数": total_diet, "总关联药材数": total_herb, "总关联穴位数": total_acu } } cross_path = os.path.join(output_dir, "体质-大医网交叉关联.json") with open(cross_path, "w", encoding="utf-8") as f: json.dump(cross_ref, f, ensure_ascii=False, indent=2) print(f"\nSaved cross-reference to {cross_path}") print(f"Summary: {total_diet} diet entries, {total_herb} herb entries, {total_acu} acupoint entries matched") if __name__ == "__main__": main()