]> Panopticon :: 2007年11月 Archive

先日パシフィコ横浜で開催された、「Embededd Technology2007」に行ってきました。名前のとおり組込み技術関連の展示会です。多数のカンファレンスも同時に開催されます。Linux関連では次の講演を聴かせていただきました。

Emblixセッション 〜組込みLinuxにおける品質と信頼性〜

組込みリナックス開発 〜組込み機器開発におけるコミュニティーの価値〜

二つめの講演の中でKernel Newbiesというサイトが紹介されていました。というか講演者の方が主催している、Kernel開発者の新規参入を促進するためのプロジェクトだそうです。→日本語

Linuxカーネル2.6解読室大学でオペレーティングシステムの講義をとったときには組込みのことを知らなかったので、OSなんて誰が作るんだよ......と思っていましたが、来年以降作らされる可能性が高そうです。人生何が起こるかわかりません。大学の授業はしっかり聞きましょう(知人にはおまえが言うな、と言われそうですが)。

とりあえずこの本でKernelの世界に入門しようと思います。

ちょっとHTMLをパースする必要があったので、BeautifulSoupを使ってみました。参考にさせていただいたサイトはこちら。

あかさかランチにっき: BeautifulSoupによるスクレイピングの練習
あかさかランチにっき: 続・BeautifulSoupのスクレイピングの練習
Perl使いのPythonちゃん: BeautifulSoupでHTML解析
Perl使いのPythonちゃん: PythonでGoogleの表示順位を取得

特定タグの抽出

>>> from BeautifulSoup import BeautifulSoup
>>> import urllib2
>>> url = 'http://www.crummy.com/software/BeautifulSoup/documentation.html'
>>> html = urllib2.urlopen(url).read()
>>> soup = BeautifulSoup(html)
>>> soup('h1')
[<h1>Beautiful Soup Documentation</h1>]

特定のタグを抽出したいときには、上のリンク先の例にあるようにfindAll()を使うこともできる。抽出した結果には抽出タグ自身も含まれている。これを取り除くにはrenderContents()を使う。

>>> for s in soup('h1'):
...     s.renderContents()
...
'Beautiful Soup Documentation'

特定タグについてさらに絞りこんで抽出

それぞれのタグについて、条件をつけてさらに絞りこみたいときにはディクショナリが使える。アンカータグでクラスが "l" のものを絞りこみ、リンク先URLとアンカーテキストからなるタプルのリストを返すには次のように書く。 (Googleの検索結果表示画面で、外部リンク先へのアンカータグのクラスは "l"。したがって、Googleの検索結果をsoupに入れておけば、URLとタイトルの組からなるリストができる)

[(_a.get('href'), _a.renderContents()) for _a in soup('a', {'class' : 'l'})]

HTMLの本文のみを抽出

renderContents()は、子要素のタグも含めて文字列にする。アンカータグ内で b タグなんかが使われていると、「***<b>***</b>」のような文字列が返ってきてしまう。

BeautifulSoupによってHTMLが木構造に分解されたとき、それぞれの要素は自分の子要素(タグで囲まれた部分)をcontentsというリストとして持っているようだ。

>>> ex = BeautifulSoup('<a>This is <b>Example.</b></a>')
>>> for e in ex('a'):
...     print e.contents
...
[u'This is ', <b>Example.</b>]

ここで、contentsの長さが1のとき、つまりタグが入れ子を含まないとき、タグが囲む文字列を"string"という識別子で取得できる。タグが複数の子要素を持つとき、stringはNoneとなっている。

>>> ex = BeautifulSoup('<a>This is <b>Example.</b></a><a>text</a>')
>>> for e in ex('a'):
...     print e.string
...
None
text

これを使って、HTMLのタグを取り除く関数が書ける。

import re, urllib2
from BeautifulSoup import BeautifulSoup

def getPlainText(soup):
   text = ''.join([ s.string if s.string else getPlainText(s) for s in soup ])
   ctug = re.compile('<!--.*?-->',re.DOTALL)
   text = ctug.sub('', x)
   return text

url = 'http://www.crummy.com/software/BeautifulSoup/documentation.html'
html = urllib2.urlopen(url).read()
soup = BeautifulSoup(html)
print getPlainText(soup)

改行のみの行を取り除きたいときは、joinの前でfilter()を使うと簡単。ctugは「<!-- -->」のようなコメントを取り除くためのもの。re.DOTALLは正規表現の「. (ドット)」で改行も含めてマッチさせるのに必要。しかし、これだとscriptタグで囲まれた部分(javascriptとか)は取り除かれずに返ってきてしまう。document.write()をどう扱うべきか、、、。

''.join(filter(lambda(x): x != '\n' ,[ s.string if s.string else getPlainText(s) for s in soup ]))