[Python] 正規表現でHTMLからテキストだけ抽出する

あまり使う事はないのですが、たまにあれどうするんだっけと思うので記事にしておきます。

とりあえず何となく自分で書いてみたのが以下のようなコードなんですが、タグも取りきれてないし色々微妙で、正規表現面倒くさくて辛いです。

def strip_tag(url):
    resp = requests.get(url)
    texts = re.findall(r'<[^>]+?>(.+?)<\/[^>]+?>', resp.content)
    return " ".join(texts)

それでなんか無いのと思って調べていると、DjangoとNLTKがHTMLからタグを取り除くユーティリティ関数をもっている事がわかりました。こちらがDjangoのユーティリティ関数。別に何でもないですが、あーテキスト取り出すんじゃなくてタグを消せば良いのかということですね。

# django/utils/html.py
def strip_tags(value):
    """Returns the given HTML with all tags stripped."""
    return re.sub(r'<[^>]*?>', '', force_unicode(value))

そしてNLTKのがこちら。空白を取る処理が何故3行必要なのか解りませんが、試行錯誤の後が見えてキチンとしてそうです。

# nltk/utils.py
def clean_html(html):
    """
    Remove HTML markup from the given string.

    :param html: the HTML string to be cleaned
    :type html: str
    :rtype: str
    """

    # First we remove inline JavaScript/CSS:
    cleaned = re.sub(r"(?is)<(script|style).*?>.*?(</\1>)", "", html.strip())
    # Then we remove html comments. This has to be done before removing regular
    # tags since comments can contain '>' characters.
    cleaned = re.sub(r"(?s)<!--(.*?)-->[\n]?", "", cleaned)
    # Next we can remove the remaining tags:
    cleaned = re.sub(r"(?s)<.*?>", " ", cleaned)
    # Finally, we deal with whitespace
    cleaned = re.sub(r"&nbsp;", " ", cleaned)
    cleaned = re.sub(r"  ", " ", cleaned)
    cleaned = re.sub(r"  ", " ", cleaned)
    return cleaned.strip()

ちゃんと理解してはいないのですが、とりあえずnltk.clean_html使っとけば良いんじゃね?というところです。ベターな方法があったら教えてください。

2012.8.16 追記
clean_htmlだけだとどうも改行が上手く処理できてないようなので、clean_html処理後に空白改行をさらに処理すると良い感じになりました。

resp = requests.get(url)
result = nltk.clean_html(resp.content)
print re.sub(r'\s+', ' ', result)

Leave a Reply

Your email address will not be published. Required fields are marked *