2012-07-02 11 views
5

Mam migrację niektórych parserów z BeautifulSoup3 do BeautifulSoup4 i pomyślałem, że byłoby dobrym pomysłem, aby profilować, jak szybko by się to stało, biorąc pod uwagę, że lxml jest super szybki i jest to parser, którego używam z BS4, tutaj są to wyniki profilu:Beautifulsoup4 z lxml vs Beautifulsoup3

Dla BS3:

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) 
... 

Dla BS4 stosując 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) 
... 

dlaczego BS4 dzwoni 4 tim es więcej funkcji? dlaczego w ogóle używa on HTMLParser, jeśli ustawię go na lxml?

najbardziej zauważalnych rzeczy zmieniłem od BS3 do BS4 były to:

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]] 

wszystko inne to tylko niektóre zmiany nazwy (jak findParent -> find_parent)

EDIT:

mój środowisko:

python 2.7.3 
beautifulsoup4==4.1.0 
lxml==2.3.4 

EDYCJA 2:

Oto mała próbka kodu, aby ją wypróbować:

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() 
+2

Nie możemy odtworzyć wyników, jeśli nie podasz nam przykładowego adresu URL, z którym można by pracować. (Czy ustaliłeś, czy plik lxml.html przedstawia ten problem, czy tylko BS4?) –

+0

tylko BS4, nie próbowałem tego z samym lxml. Pozwól mi stworzyć prosty przykład bardzo szybki, więc możesz go odtworzyć. – Hassek

+0

ok wystarczy dodać mały przykład, aby każdy mógł go wypróbować – Hassek

Odpowiedz

1

Uważam, że głównym problemem jest to błąd w Pięknej Soup 4. Mam filed it i poprawka ukaże się w następnej wersji. Dzięki za znalezienie tego.

Mimo to nie mam pojęcia, dlaczego Twój profil w ogóle wspomina klasę HTMLParser, biorąc pod uwagę, że używasz lxml.

+0

tak, a także w teście wikipedia nie pojawia się. Dzięki za wskazanie go jako błędu, mam nadzieję, że to się wkrótce poprawi! – Hassek