| ページ一覧 | ブログ | twitter |  書式 | 書式(表) |

MyMemoWiki

Beautiful Soup

提供: MyMemoWiki
ナビゲーションに移動 検索に移動

目次

Beautiful Soup (HTML XML解析)

Python |

Beautiful Soup 4

インストール

PIPからインストール

  1. # pip install BeautifulSoup
  • Python3
  1. $ pip install beautifulsoup4

ダウンロードして解凍

  1. piroto@eisai /cygdrive/c/Users/piroto/Downloads
  2. $ tar -xvf beautifulsoup4-4.1.2.tar.gz

インストール

  1. $ cd beautifulsoup4-4.1.2
  2. $ python setup.py install

パーサーのインストール

  • Beautiful Soup は Pythonの標準ライブラリに含まれているHTML パーサーをサポートしています。
  • その他にもサードパーティー製のパーサーもサポートしています。
    • その一つが、lxmlパーサーで、以下の様にインストールできます。
  1. $ apt-get install python-lxml
  2. $ easy_install lxml
  3. $ pip install lxml
  • 以下の様なパーサーがあります
    • Python 標準ライブラリのパーサー
    • lxml HTMLパーサー
    • lxml XMLパーサー
    • html5lib

Import

  1. from BeautifulSoup import BeautifulSoup # For processing HTML
  2. from BeautifulSoup import BeautifulStoneSoup # For processing XML
  3. import BeautifulSoup # To get everything

<blockquote>No module named BeautifulSoup エラーとなる場合</blockquote>

  1. from bs4 import BeautifulSoup # To get everything

解析

文字列およびファイルハンドルによる文書解析

  1. soup = BeautifulSoup(open("index.html"))
  2. soup = BeautifulSoup("<html>data</html>")

URLを指定して解析

  1. import urllib2
  2. from BeautifulSoup import BeautifulSoup
  3. soup = BeautifulSoup(urllib2.urlopen('http://xxxxx.com'))
  • Python3
  1. import urllib.request as request
  2. from bs4 import BeautifulSoup
  3. soup = BeautifulSoup(urllib.request.urlopen('http://xxxxx.com'))

エンコードの変換

  • 文字化けする場合(例えばSHIFT-JIS)の対処
  1. response = urllib.request.urlopen(url)
  2. html = response.read().decode(response.headers.get_content_charset(), errors='ignore')
  3. parsed_html = BeautifulSoup(html, 'html.parser')

オブジェクト

  • Beautiful Soup は複雑なHTML文書を、Python オブジェクトのツリーに変換する
  • 以下の4種類のオブジェクトを扱うだけでよい

Tag

  • XML、HTMLのタグに一致する
  1. tag = soup.b

Name

  • すべてのタグは、.name でアクセスできる名前を持つ
  • タグの名称を変更すると、内容も変更される
  1. tag.name

Attributes

  • タグはいくつかの属性をもつ。
  • 以下の様にアクセス可能
  1. tag['class']
  • .attrs で直接アクセスできる
  • 追加、削除、変更ができる
  1. tag['class'] = 'verybold'
  2. tag['id'] = 1
  3. del tag['class']
  4. del tag['id']

複数値属性

  • HTML4では、いくつかの属性で、複数の値を持つことができる
  • もっとも知られているのが、class
  • Beautiful Soupでは、リストとして扱う
  1. css_soup = BeautifulSoup('<p class="body strikeout"></p>')
  2. css_soup.p['class']
  3. # ["body", "strikeout"]
  • XMLでは、複数値として扱わない
  1. xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
  2. xml_soup.p['class']
  3. # u'body strikeout'

NavigableString

  • 文字列は、Beautiful Soup で、NavigableStringを利用する
  • Python のUnicode文字列とほぼ同じ
  • treeをナビゲートしたり検索したりする機能がサポートされている
  1. tag.string
  2. # u'Extremely bold'
  3. type(tag.string)
  4. # <class 'bs4.element.NavigableString'>
  • unicode() で、Unicode 文字列に変換できる
  1. unicode_string = unicode(tag.string)
  2. unicode_string
  3. # u'Extremely bold'
  4. type(unicode_string)
  5. # <type 'unicode'>

BeautifulSoup

  • 文書全体を表す
  • Tagオブジェクトとして文書を扱う
  • .name は、特別に、"[document]"となる

コメントと特殊な文字列

コメント

  • Commentオブジェクトは、NavigableStringの特殊型
  1. markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
  2. soup = BeautifulSoup(markup)
  3. comment = soup.b.string
  4. type(comment)
  5. # <class 'bs4.element.Comment'>

treeのナビゲート

下がる

タグ名を使ったナビゲート

  1. soup.head
  2. soup.title
  3. soup.find_all('a')

.contents と .children

  1. head_tag.contents
  2. [<title>The Dormouse's story</title>]
  1. for child in title_tag.children:
  2. print(child)

.descendants

  • .contents および .children は、タグの直接の子供しか考慮していない
  • ネストした子供を順次取り出す
  1. for child in head_tag.descendants:
  2. print(child)
  3. # <title>The Dormouse's story</title>
  4. # The Dormouse's story

.string

  1. title_tag.string
  2. # u'The Dormouse's story'

.strings と stripped_strings

strings
  1. for string in soup.strings:
  2. print(repr(string))
  3. # u"The Dormouse's story"
  4. # u'\n\n'
  5. # u"The Dormouse's story"
  6. # u'\n\n'
stripped_strings
  1. for string in soup.stripped_strings:
  2. print(repr(string))
  3. # u"The Dormouse's story"
  4. # u"The Dormouse's story"

上がる

.parent

  1. title_tag = soup.title
  2. title_tag
  3. # <title>The Dormouse's story</title>
  4. title_tag.parent
  5. # <head><title>The Dormouse's story</title></head>

.paretns

  1. link = soup.a
  2. link
  3. # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
  4. for parent in link.parents:
  5. if parent is None:
  6. print(parent)
  7. else:
  8. print(parent.name)
  9. # p
  10. # body
  11. # html
  12. # [document]
  13. # None

横に移動

.next_sibling と .prebious_sibling

  1. sibling_soup.b.next_sibling
  2. # <c>text2</c>
  3.  
  4. sibling_soup.c.previous_sibling
  5. # <b>text1</b>

.next_siblings と .prebious_siblings

  1. for sibling in soup.a.next_siblings:
  2. print(repr(sibling))
  3. for sibling in soup.find(id="link3").previous_siblings:
  4. print(repr(sibling))

後ろ向き前向き

.next_element と .previous_element

.next_elements と .previous_elements

ツリーの検索

string

  1. soup.find_all('b')

正規表現

  1. import re
  2. for tag in soup.find_all(re.compile("^b")):
  3. print(tag.name)
  4. # body
  5. # b

リスト

  1. soup.find_all(["a", "b"])

関数

findAll()

タグ名を渡す
  1. soup.findAll('b')
正規表現を使う
  1. import re
  2. tagsStartingWithB = soup.findAll(re.compile('^b'))
リストまたは辞書を渡す(結果は同一だが後者が高速)
  1. soup.findAll(['title', 'p'])
  2. oup.findAll({'title' : True, 'p' : True})
Trueを渡すとすべてのタグを返す
  1. allTags = soup.findAll(True)
一つの引数をもち真偽値を返す呼び出し可能オブジェクトを渡すとフィルタできる
  1. soup.findAll(lambda tag: len(tag.attrs) == 2)

find()

  • 結果が一つしかないと分かっている場合など、最後までスキャンする必要はない利用
  1. find(name, attrs, recursive, string, **kwargs)
  • 以下はほぼ同等
  1. soup.find_all('title', limit=1)
  2. # [<title>The Dormouse's story</title>]
  3.  
  4. soup.find('title')
  5. # <title>The Dormouse's story</title>
CSSクラスで検索
  1. soup.find("b", { "class" : "lime" })
  2. # <b class="lime">Lime</b>

find_parents() と find_parent()

find_next_siblings() と find_next_sibling()

  • あるオブジェクトのnextSiblingメンバー変数を辿り、指定したTagあるいはNavigableTextを集めてきます。
  1. paraText = soup.find(text='This is paragraph ')
  2. paraText.findNextSiblings('b')
  3. # [<b>one</b>]
  4.  
  5. paraText.findNextSibling(text = lambda(text): len(text) == 1)
  6. # u'.'

find_previous_siblings() と find_previous_sibling()

find_all_next() と find_next()

find_all_previous() と find_previous()

CSS selectors

タグ

  1. soup.select("title")

配下のタグ

  1. soup.select("body a")

直下のタグ

  1. soup.select("head > title")

CSS class

  1. soup.select(".sister")

ID

  1. soup.select("#link1")
  2. soup.select("a#link2")

属性

  1. soup.select('a[href]')

属性値

  1. soup.select('a[href="http://example.com/elsie"]')

ツリーの操作

タグ名と属性の変更

  1. tag.name = "blockquote"
  2. tag['class'] = 'verybold'
  3. tag['id'] = 1
  4. del tag['class']
  5. del tag['id']

.stringの変更

  1. tag.string = "New link text."

append()

  1. soup = BeautifulSoup("<a>Foo</a>")
  2. soup.a.append("Bar")

BeautifulSoup.new_string() と .new_tag()

new_string()

  1. soup = BeautifulSoup("<b></b>")
  2. tag = soup.b
  3. tag.append("Hello")
  4. new_string = soup.new_string(" there")
  5. tag.append(new_string)
  6. tag
  7. # <b>Hello there.</b>
  8. tag.contents
  9. # [u'Hello', u' there']

new_tag()

  1. soup = BeautifulSoup("<b></b>")
  2. original_tag = soup.b
  3.  
  4. new_tag = soup.new_tag("a", href="http://www.example.com")
  5. original_tag.append(new_tag)
  6. original_tag
  7. # <b><a href="http://www.example.com"></a></b>
  1. new_tag.string = "Link text."
  2. original_tag
  3. # <b><a href="http://www.example.com">Link text.</a></b>

insert()

  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. tag = soup.a
  4.  
  5. tag.insert(1, "but did not endorse ")
  6. tag
  7. # <a href="http://example.com/">I linked to but did not endorse <i>example.com</i></a>
  8. tag.contents
  9. # [u'I linked to ', u'but did not endorse', <i>example.com</i>]

insert_before() と insert_after()

clear()

  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. tag = soup.a
  4.  
  5. tag.clear()
  6. tag
  7. # <a href="http://example.com/"></a>

extract()

  • タグもしくは文字列をツリーから削除
  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. a_tag = soup.a
  4.  
  5. i_tag = soup.i.extract()
  6.  
  7. a_tag
  8. # <a href="http://example.com/">I linked to</a>
  9.  
  10. i_tag
  11. # <i>example.com</i>

decompose()

  • タグをツリーから取り除く
  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. a_tag = soup.a
  4.  
  5. soup.i.decompose()
  6.  
  7. a_tag
  8. # <a href="http://example.com/">I linked to</a>

replace_with()

  • タグおよび文字列をツリーから取り除き、別のタグおよび文字列に置き換える

wrap()

  • 要素をタグでラップする
  1. soup = BeautifulSoup("<p>I wish I was bold.</p>")
  2. soup.p.string.wrap(soup.new_tag("b"))
  3. # <b>I wish I was bold.</b>

unwrap()

  • タグをはがす
  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. a_tag = soup.a
  4.  
  5. a_tag.i.unwrap()
  6. a_tag
  7. # <a href="http://example.com/">I linked to example.com</a>

出力

Pretty-printing

prettify()

Non-pretty printing

unicode() もしくは str()を使う

XML

  1. from BeautifulSoup import BeautifulStoneSoup
  2.  
  3. def get_translation(itemid):
  4. ItemId から、訳語を取得する
  5. url = r'http://btonic.est.co.jp/NetDic/NetDicV09.asmx/GetDicItemLite?Dic=EJdict&Item={0}&Loc=&Prof=XHTML'
  6. url = url.format(itemid)
  7.  
  8. f = urllib2.urlopen(url)
  9.  
  10. soup = BeautifulStoneSoup(f.read())
  11. #print soup.prettify()
  12. try:
  13. ret = soup.body('div')[1].text
  14. except:
  15. ret =
  16. return ret

ページを解析し指定タグのテキストのみ取り出す

  1. soup = BeautifulSoup(urllib2.urlopen(url))
  2. for p in soup('p'):
  3. print p.text

タグの文字列を取得する

  1. soup = BeautifulSoup(urllib2.urlopen(url))
  2. .join(soup.findAll(text=True))

必要なタグのみ解析する

  1. tags = SoupStrainer(['title','img','h1','h2','h3','h4','h5','h6','p','meta','link'])
  2. soup = BeautifulSoup(urllib2.urlopen(url), parseOnlyThese=tags)

タグに囲まれた文字列値がある場合出力

  1. soup = BeautifulSoup(urllib2.urlopen(url))
  2. if hasattr(soup, "title") and hasattr(soup.title, "string"):
  3. print soup.title.string

Image タグから リンクを抜き出す

  1. soup = BeautifulSoup(urllib2.urlopen(url))
  2. for tag in soup.findAll():
  3. if tag.name == 'img':
  4. print tag['src']