web-dev-qa-db-ja.com

python-lxmlまたはBeautifulSoupでHTMLを解析しますか?

私ができることから、Pythonの2つの主要なHTML解析ライブラリはlxmlとBeautifulSoupです。作業中のプロジェクトにBeautifulSoupを選択しましたが、特に選択しませんでした。しかし、多くの人がlxmlを好むようであり、lxmlのほうが速いと聞きました。

だから、私は一方の利点が他のものよりも優れているのだろうか? lxmlをいつ使用したいのか、BeautifulSoupを使用したほうがよいのはいつですか?他に検討する価値のあるライブラリはありますか?

54
Monika Sulik

まず第一に、BeautifulSoupは積極的に保守されなくなり、 著者は代替案も推奨しています (lxmlなど)。

リンクされたページからの引用:

Beautiful Soupのバージョン3.1.0は、バージョン3.0.8よりも実際のHTMLで著しく劣ります。最も一般的な問題は、タグの不適切な処理、「不正な開始タグ」エラー、および「不正な終了タグ」エラーです。このページでは、何が起こったのか、問題にどのように対処するのか、今すぐにできることを説明しています。

このページはもともと2009年3月に作成されました。それ以降、3.1シリーズに代わって3.2シリーズがリリースされ、4.xシリーズの開発が進行中です。このページは過去の目的のために残ります。

tl; dr

代わりに3.2.0を使用してください。

22
Alex Brasetvik

Pyqueryは、Python(内部でlxmlを使用)へのjQueryセレクターインターフェイスを提供します。

http://pypi.python.org/pypi/pyquery

それは本当に素晴らしいです、私はもう何も使いません。

26
mikeal

要約すると、lxmlは、超高速の製品品質のhtmlおよびxmlパーサーとして位置付けられており、ちなみに、BeautifulSoupの機能にフォールバックするsoupparserモジュールも含まれています。 BeautifulSoupは1人のプロジェクトであり、時間の節約のために、整形式でないhtmlまたはxmlからデータをすばやく抽出するように設計されています。

lxml documentation は、両方のパーサーに長所と短所があることを示しています。このため、lxmlsoupparserを提供するので、前後に切り替えることができます。引用、

BeautifulSoupは異なる解析アプローチを使用します。これは実際のHTMLパーサーではありませんが、正規表現を使用してタグスープを調べます。したがって、場合によってはより寛容になり、他の場合にはあまり良くありません。 lxml/libxml2が壊れたHTMLをより適切に解析および修正することは珍しくありませんが、BeautifulSoupにはエンコード検出の優れたサポートがあります。 それは、どのパーサーがよりよく機能するかによって大きく異なります。

最後に、彼らは言っています、

このパーサーを使用する欠点は、lxmlのHTMLパーサーよりもはるかに遅いことです。 パフォーマンスが重要な場合、特定の場合のフォールバックとしてのみsoupparserを使用することを検討する必要があります。

私がそれらを正しく理解していれば、それはスープパーサーがより堅牢であることを意味します---正規表現を使用することで不正なタグの「スープ」に対処できます---一方、lxmlはより単純で、単に物を解析してあなたは期待するでしょう。 BeautifulSoupsoupparserだけでなく、lxml自体にも適用されると思います。

また、BeautifulSoupのエンコード検出を利用しながら、lxmlを使用してすばやく解析する方法も示しています。

>>> from BeautifulSoup import UnicodeDammit

>>> def decode_html(html_string):
...     converted = UnicodeDammit(html_string, isHTML=True)
...     if not converted.unicode:
...         raise UnicodeDecodeError(
...             "Failed to detect encoding, tried [%s]",
...             ', '.join(converted.triedEncodings))
...     # print converted.originalEncoding
...     return converted.unicode

>>> root = lxml.html.fromstring(decode_html(tag_soup))

(同じソース: http://lxml.de/elementsoup.html )。

BeautifulSoupの作成者の言葉では、

それでおしまい!楽しんで!みんなの時間を節約するために、Beautiful Soupを書きました。慣れてしまえば、設計が不十分なWebサイトからわずか数分でデータを収集できます。コメントがある場合、問題が発生した場合、またはBeautiful Soupを使用しているプロジェクトについて知りたい場合は、メールを送信してください。

 --Leonard

Beautiful Soup documentation から引用。

これが明らかになったことを願っています。このスープは、設計が不十分なWebサイトからデータを抽出する時間を節約するために設計された素晴らしい1人のプロジェクトです。目標は、現時点で時間を節約し、仕事を終わらせることであり、必ずしも長期的に時間を節約することではなく、間違いなくソフトウェアのパフォーマンスを最適化しないことです。

また、 lxml website から、

lxmlはPython Package Indexから200万回以上ダウンロードされており、LinuxやMacOS-Xなどの多くのパッケージ配布でも直接利用できます。

そして、 なぜlxml? から

Cライブラリlibxml2およびlibxsltには大きな利点があります。..標準準拠...全機能搭載...高速。速い!早く! ... lxmlは、新しいPython libxml2とlibxsltのバインディングです...

15
osa

lxml.soup parser を使用するBeautifulSoupを使用しないでください。lxmlのパワーを利用して、本当に壊れたがらくたHTMLを処理するBeautifulSoupの優れた部分を使用できます。

11
Peter Bengtsson

HTMLの構文解析に大成功を収めたlxmlを使用しました。また、「すっきりした」HTMLをうまく処理しているようです。強くお勧めします。

HereいHTMLの処理を試すために私が横たわった簡単なテストを次に示します。

import unittest
from StringIO import StringIO
from lxml import etree

class TestLxmlStuff(unittest.TestCase):
    bad_html = """
        <html>
            <head><title>Test!</title></head>
            <body>
                <h1>Here's a heading
                <p>Here's some text
                <p>And some more text
                <b>Bold!</b></i>
                <table>
                   <tr>row
                   <tr><td>test1
                   <td>test2
                   </tr>
                   <tr>
                   <td colspan=2>spanning two
                </table>
            </body>
        </html>"""

    def test_soup(self):
        """Test lxml's parsing of really bad HTML"""
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(self.bad_html), parser)
        self.assertEqual(len(tree.xpath('//tr')), 3)
        self.assertEqual(len(tree.xpath('//td')), 3)
        self.assertEqual(len(tree.xpath('//i')), 0)
        #print(etree.tostring(tree.getroot(), pretty_print=False, method="html"))

if __== '__main__':
    unittest.main()
5
overthink

確かに、EHPを使用します。 lxmlよりも高速で、はるかにエレガントで使いやすいです。

チェックアウト。 https://github.com/iogf/ehp

<body ><em > foo  <font color="red" ></font></em></body>


from ehp import *

data = '''<html> <body> <em> Hello world. </em> </body> </html>'''

html = Html()
dom = html.feed(data)

for ind in dom.find('em'):
    print ind.text()    

出力:

Hello world. 
1
Unknown Soldier

やや時代遅れの速度比較が見つかります here 、これは明らかに速度の違いが劇的に見えるのでlxmlを推奨します。

0
Michael