PythonでHTMLをパースする:HTMLParser

今回は Python の標準モジュールである urllib2 と HTMLParser クラスを使って Web 上のリソースにアクセスし、取得した HTML を解析する方法について説明します。

Web上からHTMLを取得

Python で Web 上にあるリソースにアクセスするためには urllib2 の urlopen() を使用します。以下のサンプルプログラムでは、指定した URLから HTML を取得し、その取得した HTML をそのまま表示しています。

# -*- coding: utf-8 -*- 

import urllib2

if __name__ == "__main__":

    url = "http://www.python.org"          # Pythonの公式ページのURL

    response = urllib2.urlopen(url)        # URLを指定してHTMLファイルを開く
    print unicode(response.read(),"utf-8") # 取得したHTMLファイルの内容を表示する

    response.close()

HTML タグの情報を取得・解析する

取得した HTML を解析するためには HTMLParser を継承して使用します。今回は主に以下の3つのメソッドを利用します。

1.  開始タグを扱うためのメソッド

handle_starttag(self, 開始タグ名, 属性名と属性値のタプルのリスト)

2. 要素内容を扱うためのメソッド

handle_data(self, 要素内容)

3. 終了タグを扱うためのメソッド

handle_endtag(self, 終了タグ)

取得したHTML を HTMLParser の feed() で読み込ませると、各要素に対して上の3つのメソッドが順番に実行されていきます。

ページのタイトルを取得

次のサンプルプログラムは、リンク先のタイトルを取得し表示します。

# -*- coding: utf-8 -*- 

import urllib2
from HTMLParser import HTMLParser

class TestParser(HTMLParser): # HTMLParserを継承したクラスを定義する

    def __init__(self):
        HTMLParser.__init__(self)
        self.flag = False # タイトルタグの場合のフラグ

    def handle_starttag(self, tag, attrs): # 開始タグを扱うためのメソッド
        if tag == "title":
            self.flag = True

    def handle_data(self, data): # 要素内用を扱うためのメソッド
        if self.flag:
            print data
            self.flag = False

if __name__ == "__main__":

    url = "http://www.python.org/"

    response = urllib2.urlopen(url)
    
    parser = TestParser()        # パーサオブジェクトの生成
    parser.feed(response.read()) # パーサにHTMLを入力する

    parser.close()
    response.close()

実行結果

Welcome to Python.org

上の例ではまず、urlopen() でWeb上のリソースを取得し feed() で取得した HTML をパーサで読み込みます。

次に、handle_startag() が実行されタグ名が title だった場合、フラグを立てます。

そして、フラグが True の場合 handle_data() で要素内容を、すなわち <title> </title> のタグで囲まれている部分を表示しています。

ページ中のリンクを抽出する

以下は、ページ中の外部リンクをすべて抽出するプログラムです。

# -*- coding: utf-8 -*- 

import urllib2
import re
from HTMLParser import HTMLParser

class TestParser(HTMLParser):

    def __init__(self):
        HTMLParser.__init__(self)
        self.url = ""

    def handle_starttag(self, tag, attrs):
        if tag == "a": # 開始タグがaであるかどうか判定
            attrs = dict(attrs) # タプルを辞書に変換する
            if 'href' in attrs: # キー値(属性名)がhrefであるか判定
                self.url = attrs['href']

    def handle_endtag(self, tag): # 開始・終了タグに囲まれた中身の処理
        if self.url and re.match('^http', self.url): # 先頭がhttpであるか判定
            print self.url
            self.url = ""
                 
if __name__ == "__main__":

    url = "http://www.python.org/"

    response = urllib2.urlopen(url)
    
    parser = TestParser()
    parser.feed(response.read())

    parser.close()

先ほどの例と同様にまず、まず feed() で HTML を読み込みます。

次に、handle_startag() を用いて a タグの href 属性の値を取得して表示します。 属性のリスト attrs は (name, value) のタプルのリストで構成されており、タプルのままだと扱いづらいので、辞書に変換して使用しています。そして、その辞書のキー値が href のものだけ抽出し self.url に保存しています。

最後に、handle_endtag() が実行されます。今回は外部リンクを抽出するので、正規表現を利用して先頭の文字列が http であるか確認し保存しています。


イベント