Python Tips: Python の標準ライブラリだけで HTML からテキストを抽出したい

Python の標準ライブラリだけを使って HTML から特定のタグの中のテキストを抽出する方法について説明します。

一般的には Requests や BeautifulSoup などの便利なパッケージを使うのが確実でなおかつ早いですが、今回は標準ライブラリだけを使った方法を説明します。 追加のパッケージを入れられない・入れたくない何らかの事情がある場合は今回のようなアプローチをとることになるかと思います。

早速実際のコードです。 html.parser.HTMLParser を使うと比較的かんたんに実装できます:

from html.parser import HTMLParser


def extract_title(html: str) -> str:
    """HTML から `title` タグの中身を抽出する"""
    return TagTextExtractor('title').find(html)


class TagTextExtractor(HTMLParser):
    """指定されたタグの中身を抽出する"""
    def __init__(self, tag: str):
        HTMLParser.__init__(self)
        self.tag = tag
        self._in_region = False
        self._text = ''

    def find(self, html) -> str:
        self._in_region = False
        self._text = ''

        super().feed(html)
        text = self._text

        self._in_region = False
        self._text = ''

        return text

    def handle_starttag(self, tag, attrs):
        if tag == self.tag:
            self._in_region = True

    def handle_endtag(self, tag):
        if tag == self.tag:
            self._in_region = False

    def handle_data(self, data):
        if self._in_region:
            self._text += data
extract_title(html)
# => "Example Domain" など

HTML が手元に無い場合は先に urllib.request で取得してこれば OK です:

import urllib.request


def fetch_html(url: str) -> str:
    """指定された URL の HTML を取得する"""
    with urllib.request.urlopen(url) as response:
        html = response.read().decode()
    return html

extract_title()fetch_html() は次のように組み合わせて使えます:

URLS = """https://example.com
https://wikipedia.org
https://apple.com
https://www.mozilla.org""".splitlines()

for url in URLS:
    html = fetch_html(url)
    title = extract_title(html)
    print(f'{url} {title}')
# =>
# https://example.com Example Domain
# https://wikipedia.org Wikipedia
# https://apple.com Apple
# https://www.mozilla.org Internet for people, not profit — Mozilla

参考