何度かBeautifulSoupについては書いているのですが、未だに使い方が覚えられずにイライラします。仕方が無いのでまとめて置く事にしました。BeautifulSoupはHTMLから情報を取得するだけ無く、HTMLの編集もできますが、ここではスクレイピング用途のみに絞っています。
使用するのは以下のHTMLです。
<html> <body> <div id="search engine"> <a id="googls" href="http://google.com">one</a> <a id="yahoo" href="http://yahoo.com">two</a> <a id="bing" href="http://bing.com">three</a> </div> <div id="blog"> <a id="wordpress" href="http://ja.wordpress.org/">one</a> <a id="movabletype" href="http://www.sixapart.jp/movabletype/">two</a> <a id="nucleus" href="http://japan.nucleuscms.org/">three</a> <div> <ul> <li>one</li> <li>two</li> <li>three</li> </ul> </div> </div> </body> </html>
このHTMLを使って色々と情報を取得したのが以下です。覚えるべきはfindAllだけです。注意する必要があるのは、textを指定した場合にタグオブジェクトが取れずに、テキストオブジェクトが取れるので、一旦parentで親のタグ取りましょうという事と、正規表現で条件指定する場合は、re.compileで正規表現オブジェクトを渡すという事位ですか。
#!/usr/bin/python # -*- coding: utf-8 -*- import re import urllib from BeautifulSoup import BeautifulSoup html = ''' 上記HTML。ここに書くと表示が乱れるので分けました。 ''' def main(): soup = BeautifulSoup(html) # 基本はfindかfindAllでタグ名指定で要素を取得 links = soup.findAll('a') for link in links: print link.name # タグ名 print link.string # タグの中のテキスト print dict(link.attrs)['href'] # attrsはタプルのリストなので辞書経由でアクセスが便利 blogdiv = soup.find('div', attrs={'id':'blog'}) # タグ名に加えてattrsで属性条件を入れる bloglinks = blogdiv.findAll('a') # 要素に対してもfind/findAll可能。子要素からの検索になる for link in bloglinks: print link # 要素をそのまま出力すると、その部分のHTMLになる # タグ内のテキストで検索 firstlinks = soup.findAll(text="one") for link in firstlinks: print link.parent # テキストで検索した場合はテキストオブジェクトが取れる。タグにアクセスしたい場合はparent経由 # findAllのタグ条件はリストで複数指定可能 li_or_a = soup.findAll(['a', 'li']) for tag in li_or_a: print tag # テキスト検索も複数指定可能 one_or_two = soup.findAll(text=['one', 'two']) for tag in one_or_two: print tag # recursiveを無効にすれば、自身の子要素からのみ検索できる only_children = soup.find('body').findAll('div', recursive=False) for div in only_children: print div # 各属性の条件指定には正規表現オブジェクトを指定できる dot_com_links = soup.findAll('a', attrs={'href':re.compile(r'.*?\.com')}) for link in dot_com_links: print dict(link.attrs)['href'] # タグ名とテキスト内容を同時に指定しても、タグは取れない firstlinks = soup.findAll('a', text="one") for link in firstlinks: print link.parent # やっぱりparentを経由する必要がある if __name__ == '__main__': main()
書いてみると何故こんな事が覚えられないのか謎ですが、とにかくこれでBeautifulSoupは使えるようになりましたね。あと以前にも書きましたが、現状のBeautifulSoupだと解析できないHTMLが存在します。その場合は僕はこうしてますが、もっと上手い方法あったら教えて下さい。
一応これでスクレイピングは出来る気がしますが、Web::Scraperと違い、必要な情報を構造化して取得する事ができないのが面倒ですね。ラッパー書きたいなぁと思いながら中々重い腰が上げられません。
関連する記事
タグ: beautifulsoup, python, scraping

