Beautiful Soup
ナビゲーションに移動
検索に移動
目次
- 1 Beautiful Soup (HTML XML解析)
- 2 インストール
- 3 Import
- 4 解析
- 5 オブジェクト
- 6 コメントと特殊な文字列
- 7 treeのナビゲート
- 7.1 下がる
- 7.2 上がる
- 7.3 横に移動
- 7.4 後ろ向き前向き
- 7.5 ツリーの検索
- 7.6 関数
- 7.7 CSS selectors
- 8 ツリーの操作
- 9 出力
- 10 例
Beautiful Soup (HTML XML解析)
Python |
Beautiful Soup 4
- https://www.crummy.com/software/BeautifulSoup/bs4/doc/
- http://kondou.com/BS4/ Beautiful Soup4 日本語
- 2012年5月にBS3の開発が終了し、現在ではBS4の利用が推奨されています
- BS3はPython3に対応していません
- ただし、BS3のスクリプトのほとんどはimport文を変えるだけでBS4でも動きます
インストール
PIPからインストール
- # pip install BeautifulSoup
- Python3
- $ pip install beautifulsoup4
ダウンロードして解凍
- piroto@eisai /cygdrive/c/Users/piroto/Downloads
- $ tar -xvf beautifulsoup4-4.1.2.tar.gz
インストール
- $ cd beautifulsoup4-4.1.2
- $ python setup.py install
パーサーのインストール
- Beautiful Soup は Pythonの標準ライブラリに含まれているHTML パーサーをサポートしています。
- その他にもサードパーティー製のパーサーもサポートしています。
- その一つが、lxmlパーサーで、以下の様にインストールできます。
- $ apt-get install python-lxml
- $ easy_install lxml
- $ pip install lxml
Import
<blockquote>No module named BeautifulSoup エラーとなる場合</blockquote>
- from bs4 import BeautifulSoup # To get everything
解析
文字列およびファイルハンドルによる文書解析
- soup = BeautifulSoup(open("index.html"))
- soup = BeautifulSoup("<html>data</html>")
URLを指定して解析
- import urllib2
- from BeautifulSoup import BeautifulSoup
- soup = BeautifulSoup(urllib2.urlopen('http://xxxxx.com'))
- Python3
- import urllib.request as request
- from bs4 import BeautifulSoup
- soup = BeautifulSoup(urllib.request.urlopen('http://xxxxx.com'))
エンコードの変換
- 文字化けする場合(例えばSHIFT-JIS)の対処
- response = urllib.request.urlopen(url)
- html = response.read().decode(response.headers.get_content_charset(), errors='ignore')
- parsed_html = BeautifulSoup(html, 'html.parser')
オブジェクト
- Beautiful Soup は複雑なHTML文書を、Python オブジェクトのツリーに変換する
- 以下の4種類のオブジェクトを扱うだけでよい
Tag
- XML、HTMLのタグに一致する
- tag = soup.b
Name
- すべてのタグは、.name でアクセスできる名前を持つ
- タグの名称を変更すると、内容も変更される
- tag.name
Attributes
- タグはいくつかの属性をもつ。
- 以下の様にアクセス可能
- tag['class']
- .attrs で直接アクセスできる
- 追加、削除、変更ができる
- tag['class'] = 'verybold'
- tag['id'] = 1
- del tag['class']
- del tag['id']
複数値属性
- HTML4では、いくつかの属性で、複数の値を持つことができる
- もっとも知られているのが、class
- Beautiful Soupでは、リストとして扱う
- css_soup = BeautifulSoup('<p class="body strikeout"></p>')
- css_soup.p['class']
- # ["body", "strikeout"]
- XMLでは、複数値として扱わない
- xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
- xml_soup.p['class']
- # u'body strikeout'
- 文字列は、Beautiful Soup で、NavigableStringを利用する
- Python のUnicode文字列とほぼ同じ
- treeをナビゲートしたり検索したりする機能がサポートされている
- tag.string
- # u'Extremely bold'
- type(tag.string)
- # <class 'bs4.element.NavigableString'>
- unicode() で、Unicode 文字列に変換できる
- unicode_string = unicode(tag.string)
- unicode_string
- # u'Extremely bold'
- type(unicode_string)
- # <type 'unicode'>
BeautifulSoup
- 文書全体を表す
- Tagオブジェクトとして文書を扱う
- .name は、特別に、"[document]"となる
コメントと特殊な文字列
コメント
- Commentオブジェクトは、NavigableStringの特殊型
- markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
- soup = BeautifulSoup(markup)
- comment = soup.b.string
- type(comment)
- # <class 'bs4.element.Comment'>
treeのナビゲート
下がる
タグ名を使ったナビゲート
- soup.head
- soup.title
- soup.find_all('a')
.contents と .children
- head_tag.contents
- [<title>The Dormouse's story</title>]
- for child in title_tag.children:
- print(child)
.descendants
- .contents および .children は、タグの直接の子供しか考慮していない
- ネストした子供を順次取り出す
- for child in head_tag.descendants:
- print(child)
- # <title>The Dormouse's story</title>
- # The Dormouse's story
.string
- title_tag.string
- # u'The Dormouse's story'
.strings と stripped_strings
strings
- for string in soup.strings:
- print(repr(string))
- # u"The Dormouse's story"
- # u'\n\n'
- # u"The Dormouse's story"
- # u'\n\n'
stripped_strings
- for string in soup.stripped_strings:
- print(repr(string))
- # u"The Dormouse's story"
- # u"The Dormouse's story"
上がる
.parent
- title_tag = soup.title
- title_tag
- # <title>The Dormouse's story</title>
- title_tag.parent
- # <head><title>The Dormouse's story</title></head>
.paretns
- link = soup.a
- link
- # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
- for parent in link.parents:
- if parent is None:
- print(parent)
- else:
- print(parent.name)
- # p
- # body
- # html
- # [document]
- # None
横に移動
.next_sibling と .prebious_sibling
- sibling_soup.b.next_sibling
- # <c>text2</c>
- sibling_soup.c.previous_sibling
- # <b>text1</b>
.next_siblings と .prebious_siblings
- for sibling in soup.a.next_siblings:
- print(repr(sibling))
- for sibling in soup.find(id="link3").previous_siblings:
- print(repr(sibling))
後ろ向き前向き
.next_element と .previous_element
.next_elements と .previous_elements
ツリーの検索
string
- soup.find_all('b')
正規表現
- import re
- for tag in soup.find_all(re.compile("^b")):
- print(tag.name)
- # body
- # b
リスト
- soup.find_all(["a", "b"])
関数
findAll()
タグ名を渡す
- soup.findAll('b')
正規表現を使う
- import re
- tagsStartingWithB = soup.findAll(re.compile('^b'))
リストまたは辞書を渡す(結果は同一だが後者が高速)
- soup.findAll(['title', 'p'])
- oup.findAll({'title' : True, 'p' : True})
Trueを渡すとすべてのタグを返す
- allTags = soup.findAll(True)
一つの引数をもち真偽値を返す呼び出し可能オブジェクトを渡すとフィルタできる
- soup.findAll(lambda tag: len(tag.attrs) == 2)
find()
- 結果が一つしかないと分かっている場合など、最後までスキャンする必要はない利用
- find(name, attrs, recursive, string, **kwargs)
- 以下はほぼ同等
- soup.find_all('title', limit=1)
- # [<title>The Dormouse's story</title>]
- soup.find('title')
- # <title>The Dormouse's story</title>
CSSクラスで検索
- soup.find("b", { "class" : "lime" })
- # <b class="lime">Lime</b>
find_parents() と find_parent()
find_next_siblings() と find_next_sibling()
- あるオブジェクトのnextSiblingメンバー変数を辿り、指定したTagあるいはNavigableTextを集めてきます。
- paraText = soup.find(text='This is paragraph ')
- paraText.findNextSiblings('b')
- # [<b>one</b>]
- paraText.findNextSibling(text = lambda(text): len(text) == 1)
- # u'.'
find_previous_siblings() と find_previous_sibling()
find_all_next() と find_next()
find_all_previous() と find_previous()
CSS selectors
タグ
- soup.select("title")
配下のタグ
- soup.select("body a")
直下のタグ
- soup.select("head > title")
CSS class
- soup.select(".sister")
ID
- soup.select("#link1")
- soup.select("a#link2")
属性
- soup.select('a[href]')
属性値
- soup.select('a[href="http://example.com/elsie"]')
ツリーの操作
タグ名と属性の変更
- tag.name = "blockquote"
- tag['class'] = 'verybold'
- tag['id'] = 1
- del tag['class']
- del tag['id']
.stringの変更
- tag.string = "New link text."
append()
- soup = BeautifulSoup("<a>Foo</a>")
- soup.a.append("Bar")
BeautifulSoup.new_string() と .new_tag()
new_string()
- soup = BeautifulSoup("<b></b>")
- tag = soup.b
- tag.append("Hello")
- new_string = soup.new_string(" there")
- tag.append(new_string)
- tag
- # <b>Hello there.</b>
- tag.contents
- # [u'Hello', u' there']
new_tag()
- soup = BeautifulSoup("<b></b>")
- original_tag = soup.b
- new_tag = soup.new_tag("a", href="http://www.example.com")
- original_tag.append(new_tag)
- original_tag
- # <b><a href="http://www.example.com"></a></b>
- new_tag.string = "Link text."
- original_tag
- # <b><a href="http://www.example.com">Link text.</a></b>
insert()
- markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
- soup = BeautifulSoup(markup)
- tag = soup.a
- tag.insert(1, "but did not endorse ")
- tag
- # <a href="http://example.com/">I linked to but did not endorse <i>example.com</i></a>
- tag.contents
- # [u'I linked to ', u'but did not endorse', <i>example.com</i>]
insert_before() と insert_after()
clear()
- markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
- soup = BeautifulSoup(markup)
- tag = soup.a
- tag.clear()
- tag
- # <a href="http://example.com/"></a>
extract()
- タグもしくは文字列をツリーから削除
- markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
- soup = BeautifulSoup(markup)
- a_tag = soup.a
- i_tag = soup.i.extract()
- a_tag
- # <a href="http://example.com/">I linked to</a>
- i_tag
- # <i>example.com</i>
decompose()
- タグをツリーから取り除く
- markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
- soup = BeautifulSoup(markup)
- a_tag = soup.a
- soup.i.decompose()
- a_tag
- # <a href="http://example.com/">I linked to</a>
replace_with()
- タグおよび文字列をツリーから取り除き、別のタグおよび文字列に置き換える
wrap()
- 要素をタグでラップする
- soup = BeautifulSoup("<p>I wish I was bold.</p>")
- soup.p.string.wrap(soup.new_tag("b"))
- # <b>I wish I was bold.</b>
unwrap()
- タグをはがす
- markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
- soup = BeautifulSoup(markup)
- a_tag = soup.a
- a_tag.i.unwrap()
- a_tag
- # <a href="http://example.com/">I linked to example.com</a>
出力
Pretty-printing
prettify()
Non-pretty printing
unicode() もしくは str()を使う
XML
- from BeautifulSoup import BeautifulStoneSoup
- def get_translation(itemid):
- ItemId から、訳語を取得する
- url = r'http://btonic.est.co.jp/NetDic/NetDicV09.asmx/GetDicItemLite?Dic=EJdict&Item={0}&Loc=&Prof=XHTML'
- url = url.format(itemid)
- f = urllib2.urlopen(url)
- soup = BeautifulStoneSoup(f.read())
- #print soup.prettify()
- try:
- ret = soup.body('div')[1].text
- except:
- ret =
- return ret
例
ページを解析し指定タグのテキストのみ取り出す
- soup = BeautifulSoup(urllib2.urlopen(url))
- for p in soup('p'):
- print p.text
タグの文字列を取得する
- soup = BeautifulSoup(urllib2.urlopen(url))
- .join(soup.findAll(text=True))
必要なタグのみ解析する
- tags = SoupStrainer(['title','img','h1','h2','h3','h4','h5','h6','p','meta','link'])
- soup = BeautifulSoup(urllib2.urlopen(url), parseOnlyThese=tags)
タグに囲まれた文字列値がある場合出力
- soup = BeautifulSoup(urllib2.urlopen(url))
- if hasattr(soup, "title") and hasattr(soup.title, "string"):
- print soup.title.string
Image タグから リンクを抜き出す
- soup = BeautifulSoup(urllib2.urlopen(url))
- for tag in soup.findAll():
- if tag.name == 'img':
- print tag['src']
© 2006 矢木浩人