Parsowanie HTML w Pythonie-lxml czy BeautifulSoup? Który z nich jest lepszy do jakich celów?

Z tego co wiem, dwie główne biblioteki analizujące HTML w Pythonie to lxml i BeautifulSoup. Wybrałem BeautifulSoup dla projektu, nad którym pracuję, ale wybrałem go bez konkretnego powodu, poza znalezieniem składni nieco łatwiejszej do nauczenia się i zrozumienia. Ale widzę, że wiele osób preferuje lxml i słyszałem, że lxml jest szybszy.

Więc zastanawiam się jakie są zalety jednego nad drugim? Kiedy chcę używać lxml, a kiedy lepiej używać BeautifulSoup? Czy są jakieś inne biblioteki warte rozważenia?

Author: Monika Sulik, 2009-12-17

7 answers

na początek BeautifulSoup nie jest już aktywnie utrzymywany, a autor zaleca nawet alternatywy, takie jak lxml.

Cytowanie z linkowanej strony:

Wersja 3.1.0 pięknej zupy robi znacznie gorzej w rzeczywistym HTML niż wersja 3.0.8. Najbardziej częstymi problemami są rozwiązywanie tagi: "nieprawidłowy start tag "errors, and" bad end tag " errors. Ta strona wyjaśnia, co się stało, jak problemem będzie adresowane, oraz co możesz teraz zrobić.

Ta strona została pierwotnie napisana w Marzec 2009r. Od tego czasu seria 3.2 został wydany, zastępując 3.1 serii, a rozwój 4.x seria ruszyła. Ta strona pozostanie na historycznym cele.

Tl; dr

Użyj zamiast tego 3.2.0.

 22
Author: Alex Brasetvik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-25 02:37:37

Pyquery dostarcza interfejs selektora jQuery do Pythona (używając pod maską lxml).

Http://pypi.python.org/pypi/pyquery

To jest naprawdę niesamowite, nie używam już niczego innego.
 25
Author: mikeal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-03 18:40:51

Podsumowując, {[2] } jest umieszczony jako błyskawiczny parser html i xml jakości produkcji, który, nawiasem mówiąc, zawiera również moduł soupparser, aby wrócić do funkcjonalności BeautifulSoup. BeautifulSoup to jednoosobowy projekt, zaprojektowany, aby zaoszczędzić czas na szybkie wyodrębnianie danych ze słabo uformowanego html lub xml.

Dokumentacja Lxml mówi, że oba parsery mają zalety i wady. Z tego powodu, lxml zapewnia soupparser, dzięki czemu można przełączać się tam iz powrotem. Cytowanie,

BeautifulSoup używa innego podejścia do parsowania. To nie jest prawdziwy HTML parser ale używa wyrażeń regularnych do przeszukiwania tagów. On dlatego w niektórych przypadkach bardziej wyrozumiały, a w innych mniej dobry. On często zdarza się, że lxml / libxml2 lepiej parsuje i naprawia zepsuty HTML, ale BeautifulSoup ma superiour wsparcie dla wykrywania kodowania. It bardzo wiele zależy od wejścia, który parser działa lepiej.

W końcu są mówiąc:

Minusem korzystania z tego parsera jest to, że jest on znacznie wolniejszy niż parser HTML lxml. więc jeśli wydajność ma znaczenie, możesz chcieć aby rozważyć użycie soupparser tylko jako alternatywy dla niektórych przypadków.

Jeśli dobrze je Rozumiem, oznacza to, że parser zupy jest bardziej wytrzymały - - - może poradzić sobie z "zupą" zniekształconych tagów za pomocą wyrażeń regularnych - - - podczas gdy lxml jest prostszy i po prostu parsuje rzeczy i buduje drzewo, jak można się spodziewać. Zakładam, że dotyczy to również samego BeautifulSoup, a nie tylko soupparser dla lxml.

Pokazują również, jak korzystać z detekcji kodowania BeautifulSoup, podczas szybkiego parsowania za pomocą 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))

(to samo źródło: http://lxml.de/elementsoup.html).

Słowami Twórcy BeautifulSoup,

To jest to! Baw się dobrze! Napisałem piękną zupę, żeby oszczędzić wszystkim czasu. Kiedy się do tego przyzwyczaisz, powinieneś być w stanie wrangle dane z źle zaprojektowane strony internetowe w kilka minut. Wyślij mi e-mail, jeśli masz jakieś uwagi, napotkasz problemy lub chcesz, żebym wiedział o Twoim projekt, który wykorzystuje piękną zupę.

 --Leonard

Cytat z pięknej dokumentacji zupy.

Mam nadzieję, że to jest teraz jasne. The soup to genialny jednoosobowy projekt zaprojektowany, aby zaoszczędzić czas na wydobywanie danych ze źle zaprojektowanych stron internetowych. Celem jest oszczędność czasu w tej chwili, aby wykonać zadanie, a nie koniecznie, aby zaoszczędzić czas w dłuższej perspektywie, a na pewno nie w celu optymalizacji wydajności oprogramowania.

Również ze strony lxml ,

Lxml został pobrany z indeksu pakietów Pythona więcej niż dwa milion razy i jest również dostępny bezpośrednio w wielu pakietach dystrybucje, np. dla Linuksa lub MacOS-X.

A od dlaczego lxml?,

Biblioteki C libxml2 i libxslt mają ogromne korzyści:... Zgodny ze standardami... W pełni funkcjonalny... szybko. szybko! Szybko! ... lxml jest nowym Bindowaniem Pythona dla libxml2 i libxslt...

 14
Author: osa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-23 18:25:30

Nie używaj BeautifulSoup, używaj lxml.soupparser wtedy siedzisz na szczycie mocy lxml i możesz użyć dobrych bitów BeautifulSoup, które jest do czynienia z naprawdę zepsutym i gównianym HTML.

 11
Author: Peter Bengtsson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-29 12:37:25

Używałem lxml z wielkim powodzeniem do parsowania HTML. Wydaje się, że dobrze radzi sobie z obsługą "soupy" HTML. Gorąco polecam.

Oto szybki test, który miałem, aby spróbować obsłużyć jakiś brzydki 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 __name__ == '__main__':
    unittest.main()
 5
Author: overthink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-17 14:19:18

Na pewno użyłbym EHP. Jest szybszy niż lxml, znacznie bardziej elegancki i prostszy w użyciu.

Zobacz też 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()    

Wyjście:

Hello world. 
 1
Author: Unknown Soldier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-20 10:03:18

Nieco przestarzałe porównanie prędkości można znaleźć tutaj, które wyraźnie zaleca lxml, ponieważ różnice prędkości wydają się drastyczne.

 0
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-08 13:42:45