風柳メモ

ソフトウェア・プログラミング関連の覚書が中心

Beautiful Soupで同様のことをしてみる

承前

lxmlの代わりに、Beautiful Soup(2013/01/02現在 Beautiful Soup 4.1.3)ならできるか、と試してみました。
XPathが使えないのが難点なんだけど…。

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup, NavigableString

TEST_HTML=u"""
<html>
  <head><title>TEST</title></head>
  <body>
    <div id="text">
      書き始め。
      <p>
        本文はここ。<br />
        ここまでだけ残して、後は消したいの。
      </p>
      <hr />
      <!-- cutting line  -->
      <p>ここから先は要らない</p>
      dust
      <b>ゴミ</b>
      廃棄物<br />
      unnecessary text
    </div>
  </body>
</html>
"""

if __name__ == '__main__':
  soup = BeautifulSoup(TEST_HTML, 'lxml')
  hr = soup.find('div', id='text').find('hr')
  next_elm = hr.next_sibling
  ci = 1
  while next_elm:
    print u'No.%2d' % (ci)
    tgt_elm = next_elm
    print tgt_elm
    next_elm = tgt_elm.next_sibling

    #if isinstance(tgt_elm, NavigableString):
    #  # NavigableStringのサブクラス有り(Comment, CData, ProcessingInstruction, Declaration, Doctype)

    if hasattr(tgt_elm, 'decompose'):
      tgt_elm.decompose()
    else:
      tgt_elm.replace_with('')

    print u'='*50+u'\n'
    ci += 1

  print u'■結果'
  print unicode(soup)
  print u'\n'
  print u'■結果 (整形後)'
  print soup.prettify()

# ■ end of file

結果

No. 1


==================================================

No. 2
 cutting line
==================================================

No. 3


==================================================

No. 4
<p>ここから先は要らない</p>
==================================================

No. 5

      dust

==================================================

No. 6
<b>ゴミ</b>
==================================================

No. 7

      廃棄物
==================================================

No. 8
<br/>
==================================================

No. 9

      unnecessary text

==================================================

■結果
<html><head><title>TEST</title></head><body>
<div id="text">
      書き始め。
      <p>
        本文はここ。<br/>
        ここまでだけ残して、後は消したいの。
      </p>
<hr/></div>
</body></html>


■結果 (整形後)
<html>
 <head>
  <title>
   TEST
  </title>
 </head>
 <body>
  <div id="text">
   書き始め。
   <p>
    本文はここ。
    <br/>
    ここまでだけ残して、後は消したいの。
   </p>
   <hr/>
  </div>
 </body>
</html>

一応、やりたいことは出来るのかな

テキストノードに相当するのが NavigableString で、これは他の要素(Tag付)みたいにTag.decompose()で消すことはできない模様。
ただ、Str.replace_with(<置換文字列>) で文字列を書き換えることは出来るので、引数に空文字('')を指定してやれば、実質的に消すことは出来る。

サゲ

というわけで、だれか、Beautiful Soup 4で XPath も使えるようにしてください(苦笑)。