Pythonを利用したWebスクレイピングにおいて、情報の構造化は非常に重要なステップとなります。
特にHTMLの<dl>(定義リスト)タグは、製品の仕様表やプロフィール情報、用語解説などで頻繁に利用されています。
この<dl>タグ内に含まれる<dt>(用語)と<dd>(説明)のペアを、Pythonの辞書型(dict)に変換することで、その後のデータ処理やJSON形式への出力が格段にスムーズになります。
本記事では、BeautifulSoupライブラリを用いて、効率的にdlタグの情報を辞書型へ変換する具体的な手法を解説します。
実務で役立つコード例とともに、複雑な構造への対応策も併せて紹介していきましょう。
dlタグと辞書型の親和性
HTMLの<dl>要素は、名前(<dt>)と値(<dd>)が対になっている構造を持ちます。
これはPythonにおけるキーと値のペアでデータを保持する「辞書型」のコンセプトと完全に一致しています。
スクレイピングで取得した生のリテラルデータを辞書型に格納することで、特定の項目名を用いたデータの抽出が容易になります。
後続のデータ分析やデータベースへの保存を考慮すると、取得段階で辞書型に変換しておくのがベストプラクティスと言えます。
基本的なdlタグの解析手順
BeautifulSoupを使って解析を行う前に、まずはターゲットとなるHTMLの構造を正確に把握する必要があります。
dlタグの構造を確認する
一般的な定義リストは、以下のようなHTML構造をしています。
<dl id="product-spec">
<dt>商品名</dt>
<dd>高性能スクレイピングツール</dd>
<dt>価格</dt>
<dd>2,980円</dd>
<dt>在庫</dt>
<dd>あり</dd>
</dl>
この例では、<dt>が辞書のキー、<dd>が辞書の値に対応することになります。
BeautifulSoupでの基本的な取得方法
まずはBeautifulSoupオブジェクトを生成し、findメソッドやselectメソッドで<dl>タグを特定します。
その後、タグ内のすべての要素をループ処理で走査していく流れが基本となります。
実践的な辞書変換のプログラム例
ここからは、実際に動作するPythonコードを用いて、変換プロセスを詳しく見ていきましょう。
1対1の対応関係で変換する場合
最もシンプルなケースは、1つの<dt>に対して1つの<dd>が順番に並んでいる構成です。
以下のコードは、BeautifulSoupのfind_allを用いてデータを抽出する手法です。
from bs4 import BeautifulSoup
html_content = """
<dl>
<dt>OS</dt>
<dd>Windows 11</dd>
<dt>CPU</dt>
<dd>Intel Core i7</dd>
<dt>RAM</dt>
<dd>16GB</dd>
</dl>
"""
soup = BeautifulSoup(html_content, 'html.parser')
dl_tag = soup.find('dl')
# zip関数を利用したスマートな変換
keys = [dt.get_text(strip=True) for dt in dl_tag.find_all('dt')]
values = [dd.get_text(strip=True) for dd in dl_tag.find_all('dd')]
result_dict = dict(zip(keys, values))
print(result_dict)
{'OS': 'Windows 11', 'CPU': 'Intel Core i7', 'RAM': '16GB'}
zip関数を利用することで、2つのリストを結合して効率的に辞書を生成できます。
1つのdtに対して複数のddが存在する場合
Webサイトによっては、1つの項目(<dt>)に対して複数の説明(<dd>)が付与されていることがあります。
この場合、先ほどのzip方式ではデータのズレが生じるため、イテレータを用いた処理が推奨されます。
from bs4 import BeautifulSoup
html_complex = """
<dl>
<dt>カテゴリ</dt>
<dd>家電</dd>
<dd>PCパーツ</dd>
<dt>配送方法</dt>
<dd>宅配便</dd>
</dl>
"""
soup = BeautifulSoup(html_complex, 'html.parser')
dl_data = {}
current_key = None
# dl内の子要素をループ
for child in soup.find('dl').find_all(['dt', 'dd']):
if child.name == 'dt':
current_key = child.get_text(strip=True)
dl_data[current_key] = []
elif child.name == 'dd' and current_key:
dl_data[current_key].append(child.get_text(strip=True))
# 1つしか値がない場合はリストを解除する調整
final_data = {k: v[0] if len(v) == 1 else v for k, v in dl_data.items()}
print(final_data)
{'カテゴリ': ['家電', 'PCパーツ'], '配送方法': '宅配便'}
タグの種類を判定しながら辞書を更新することで、不規則な構造にも柔軟に対応可能となります。
スクレイピング時の注意点とデータクレンジング
取得したデータがそのまま使える状態であるとは限りません。
空白文字や改行の除去
HTML内のコードの整形具合によっては、取得したテキストに余計な改行やスペースが含まれることが多々あります。
BeautifulSoupのget_text(strip=True)引数を利用するか、Python標準のstrip()メソッドを必ず適用しましょう。
欠損値への対応
サイトによっては<dt>はあるが<dd>が空欄、といったケースも存在します。
例外処理や条件分岐(if文)を組み込み、プログラムが途中で停止しないような設計を心がけてください。
まとめ
PythonのBeautifulSoupライブラリを使用して<dl>タグを辞書型に変換する方法について解説しました。
単純な1対1の構造であればzip関数を用いた手法が最も簡潔で高速です。
一方で、複雑な構造を持つサイトの場合は、タグの種類を判別しながらループ処理を行う手法が適しています。
取得したデータを辞書型に整理することは、その後のデータ分析の効率を劇的に向上させます。
今回紹介した実例を参考に、対象のWebサイトの構造に合わせた最適な変換ロジックを実装してみてください。
