!!!Beautiful Soup (HTML XML解析)
[Python]
*http://www.crummy.com/software/BeautifulSoup/
*Document
**http://www.crummy.com/software/BeautifulSoup/documentation.html
**http://tdoc.info/beautifulsoup/ 日本語
!!!インストール
!!PIPからインストール
# pip install BeautifulSoup
!!ダウンロードして解凍
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
*以下の様なパーサーがあります
**Python 標準ライブラリのパーサー
**lxml HTMLパーサー
**lxml XMLパーサー
**html5lib
!!!Import
from BeautifulSoup import BeautifulSoup # For processing HTML
from BeautifulSoup import BeautifulStoneSoup # For processing XML
import BeautifulSoup # To get everything
""No module named BeautifulSoup エラーとなる場合
from bs4 import BeautifulSoup # To get everything
!!!解析
*文字列およびファイルハンドルによる文書解析
soup = BeautifulSoup(open("index.html"))
soup = BeautifulSoup("data")
*URLを指定して解析
import urllib2
from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup(urllib2.urlopen('http://xxxxx.com'))
!!!オブジェクト
*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('
')
css_soup.p['class']
# ["body", "strikeout"]
*XMLでは、複数値として扱わない
xml_soup = BeautifulSoup('', 'xml')
xml_soup.p['class']
# u'body strikeout'
!!NavigableString
*文字列は、Beautiful Soup で、NavigableStringを利用する
*Python のUnicode文字列とほぼ同じ
*treeをナビゲートしたり検索したりする機能がサポートされている
tag.string
# u'Extremely bold'
type(tag.string)
#
*unicode() で、Unicode 文字列に変換できる
unicode_string = unicode(tag.string)
unicode_string
# u'Extremely bold'
type(unicode_string)
#
!!BeautifulSoup
*文書全体を表す
*Tagオブジェクトとして文書を扱う
*.name は、特別に、"[document]"となる
!!!コメントと特殊な文字列
!!コメント
*Commentオブジェクトは、NavigableStringの特殊型
markup = ""
soup = BeautifulSoup(markup)
comment = soup.b.string
type(comment)
#
!!!treeのナビゲート
!!下がる
!タグ名を使ったナビゲート
soup.head
soup.title
soup.find_all('a')
!.contents と .children
head_tag.contents
[The Dormouse's story]
for child in title_tag.children:
print(child)
!.descendants
*.contents および .children は、タグの直接の子供しか考慮していない
*ネストした子供を順次取り出す
for child in head_tag.descendants:
print(child)
# The Dormouse's story
# 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
# The Dormouse's story
title_tag.parent
# The Dormouse's story
!.paretns
link = soup.a
link
# Elsie
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
# text2
sibling_soup.c.previous_sibling
# text1
!.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)
# [The Dormouse's story]
soup.find('title')
# The Dormouse's story
::CSSクラスで検索
soup.find("b", { "class" : "lime" })
# Lime
!find_parents() と find_parent()
!find_next_siblings() と find_next_sibling()
*あるオブジェクトのnextSiblingメンバー変数を辿り、指定したTagあるいはNavigableTextを集めてきます。
paraText = soup.find(text='This is paragraph ')
paraText.findNextSiblings('b')
# [one]
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("Foo")
soup.a.append("Bar")
!!BeautifulSoup.new_string() と .new_tag()
!new_string()
soup = BeautifulSoup("")
tag = soup.b
tag.append("Hello")
new_string = soup.new_string(" there")
tag.append(new_string)
tag
# Hello there.
tag.contents
# [u'Hello', u' there']
!new_tag()
soup = BeautifulSoup("")
original_tag = soup.b
new_tag = soup.new_tag("a", href="http://www.example.com")
original_tag.append(new_tag)
original_tag
#
new_tag.string = "Link text."
original_tag
# Link text.
!!insert()
markup = 'I linked to example.com'
soup = BeautifulSoup(markup)
tag = soup.a
tag.insert(1, "but did not endorse ")
tag
# I linked to but did not endorse example.com
tag.contents
# [u'I linked to ', u'but did not endorse', example.com]
!!insert_before() と insert_after()
!!clear()
markup = 'I linked to example.com'
soup = BeautifulSoup(markup)
tag = soup.a
tag.clear()
tag
#
!!extract()
*タグもしくは文字列をツリーから削除
markup = 'I linked to example.com'
soup = BeautifulSoup(markup)
a_tag = soup.a
i_tag = soup.i.extract()
a_tag
# I linked to
i_tag
# example.com
!!decompose()
*タグをツリーから取り除く
markup = 'I linked to example.com'
soup = BeautifulSoup(markup)
a_tag = soup.a
soup.i.decompose()
a_tag
# I linked to
!!replace_with()
*タグおよび文字列をツリーから取り除き、別のタグおよび文字列に置き換える
!!wrap()
*要素をタグでラップする
soup = BeautifulSoup("I wish I was bold.
")
soup.p.string.wrap(soup.new_tag("b"))
# I wish I was bold.
!!unwrap()
*タグをはがす
markup = 'I linked to example.com'
soup = BeautifulSoup(markup)
a_tag = soup.a
a_tag.i.unwrap()
a_tag
# I linked to example.com
!!!出力
!!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']