书籍切片提取制作SQLite数据库检索方案之一

步骤

  1. epub转换为html格式
  2. 用Python识别html分类提取

片段的结构:

  1. 病症标题:<p><strong>第一节 感冒</strong></p>
  2. 定义部分:没有标题,直接跟在病症标题后面
  3. 各小节:以【】包裹的标题,如【病因病机】、【诊断与鉴别诊断】等

用代码适应这种结构:

import re
import pandas as pd
from bs4 import BeautifulSoup
import warnings
warnings.filterwarnings('ignore')

def extract_disease_data(html_content):
    """
    从HTML内容中提取病症数据
    """
    soup = BeautifulSoup(html_content, 'html.parser')
    
    # 找到所有的段落
    paragraphs = soup.find_all('p')
    
    diseases = []
    current_disease = None
    current_section = None
    buffer = []
    
    for i, p in enumerate(paragraphs):
        # 获取段落文本,保留换行
        text = p.get_text(strip=False)
        
        # 检查是否是病症标题(如"第一节 感冒")
        # 同时处理 <strong>第一节 感冒</strong> 这种格式
        if p.find('strong'):
            strong_text = p.find('strong').get_text(strip=True)
            title_match = re.match(r'^第.*节\s+(.*)$', strong_text.strip())
        else:
            title_match = re.match(r'^第.*节\s+(.*)$', text.strip())
            
        if title_match:
            # 保存上一个病症
            if current_disease:
                # 处理缓冲区内容
                if buffer and current_section:
                    buffer_text = '\n'.join(buffer).strip()
                    if buffer_text:
                        current_disease[current_section] = buffer_text
                diseases.append(current_disease)
            
            # 开始新的病症
            disease_name = title_match.group(1)
            current_disease = {
                '病症名称': disease_name,
                '定义': '',
                '病因病机': '',
                '诊断与鉴别诊断': '',
                '辨证论治': '',
                '辨治备要': '',
                '临证要点': '',
                '预防调护': '',
                '小结': '',
                '名医经验': '',
                '古籍摘要': '',
                '文献推介': ''
            }
            current_section = '定义'  # 定义部分没有明确标题,直接跟在病症名称后面
            buffer = []
            continue
        
        # 检查是否是各个部分的标题(使用【】包裹)
        section_patterns = [
            (r'【病因病机】', '病因病机'),
            (r'【诊断与鉴别诊断】', '诊断与鉴别诊断'),
            (r'【辨证论治】', '辨证论治'),
            (r'【辨治备要】', '辨治备要'),
            (r'【临证要点】', '临证要点'),
            (r'【预防调护】', '预防调护'),
            (r'【小结】', '小结'),
            (r'【名医经验】', '名医经验'),
            (r'【古籍摘要】', '古籍摘要'),
            (r'【文献推介】', '文献推介')
        ]
        
        section_found = False
        for pattern, section_name in section_patterns:
            if pattern in text:
                if buffer and current_section and current_disease:
                    buffer_text = '\n'.join(buffer).strip()
                    if buffer_text:
                        current_disease[current_section] = buffer_text
                current_section = section_name
                buffer = []
                section_found = True
                
                # 移除标题文本,只保留内容部分
                text = text.replace(pattern, '').strip()
                if text:  # 如果标题后面还有内容
                    buffer.append(text)
                break
        
        if section_found:
            continue
        
        # 跳过空行和只包含span标签的内容
        if not text.strip() or re.match(r'^\s*$', text):
            continue
        
        # 跳过图片标签
        if p.find('img'):
            continue
        
        # 跳过纯字体格式标签(如<font>)
        if p.find('font') and not p.get_text(strip=True):
            continue
        
        # 将内容添加到缓冲区
        if current_section and text.strip():
            # 清理文本中的多余空格,但保留换行
            cleaned_text = re.sub(r'\s+', ' ', text.strip())
            # 保留有序列表格式(如1.、2.等)
            if re.match(r'^\d+[\..]', cleaned_text):
                buffer.append(cleaned_text)
            else:
                buffer.append(cleaned_text)
    
    # 处理最后一个病症
    if current_disease:
        if buffer and current_section:
            buffer_text = '\n'.join(buffer).strip()
            if buffer_text:
                current_disease[current_section] = buffer_text
        diseases.append(current_disease)
    
    return diseases

def clean_html_content(html_content):
    """
    清理HTML内容,移除不需要的标签
    """
    # 移除script和style标签
    html_content = re.sub(r'<script[^>]*>.*?</script>', '', html_content, flags=re.DOTALL)
    html_content = re.sub(r'<style[^>]*>.*?</style>', '', html_content, flags=re.DOTALL)
    
    # 保留段落格式
    html_content = html_content.replace('<br>', '\n')
    html_content = html_content.replace('<br/>', '\n')
    html_content = html_content.replace('<br />', '\n')
    
    return html_content

def main():
    # 读取HTML文件
    with open('中医内科学.html', 'r', encoding='utf-8') as f:
        html_content = f.read()
    
    # 清理HTML内容
    html_content = clean_html_content(html_content)
    
    # 提取病症数据
    diseases = extract_disease_data(html_content)
    
    # 创建DataFrame
    df = pd.DataFrame(diseases)
    
    # 重新排列列顺序(可以根据需要调整)
    column_order = [
        '病症名称', '定义', '病因病机', '诊断与鉴别诊断', 
        '辨证论治', '辨治备要', '临证要点', '预防调护',
        '小结', '名医经验', '古籍摘要', '文献推介'
    ]
    
    # 只保留实际存在的列
    existing_columns = [col for col in column_order if col in df.columns]
    df = df[existing_columns]
    
    # 保存到Excel
    output_file = '中医内科学_病症数据.xlsx'
    df.to_excel(output_file, index=False, engine='openpyxl')
    
    print(f"数据提取完成!共提取了 {len(diseases)} 个病症信息")
    print(f"数据已保存到: {output_file}")
    
    # 显示前几行数据
    print("\n前5个病症的信息:")
    print(df.head().to_string())
    
    # 显示列信息
    print(f"\n提取的列:{list(df.columns)}")

if __name__ == "__main__":
    main()

主要修改点:

  1. 病症标题识别:改进了对<strong>第一节 感冒</strong>这种格式的支持
  2. 章节标题识别:使用正则表达式匹配【】包裹的标题
  3. 字段设置:根据您提供的片段,设置了完整的字段列表
  4. 内容清理:添加了对图片标签、字体格式标签的过滤
  5. 动态列处理:根据实际提取的列进行DataFrame构建

使用说明:

  1. 将HTML文件保存为中医内科学.html
  2. 运行此脚本
  3. 提取的数据将保存为中医内科学_病症数据.xlsx

如果您的书籍结构有变化,可以调整section_patterns列表来添加或修改章节标题。

posted on 2026-01-22 17:30  igaoyuan  阅读(1)  评论(0)    收藏  举报

导航