Webページから構造化データを抽出!Pythonライブラリ extruct 徹底解説 📊

Python

現代のWebページには、人間が読むための情報だけでなく、検索エンジンや他のプログラムが理解しやすいように「構造化データ」が埋め込まれていることが増えています。商品情報、レビュー、イベント情報、レシピなど、様々なデータが標準化された形式で記述されています。これらの構造化データを効率的に抽出できれば、Webスクレイピングやデータ分析の可能性が大きく広がりますよね!😊

そこで登場するのが、Pythonライブラリ extruct です。extruct は、HTMLドキュメントに埋め込まれた様々な形式の構造化メタデータを抽出するための強力なツールです。この記事では、extruct の基本的な使い方から、対応しているメタデータ形式、内部動作、応用例まで、徹底的に解説していきます。

🌟 extruct とは? その魅力

extruct は、HTMLマークアップから埋め込みメタデータを抽出することに特化したPythonライブラリです。Webスクレイピングライブラリの雄である Beautiful Souplxml が汎用的なHTML/XMLパーサーであるのに対し、extruct は特定の構造化データ形式(シンタックス)の抽出に焦点を当てています。

主な特徴は以下の通りです:

  • 多様なフォーマットに対応: Microdata, JSON-LD, RDFa, Open Graph, Microformats, Dublin Core など、Webで広く使われている主要な構造化データ形式をサポートしています。
  • シンプルなAPI: 基本的な抽出は非常に簡単で、数行のコードで実現できます。
  • 柔軟な選択肢: すべての形式を一括で抽出することも、特定の形式だけを選択して抽出することも可能です。
  • 依存ライブラリの活用: 内部では、各形式に対応した専門のライブラリ (rdflib, mf2py など) や HTMLパーサー (lxml, html5lib) を利用しており、信頼性の高い抽出を実現しています。Beautiful Soupも依存関係に含まれています。
  • コマンドラインツール: ライブラリとしてだけでなく、コマンドラインから直接URLを指定してメタデータを抽出するツールも提供されています。
なぜ構造化データが重要なのか?🤔
構造化データは、検索エンジンがWebページの内容をより深く理解し、リッチリザルト(検索結果での特別な表示)を表示するために利用されます。また、異なるシステム間でデータを連携したり、Webページから特定の情報を効率的に収集したりする上でも不可欠な技術となっています。extruct を使うことで、これらの貴重なデータソースに簡単にアクセスできるようになります。

🚀 インストールと基本的な使い方

インストール

extruct のインストールは、pipを使って簡単に行えます。

pip install extruct

もしコマンドラインツールも使いたい場合は、追加の依存関係 (requests) を含めてインストールします。

pip install 'extruct[cli]'

基本的な使い方: URLから抽出

最も基本的な使い方は、WebページのURLを指定して、そこに含まれるすべての構造化データを抽出する方法です。これには requests ライブラリ (別途インストールが必要) を使ってHTMLコンテンツを取得し、extruct.extract() 関数に渡します。

import requests
import extruct
import pprint
from w3lib.html import get_base_url # URLからベースURLを取得するヘルパー関数

# 抽出したいWebページのURL
url = 'https://scrapfly.io/blog/web-scraping-microformats/' # 例

# requestsを使ってHTMLコンテンツを取得
try:
    r = requests.get(url, headers={'User-Agent': 'MyExtructBot/1.0'}) # User-Agentを指定推奨
    r.raise_for_status() # HTTPエラーがあれば例外を発生させる
    html = r.text
except requests.exceptions.RequestException as e:
    print(f"Error fetching URL {url}: {e}")
    exit()

# ベースURLを取得 (相対URLの解決に必要)
base_url = get_base_url(html, url)

# extructでメタデータを抽出
# base_urlを指定することが推奨されます
# uniform=True にすると、JSON-LDの結果が常にリストになるように調整されます
# errors='log' にすると、パースエラーが発生した場合にログに出力します('strict'で例外発生、'ignore'で無視)
try:
    data = extruct.extract(html,
                           base_url=base_url,
                           uniform=True,
                           errors='log')
except Exception as e:
    print(f"Error extracting data: {e}")
    exit()

# 結果を整形して表示
pp = pprint.PrettyPrinter(indent=2)
pp.pprint(data)

このコードを実行すると、data 変数には辞書形式で抽出結果が格納されます。キーはメタデータ形式(例: 'microdata', 'json-ld', 'opengraph' など)、値はその形式で抽出されたデータのリストになります。

基本的な使い方: HTML文字列から抽出

既にHTMLコンテンツが文字列として手元にある場合は、直接それを extruct.extract() に渡すことができます。ただし、相対URLが含まれている可能性があるため、base_url を指定することが強く推奨されます。

import extruct
import pprint
from w3lib.html import get_base_url

# HTMLコンテンツ (例)
html_content = """
<!DOCTYPE html>
<html>
<head>
  <title>Test Page</title>
  <meta property="og:title" content="Example Title" />
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Person",
    "name": "John Doe",
    "url": "/profile/johndoe"
  }
  </script>
</head>
<body itemscope itemtype="http://schema.org/Product">
  <h1 itemprop="name">Awesome Gadget</h1>
  <span itemprop="price">99.99</span>
</body>
</html>
"""

# 抽出元のURL (相対パス解決のため)
original_url = 'http://example.com/page.html'
base_url = get_base_url(html_content, original_url) # または直接 'http://example.com' など

# メタデータを抽出
data = extruct.extract(html_content, base_url=base_url, errors='log')

# 結果を表示
pp = pprint.PrettyPrinter(indent=2)
pp.pprint(data)

この例では、Open Graph、JSON-LD、Microdataの3つの形式のデータが抽出されるはずです。

🧩 対応しているメタデータ形式

extruct は、以下の主要な埋め込みメタデータ形式に対応しています。それぞれの形式について簡単に見ていきましょう。

1. Microdata (マイクロデータ)

W3Cによって標準化された仕様で、HTML要素に itemscope, itemtype, itemprop といった属性を追加することで構造化データを埋め込みます。Schema.org の語彙と組み合わせて使われることが多いです。

HTML埋め込み例:

<div itemscope itemtype="http://schema.org/Person">
  My name is <span itemprop="name">Alice</span>.
  My website is <a href="http://example.com" itemprop="url">example.com</a>.
  I am a <span itemprop="jobTitle">Software Engineer</span>.
</div>

extruct での抽出結果 (data['microdata']):

[{'type': 'http://schema.org/Person',
  'properties': {'name': 'Alice',
                 'url': 'http://example.com',
                 'jobTitle': 'Software Engineer'}}]

Microdata は HTML 要素の属性として直接記述されるため、ページに表示されている情報と一致しやすいという利点があります。


2. JSON-LD (ジェイソン・エルディー)

JavaScript Object Notation for Linked Data の略で、JSON形式で構造化データを記述し、<script type="application/ld+json"> タグ内に埋め込む方式です。Googleが推奨しており、現在最も広く使われている形式の一つです。

HTML埋め込み例:

<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "Recipe",
  "name": "Chocolate Cake",
  "author": {
    "@type": "Person",
    "name": "Mary Stone"
  },
  "prepTime": "PT15M",
  "cookTime": "PT1H",
  "recipeYield": "8",
  "recipeIngredient": [
    "Flour",
    "Sugar",
    "Eggs",
    "Chocolate"
  ]
}
</script>

extruct での抽出結果 (data['json-ld']):

[{'@context': 'http://schema.org',
  '@type': 'Recipe',
  'name': 'Chocolate Cake',
  'author': {'@type': 'Person', 'name': 'Mary Stone'},
  'prepTime': 'PT15M',
  'cookTime': 'PT1H',
  'recipeYield': '8',
  'recipeIngredient': ['Flour', 'Sugar', 'Eggs', 'Chocolate']}]

JSON-LD は HTML の構造とは独立して記述できるため、実装が比較的容易ですが、ページに表示されている内容と乖離する可能性もあります。


3. RDFa (アールディーエフエー)

Resource Description Framework in Attributes の略で、Microdata と同様に HTML 属性を使って構造化データを埋め込みますが、より表現力が高い RDF (Resource Description Framework) モデルに基づいています。vocab, typeof, property などの属性を使用します。Open Graph Protocol (OGP) も内部的には RDFa の一種として扱われることがあります。

HTML埋め込み例 (Schema.org 語彙):

<div vocab="http://schema.org/" typeof="Person">
  My name is <span property="name">Bob</span>.
  My homepage is <a property="url" href="http://example.org">example.org</a>.
</div>

extruct での抽出結果 (data['rdfa']):

RDFa の抽出には rdflib ライブラリが使用され、結果は通常、グラフ構造を表現する形式 (タプルのリストなど) になります。抽出結果の構造は Microdata や JSON-LD とは異なります。

# 結果の形式は rdflib の出力に依存し、複雑になる場合がある
# 例:
# [{'@id': '_:N5f...', '@type': ['http://schema.org/Person'],
#   'http://schema.org/name': [{'@value': 'Bob'}],
#   'http://schema.org/url': [{'@id': 'http://example.org'}]}]

RDFa は Microdata よりも柔軟な表現が可能ですが、記述がやや複雑になる傾向があります。extruct における RDFa のサポートは「実験的(experimental)」と位置付けられています。


4. Open Graph Protocol (オープン・グラフ・プロトコル)

Facebook によって提唱されたプロトコルで、Webページがソーシャルグラフ上でどのように表現されるかを定義します。主に Facebook や Twitter などで Web ページのプレビュー(タイトル、説明、画像など)を表示するために使用されます。HTML の <meta> タグの property 属性 (例: property="og:title") を使って記述します。

HTML埋め込み例:

<head>
  <meta property="og:title" content="The Rock" />
  <meta property="og:type" content="video.movie" />
  <meta property="og:url" content="http://www.imdb.com/title/tt0117500/" />
  <meta property="og:image" content="http://ia.media-imdb.com/images/rock.jpg" />
  <meta property="og:description" content="A group of U.S. Marines, under command of..." />
</head>

extruct での抽出結果 (data['opengraph']):

[{'namespace': 'og',
  'properties': [('title', 'The Rock'),
                 ('type', 'video.movie'),
                 ('url', 'http://www.imdb.com/title/tt0117500/'),
                 ('image', 'http://ia.media-imdb.com/images/rock.jpg'),
                 ('description', 'A group of U.S. Marines, under command of...')]}
]

extructog:image のように同じプロパティが複数回現れる場合も考慮し、設定によっては配列として扱うことも可能です (with_og_array=True オプション、v0.10.0以降)。


5. Microformats (マイクロフォーマット)

既存の HTML クラス属性 (class="...") を利用して、特定の意味論的情報(人物、イベント、レビューなど)を表現する規約です。h-card (人物), h-entry (ブログ投稿), h-event (イベント) など、様々な “h-*” 形式があります。Microformats2 (mf2) が現在の主流です。

HTML埋め込み例 (h-card):

<div class="h-card">
  <p class="p-name">Jane Doe</p>
  <a class="u-url" href="http://janedoe.example.com">Website</a>
  <span class="p-org">Example Inc.</span>
</div>

extruct での抽出結果 (data['microformat']):

Microformats の抽出には mf2py ライブラリが使用されます。

[{'type': ['h-card'],
  'properties': {'name': ['Jane Doe'],
                 'url': ['http://janedoe.example.com'],
                 'org': ['Example Inc.']}}]

Microformats は比較的古くから存在しますが、現在でもブログなどで利用されています。


6. Dublin Core (ダブリン・コア)

図書館情報学の分野で生まれたメタデータ標準で、主にリソース(文書、画像など)の書誌情報を記述するために使われます。HTML の <meta> タグや <link> タグを使って埋め込まれます。extruct では DC-HTML-2003 という仕様に基づいた抽出をサポートしています (v0.11.0以降)。

HTML埋め込み例:

<head>
  <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
  <meta name="DC.title" content="My Document Title" />
  <meta name="DC.creator" content="John Smith" />
  <meta name="DC.date" content="2024-04-01" />
</head>

extruct での抽出結果 (data['dublincore']):

[{'namespaces': {'dc': 'http://purl.org/dc/elements/1.1/'},
  'elements': [{'name': 'title', 'content': 'My Document Title'},
               {'name': 'creator', 'content': 'John Smith'},
               {'name': 'date', 'content': '2024-04-01'}],
  'terms': []}]

Dublin Core は学術リポジトリなどで見かけることがあります。

⚙️ 内部動作とカスタマイズ

extruct は、単純に見える API の裏側で、複数のライブラリと連携して複雑な処理を行っています。その仕組みと、利用可能なカスタマイズオプションについて見ていきましょう。

HTML パーサー

extruct は、入力された HTML 文字列を解析するために HTML パーサーを利用します。デフォルトでは html5lib が使われますが、lxml がインストールされていれば、より高速な lxml が優先的に使用されます。lxml は C 言語で実装されているためパフォーマンスが高いですが、インストールに追加の手順が必要になる場合があります。

各シンタックスに対応するライブラリ

extruct は、各メタデータ形式の抽出に専用のライブラリを利用しています。

メタデータ形式利用ライブラリ備考
Microdataextruct 内部実装 (lxmlベース)W3C の仕様に基づいて実装されています。
JSON-LDextruct 内部実装標準の json モジュール (または jstyleson for JS comments, v0.10.0+) を使用してパースします。
RDFardflib, pyRdfa3RDF データの処理に標準的なライブラリを使用。実験的サポート。
Open Graphextruct 内部実装 (lxmlベース)HTML の meta タグを解析します。
Microformatsmf2pyMicroformats2 のパースに特化したライブラリです。
Dublin Coreextruct 内部実装 (lxmlベース)HTML の meta, link タグを解析します。

これらの依存ライブラリは、extruct をインストールする際に自動的にインストールされます(一部オプションあり)。

extract() 関数の主要なパラメータ

extruct.extract() 関数は、抽出処理を細かく制御するためのいくつかのパラメータを受け取ります。

パラメータ名説明デフォルト値
htmlstring抽出対象の HTML コンテンツ (バイト列または文字列)。必須
base_urlHTML ドキュメントのベース URL。相対 URL を解決するために使用されます。指定を強く推奨。None
encodingHTML のエンコーディング。指定しない場合、HTML ドキュメントから推測されます。None
syntaxes抽出するメタデータ形式のリスト。例: ['json-ld', 'microdata']。指定しない場合、サポートされているすべての形式が対象になります。['microdata', 'json-ld', 'opengraph', 'microformat', 'rdfa', 'dublincore'] (サポート状況による)
errorsパースエラー発生時の挙動を指定します。
'strict': 例外 (例: ParserError) を発生させます。
'log': エラーをログに出力し、処理を続行します。
'ignore': エラーを無視します。
'strict'
uniformTrue に設定すると、JSON-LD の結果が常にリスト形式になるように正規化されます。JSON-LD ではトップレベルが単一のオブジェクトの場合とオブジェクトの配列の場合があり得るため、これを統一します。False
return_html_node(Microdata, RDFa のみ) True にすると、抽出された各アイテムに対応する lxml の HTML 要素ノードも結果に含めます。False
with_og_array(Open Graph のみ, v0.10.0+) True にすると、og:image のように複数存在するプロパティを値のリストとして返します。False
*args, **kwargs内部で使用される各シンタックスエクストラクタに追加で渡される引数。

パラメータ利用例: JSON-LD と Microdata のみ抽出し、エラーはログに出力

import requests
import extruct
import pprint
import logging
from w3lib.html import get_base_url

# エラーログをコンソールに表示する設定
logging.basicConfig(level=logging.WARNING)

url = 'some_complex_page.html' # エラーが含まれているかもしれないページ
try:
    r = requests.get(url, headers={'User-Agent': 'MyExtructBot/1.0'})
    r.raise_for_status()
    html = r.text
except requests.exceptions.RequestException as e:
    print(f"Error fetching URL {url}: {e}")
    exit()

base_url = get_base_url(html, url)

# JSON-LD と Microdata のみ抽出し、エラーはログに出力
try:
    data = extruct.extract(html,
                           base_url=base_url,
                           syntaxes=['json-ld', 'microdata'],
                           errors='log') # エラー発生時はログ出力
except Exception as e:
    # errors='log' でも予期せぬ例外は発生しうる
    print(f"Unexpected error during extraction: {e}")
    exit()

pp = pprint.PrettyPrinter(indent=2)
pp.pprint(data)

このようにパラメータを調整することで、特定のニーズに合わせたデータ抽出が可能になります。特に errors パラメータは、大量の Web ページを処理する際に、一部のページの不正なマークアップによって全体の処理が停止するのを防ぐために重要です。

💡 ユースケースと応用例

extruct は、その強力な構造化データ抽出機能により、様々な分野で活用できます。

  • Web スクレイピングの強化: 通常の HTML タグだけでなく、構造化データを併せて抽出することで、より正確で信頼性の高い情報を収集できます。特に EC サイトの商品情報 (価格、在庫、レビュー数など) や、イベント情報サイト (日時、場所など)、レシピサイト (材料、調理時間など) のスクレイピングに有効です。
  • SEO 分析・競合調査: 競合サイトがどのような構造化データ (Schema.org マークアップなど) を実装しているかを分析し、自社サイトの SEO 戦略に活かすことができます。特定のキーワードで上位表示されるサイトが共通して利用しているスキーマなどを調査できます。
  • 自社サイトの構造化データ検証: 自社サイトに実装した構造化データが、意図した通りに抽出・解釈されるかを確認するためのテストツールとして利用できます。Google の リッチリザルト テスト のようなツールと合わせて使うことで、より詳細な検証が可能です。
  • ナレッジグラフ構築: Web 上の様々なソースから構造化データを抽出し、それらを統合して独自のナレッジグラフを構築するためのデータソースとして利用できます。抽出したエンティティ間の関係性を分析することも可能です。
  • データ連携・API 代替: 公式 API が提供されていない Web サービスでも、公開されているページに構造化データが埋め込まれていれば、それを簡易的な API のように利用してデータを取得できる場合があります (利用規約には注意が必要です)。
  • 学術研究・データジャーナリズム: 大量の Web ページから特定の情報 (例: 特定の組織に関する情報、ニュース記事のメタデータなど) を体系的に収集・分析するために利用できます。

Scrapy との連携

人気の Web スクレイピングフレームワークである Scrapy とも簡単に連携できます。Scrapy の Spider 内で extruct を呼び出し、抽出したデータを Scrapy の Item として処理することができます。

import scrapy
import extruct
from w3lib.html import get_base_url
# from myproject.items import ProductItem # Scrapy Item を定義しておく

class ProductSpider(scrapy.Spider):
    name = 'product_extractor'
    start_urls = ['http://example-shop.com/products/123']

    def parse(self, response):
        base_url = get_base_url(response.text, response.url)
        try:
            data = extruct.extract(response.body, # response.body はバイト列
                                   base_url=base_url,
                                   syntaxes=['microdata', 'json-ld'],
                                   errors='log')
        except Exception as e:
            self.logger.error(f"Extruct failed for {response.url}: {e}")
            return

        # 抽出したデータから Item を作成するロジック
        # (ここでは Microdata の Product を想定)
        for item_data in data.get('microdata', []):
            if item_data.get('type') == 'http://schema.org/Product':
                # item = ProductItem() # Scrapy Item オブジェクト
                # item['name'] = item_data.get('properties', {}).get('name')
                # item['price'] = item_data.get('properties', {}).get('price')
                # ... 他のフィールドも抽出 ...
                # yield item
                self.logger.info(f"Extracted Product: {item_data.get('properties', {}).get('name')}")
                yield item_data # 簡単のため辞書をそのまま返す例

        # JSON-LDなども同様に処理できる
        # ...

このように、Scrapy のレスポンスオブジェクトを extruct に渡すことで、スクレイピングプロセスの中に構造化データの抽出をシームレスに組み込むことができます。

🔄 他のライブラリとの比較

Web スクレイピングや HTML 解析の文脈では、他にも様々な Python ライブラリが存在します。extruct がそれらとどのように異なり、どのような場合に適しているかを見てみましょう。

ライブラリ主な目的構造化データ抽出長所短所extruct との関係
extruct埋め込み構造化メタデータの抽出◎ (専門)・多様な形式に対応
・シンプルな API
・専門ライブラリ利用
・汎用的な HTML 操作は不得意
・依存ライブラリが多い
Beautiful SoupHTML/XML のパースとDOM操作△ (手動実装が必要)・柔軟な DOM 操作
・寛容なパーサー
・初心者にも優しい
・構造化データの知識が必要
・抽出ロジックが複雑化しやすい
内部で利用されることがある (依存関係)
lxml高速な HTML/XML パースと XPath/CSS セレクタ△ (手動実装が必要)・非常に高速
・XPath/CSSセレクタ対応
・標準準拠
・API がやや低レベル
・構造化データの知識が必要
内部で HTML パーサーとして利用
ScrapyWeb スクレイピングフレームワーク△ (手動実装 or extruct等と連携)・非同期処理
・拡張性が高い
・パイプライン、ミドルウェア
・学習コストがやや高い
・構造化データ抽出は別途実装
extruct を Spider 内で利用可能
html-textHTML から人間が読む形式のテキストを抽出・主要なテキストコンテンツ抽出に特化
・シンプル
・構造化データは抽出不可Microdata のテキスト抽出などで内部利用 (v0.8.0+)
Newspaper3kニュース記事の抽出と解析△ (一部メタデータは抽出可能)・記事本文、著者、日付等の抽出
・NLP 機能
・ニュース記事以外には不向き
・構造化データ抽出は限定的
目的が異なる
TrafilaturaWeb ページからのメインコンテンツとメタデータの抽出△ (一部メタデータは抽出可能)・高速で高精度な本文抽出
・メタデータ抽出機能あり
・構造化データの網羅性は extruct に劣る一部機能が重複するが、extruct は構造化データにより特化

使い分けのポイント:

  • Web ページに埋め込まれた Schema.org, JSON-LD, Open Graph などの標準的な構造化データ を網羅的に、かつ簡単に抽出したい場合は extruct が最適です。
  • 特定の HTML タグや CSS クラスに含まれる情報を、構造化データ形式に関わらず柔軟に抽出 したい場合は Beautiful Souplxml を使って自分で抽出ロジックを組むのが適しています。
  • 大規模なクローリングや複雑なスクレイピング処理 を行いたい場合は Scrapy フレームワークを基盤とし、必要に応じて extruct や他のパーサーライブラリを組み込むのが良いでしょう。
  • 単に Web ページから 記事本文のようなメインテキスト を抽出したい場合は html-textTrafilatura がより手軽かもしれません。

多くの場合、これらのライブラリは競合するものではなく、目的に応じて組み合わせて使うことで、より強力なデータ抽出パイプラインを構築できます。🛠️

📝 まとめと注意点

extruct は、Web ページに埋め込まれた多様な形式の構造化メタデータを、シンプルかつ効率的に抽出するための優れた Python ライブラリです。Microdata, JSON-LD, Open Graph など、現代の Web で広く利用されている標準形式に対応しており、Web スクレイピング、SEO 分析、データ収集など、多くの場面で強力な武器となります。

👍 メリット

  • 簡単な API: 基本的な抽出は数行のコードで可能。
  • 幅広い形式をサポート: 一つのライブラリで多くの構造化データ形式に対応。
  • 依存ライブラリの活用: 各形式の専門ライブラリを利用し、信頼性の高い抽出を実現。
  • 柔軟なオプション: 抽出対象のシンタックス選択、エラーハンドリングなど、カスタマイズが可能。

⚠️ 注意点

  • 依存関係: 多くの外部ライブラリに依存しているため、環境によっては依存関係の解決に注意が必要な場合があります。特に lxmlrdflib 関連。
  • HTML の品質依存: 抽出対象の HTML が不正な形式であったり、構造化データの記述に誤りがある場合、期待通りに抽出できない、あるいはエラーが発生する可能性があります。errors パラメータを適切に設定することが重要です。
  • RDFa の実験的サポート: RDFa の抽出は「実験的」とされており、複雑なケースでは挙動が不安定になる可能性があります。
  • パフォーマンス: 非常に大量のページを高速に処理する必要がある場合、依存ライブラリを含めた全体のパフォーマンスを考慮する必要があります。lxml の利用が推奨されます。
  • ウェブサイトの変更: Web サイトの構造やマークアップは変更される可能性があるため、定期的なスクリプトのメンテナンスが必要です。
extruct を活用することで、これまで手動での解析や複雑なスクレイピングロジックが必要だった構造化データの抽出が、格段に容易になります。Web から価値あるデータを引き出すための強力なツールとして、ぜひあなたのプロジェクトに取り入れてみてください!🎉

コメント

タイトルとURLをコピーしました