Beautifulsoup4 с lxml против Beautifulsoup3

Я переношу некоторые синтаксические анализаторы с BeautifulSoup3 на BeautifulSoup4 и подумал, что было бы неплохо профилировать, насколько быстрее это будет происходить, учитывая, что lxml очень быстрый, и это парсер, который я использую с BS4, вот результаты профиля:

Для БС3:

43208 function calls (42654 primitive calls) in 0.103 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.000    0.000 <string>:2(<module>)
   18    0.000    0.000    0.000    0.000 <string>:8(__new__)
    1    0.000    0.000    0.072    0.072 <string>:9(parser)
   32    0.000    0.000    0.000    0.000 BeautifulSoup.py:1012(__init__)
    1    0.000    0.000    0.000    0.000 BeautifulSoup.py:1018(buildTagMap)
... 

Для BS4 с использованием lxml:

164440 function calls (163947 primitive calls) in 0.244 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.040    0.040    0.069    0.069 <string>:2(<module>)
   18    0.000    0.000    0.000    0.000 <string>:8(__new__)
    1    0.000    0.000    0.158    0.158 <string>:9(parser)
    1    0.000    0.000    0.008    0.008 HTMLParser.py:1(<module>)
    1    0.000    0.000    0.000    0.000 HTMLParser.py:54(HTMLParseError)
...

почему BS4 вызывает в 4 раза больше функций? почему он вообще использует HTMLParser, если я настроил его на использование lxml?

Наиболее заметными вещами, которые я изменил с BS3 на BS4, были следующие:

 BeautifulSoup(html, convertEntities=BeautifulSoup.HTML_ENTITIES)  --->
 BeautifulSoup(html, 'lxml')

 [x.getText('**SEP**') for x in i.findChildren('font')[:2]] --->
 [x.getText('**SEP**', strip=True) for x in i.findChildren('font')[:2]]

все остальное - это просто некоторые изменения имени (например, findParent --> find_parent)

РЕДАКТИРОВАТЬ:

моя среда:

python 2.7.3
beautifulsoup4==4.1.0
lxml==2.3.4

РЕДАКТИРОВАТЬ 2:

Вот небольшой пример кода, чтобы попробовать:

from cProfile import Profile

from BeautifulSoup import BeautifulSoup
from bs4 import BeautifulSoup as BS4
import urllib2


def parse(html):

    soup = BS4(html, 'lxml')
    hl = soup.find_all('span', {'class': 'mw-headline'})
    return [x.get_text(strip=True) for x in hl]


def parse3(html):

    soup = BeautifulSoup(html, convertEntities=BeautifulSoup.HTML_ENTITIES)
    hl = soup.findAll('span', {'class': 'mw-headline'})
    return [x.getText() for x in hl]


if __name__ == "__main__":
    opener = urllib2.build_opener()
    opener.addheaders = [('User-agent', 'Mozilla/5.0')]
    html = ''.join(opener.open('http://en.wikipedia.org/wiki/Price').readlines())

    profiler = Profile()
    print profiler.runcall(parse, html)
    profiler.print_stats()

    profiler2 = Profile()
    print profiler2.runcall(parse3, html)
    profiler2.print_stats()

person Hassek    schedule 02.07.2012    source источник
comment
Мы не сможем воспроизвести ваши результаты, если вы не предоставите нам образец URL-адреса для работы, в котором обнаружена эта проблема. (Кроме того, вы определили, проявляется ли эта проблема в файле lxml.html или только в BS4?)   -  person Charles Duffy    schedule 02.07.2012
comment
только BS4, не пробовал это только с lxml. Позвольте мне очень быстро создать простой пример, чтобы вы, ребята, могли воспроизвести его.   -  person Hassek    schedule 02.07.2012
comment
хорошо, просто добавил небольшой пример, чтобы каждый мог попробовать   -  person Hassek    schedule 02.07.2012


Ответы (1)


Я считаю, что основная проблема заключается в ошибке в Beautiful Soup 4. Я зарегистрировал ее. и исправление будет выпущено в следующей версии. Спасибо, что нашли это.

Тем не менее, я понятия не имею, почему в вашем профиле вообще упоминается класс HTMLParser, учитывая, что вы используете lxml.

person Leonard Richardson    schedule 02.07.2012
comment
да, и в тесте википедии он тоже не отображается. Спасибо, что указали на ошибку, надеюсь, это скоро исправят! - person Hassek; 03.07.2012