かなり無理やりなパッチ
回答もつきそうにないし、Beautiful Soup 4 で XPath を使う方法もわからないので、無理やり自己解決。
ダウンロード:bs4_plus_xpath.tgz
Beautiful Soup 4 + lxmlで無理やりXPath
from bs4 import BeautifulSoup from bs4_plus_xpath import Tag
Tag クラスに xpath という関数をくっつけている。
soup = BeautifulSoup(html, 'lxml')
elm_list = soup.xpath(<XPath式>)
みたいな感じで、XPath式を指定して要素を取得できる。これらは BeautifulSoup 要素(Tag等)なので、元の関数はそのまま使える。
例
#! /usr/bin/env python # -*- coding: utf-8 -*- from bs4 import BeautifulSoup, NavigableString from bs4_plus_xpath import Tag 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> """ #{ // def remove_elm_list() def remove_elm_list(elm_list): for (ci, elm) in enumerate(elm_list): print u'No.%2d' % (ci+1) print elm if hasattr(elm, 'decompose'): # 通常のノード elm.decompose() else: # テキストノード elm.replace_with('') print u'='*50+u'\n' #} // end of remove_elm_list() if __name__ == '__main__': soup = BeautifulSoup(TEST_HTML, 'lxml') junk_elm_list = soup.xpath(u'//div[@id="text"]/hr/following-sibling::node()') remove_elm_list(junk_elm_list) print u'■結果' print unicode(soup) print u'\n' print u'■結果 (整形後)' print soup.prettify() # ■ end of file
実行結果
No. 1
 cutting line
==================================================
No. 2
<p>ここから先は要らない</p>
==================================================
No. 3
      dust
==================================================
No. 4
<b>ゴミ</b>
==================================================
No. 5
      廃棄物
==================================================
No. 6
<br/>
==================================================
No. 7
      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>
言い訳
ソースを見ればわかりますが、かなり無理やりなことをやっており、ちゃんと動く保証は一切ありませんので、ご容赦を。
その作り上、速度も非常に遅くなります。
「俺は XPath 指定じゃないと使う気にならないんだっ!」という奇特な方は、ご参考までにということで。
それ以外の方は、素直に Beautiful Soup の普通の検索方法を使った方がよいです。