Python Tips

歌詞をごそっとダウンロードするためにHTMLParserを使ってみました。クラス内の関数が受動的に呼ばれるのはちょっと予想と違って戸惑いましたが、目的は達成できたのでよしとしましょう。HTMLを簡単にいじれるとなんか嬉しいですね。


下の例はbaseURLのページにあるリンクをすべて抽出する例です。

# -*- encoding: sjis -*-

import os,sys
import urllib
from HTMLParser import HTMLParser

baseURL = 'http://www.yahoo.co.jp/'

class MyHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.URL = ""
        self.lastURL = ""
    
    #タグ以外の文字列が来たときに呼び出される
    def handle_data(self,data):
        if data and self.lastURL != self.URL:
            self.lastURL = self.URL
            print "DATA:" + data
            print "URL:" + self.URL
    
    #なんらかのタグが見つかったら呼び出される
    #tagにタグ名、attrsに属性とその値のシーケンス
    def handle_starttag(self,tag,attrs):
        if tag == 'a':
            for e in attrs:
                if e[0] == 'href':
                    self.URL = e[1]
    
    #終了タグが見つかったら呼び出される
    def handle_endtag(self,tag):
        pass

if __name__ == "__main__":
    urlfile = urllib.urlopen(baseURL)
    charset = urlfile.headers.getparam('charset')
    data = urlfile.read()
    urlfile.close()
    
    mp = MyHTMLParser()
    mp.feed(unicode(data,charset))

流れとしては

  1. テキストデータを全て読み込み
  2. HTMLParserを継承したクラスのインスタンスを作成
  3. feedでテキストデータを与える
  4. クラス内のhandle〜系の関数が随時呼ばれる

解析した後に任意のタグにアクセスするといったことはできません(と思います)。テキスト内に<a href='link.html'>リンク</a>というテキストが出てくると以下のようにクラス内の3つの関数が順に呼ばれます。関数名の下にあるのは引数にセットされた値です。

handle_starttag(self,tag,attrs)
  tag='a'
  attrs=[(u'href',u'link.html')]

handle_data(self,data)
  data=u'リンク'

handle_endtag(self,tag)
  tag='a'


リンクテキストを得るためにself.URLやself.lastURLなんてのを使いましたが、他にもっとスマートな方法があるのかなぁ。