電子書籍からデータを抽出し、構造化してデータベースに格納するまでのプロセスについて解説します。全体的な流れはEPUB形式の書籍をHTMLに変換し、Excelファイルを経由してデータベースに保存するというものです。
抽出プロセスの全体像
- EPUB形式の書籍をHTMLファイルに変換する
- HTMLの構造と特徴的なタグや記号(見出しタグ、括弧類など)を分析する
- Pythonでパース処理を行い、必要なデータを抽出してExcel形式で出力する
HTML構造の分析
対象となるHTMLファイルを確認すると、処方箋情報が特定の見出しタグ(<h2 class="sect2">)で構造化されていることがわかります。各処方箋は医師名と処方名からなるタイトルを持ち、「組成」「功效」「主治」「用法」「経験」といった項目が括弧書きのラベルで区切られています。
抽出対象の構造例:
<h2>王綿之:加味香蘇散</h2>
【組成】 紫蘇葉5g、陳皮・香附各4g...(成分情報)
【功效】 発汗解表。(効果)
【主治】 四時感冒之風寒表証...(適応症)
【用法】 水煎服、毎日1剤。(使用方法)
【経験】 本方王老多用于治療...(臨床経験)
Pythonによる実装
BeautifulSoupを使用してHTMLを解析し、pandasでデータを整理してExcelに出力します。以下は実装コードの例です。
import pandas as pd
from bs4 import BeautifulSoup
import re
# 定数定義
INPUT_FILE = 'medical_book_sample.html'
OUTPUT_FILE = 'prescriptions_extracted.xlsx'
TARGET_CLASS = 'sect2'
# 抽出対象のラベル定義
LABELS = {
'【組成】': 'ingredients',
'【功效】': 'effects',
'【主治】': 'indications',
'【用法】': 'usage',
'【経験】': 'clinical_notes'
}
def load_html_content(filepath):
"""HTMLファイルを読み込んでBeautifulSoupオブジェクトを返す"""
with open(filepath, 'r', encoding='utf-8') as file:
return BeautifulSoup(file.read(), 'html.parser')
def extract_prescription_title(element):
"""h2要素から処方名を抽出(医師名:処方名の形式)"""
title_text = element.get_text(strip=True)
return title_text if ':' in title_text else None
def parse_content_block(paragraph):
"""段落からラベルと内容を分離して返す"""
text = paragraph.get_text(strip=True)
for label_jp, label_en in LABELS.items():
if label_jp in text:
content = text.replace(label_jp, '').strip()
return label_en, content
return None, None
def extract_prescriptions(soup):
"""HTMLから全ての処方情報を抽出"""
sections = soup.find_all('h2', class_=TARGET_CLASS)
extracted_data = []
for section in sections:
# 処方名の取得
title = extract_prescription_title(section)
if not title:
continue
# 処方データの初期化
prescription = {
'処方名': title,
'ingredients': '',
'effects': '',
'indications': '',
'usage': '',
'clinical_notes': ''
}
# 次のh2タグまでの段落を処理
next_element = section.find_next_sibling()
while next_element:
# 次のセクションに到達したら終了
if next_element.name == 'h2' and TARGET_CLASS in next_element.get('class', []):
break
if next_element.name == 'p':
field_name, content = parse_content_block(next_element)
if field_name and content:
prescription[field_name] = content
next_element = next_element.find_next_sibling()
extracted_data.append(prescription)
return extracted_data
def save_to_excel(data, output_path):
"""データをExcelファイルに保存"""
df = pd.DataFrame(data)
df.to_excel(output_path, index=False, engine='openpyxl')
return len(data)
# メイン処理
def main():
soup = load_html_content(INPUT_FILE)
prescriptions = extract_prescriptions(soup)
count = save_to_excel(prescriptions, OUTPUT_FILE)
print(f'抽出完了: {count}件の処方データを{OUTPUT_FILE}に保存しました')
if __name__ == '__main__':
main()
拡張版:より堅牢な解析
HTML内にspanタグなどの入れ子構造がある場合、より詳細な解析が必要になります。以下は、spanタグ内の強調テキストを考慮した実装です。
import pandas as pd
from bs4 import BeautifulSoup
class PrescriptionExtractor:
"""処方情報抽出クラス"""
FIELD_MAPPING = {
'【組成】': 'ingredients',
'【功效】': 'effects',
'【主治】': 'indications',
'【用法】': 'usage',
'【経験】': 'clinical_notes'
}
def __init__(self, html_path):
self.soup = self._load_html(html_path)
self.results = []
def _load_html(self, path):
with open(path, 'r', encoding='utf-8') as f:
return BeautifulSoup(f.read(), 'html.parser')
def _get_label_from_element(self, element):
"""spanタグからラベルを取得"""
span = element.find('span', class_='emphasis_bold')
if span:
return span.get_text(strip=True)
return None
def _extract_text_content(self, element, label):
"""ラベルを除いたテキスト内容を取得"""
full_text = element.get_text(strip=True)
return full_text.replace(label, '').strip()
def process_sections(self):
"""全セクションを処理"""
sections = self.soup.find_all('h2', class_='sect2')
for section in sections:
title = section.get_text(strip=True)
# 医師名:処方名の形式のみ処理
if ':' not in title:
continue
record = self._create_record(title)
self._process_paragraphs(section, record)
self.results.append(record)
return self.results
def _create_record(self, title):
"""新規レコードの初期化"""
return {
'処方名': title,
'ingredients': '',
'effects': '',
'indications': '',
'usage': '',
'clinical_notes': ''
}
def _process_paragraphs(self, section, record):
"""段落を処理してレコードに追加"""
current = section.find_next_sibling()
while current:
if self._is_next_section(current):
break
if current.name == 'p':
self._update_record(current, record)
current = current.find_next_sibling()
def _is_next_section(self, element):
"""次のセクションかどうかを判定"""
return (element.name == 'h2' and
'sect2' in element.get('class', []))
def _update_record(self, paragraph, record):
"""段落からデータを抽出してレコードを更新"""
label = self._get_label_from_element(paragraph)
if label and label in self.FIELD_MAPPING:
field = self.FIELD_MAPPING[label]
record[field] = self._extract_text_content(paragraph, label)
def export_excel(self, output_path):
"""Excelファイルに出力"""
df = pd.DataFrame(self.results)
df.to_excel(output_path, index=False, engine='openpyxl')
return output_path
# 実行例
if __name__ == '__main__':
extractor = PrescriptionExtractor('medical_book_sample.html')
data = extractor.process_sections()
extractor.export_excel('prescriptions_output.xlsx')
print(f'{len(data)}件の処方を抽出しました')
実行環境の準備
上記コードを実行するには、以下のライブラリが必要です。
pip install pandas openpyxl beautifulsoup4
出力結果
実行後、以下のカラムを持つExcelファイルが生成されます。
- 処方名:医師名と処方名(例:王綿之:加味香蘇散)
- ingredients(組成):構成成分と分量
- effects(功效):薬効・作用
- indications(主治):適応症・症状
- usage(用法):服用方法
- clinical_notes(経験):臨床経験・解説
この方法を応用することで、様々な構造の電子書籍から必要な情報を効率的に抽出し、データベース化することが可能です。