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 であるか確認し保存しています。