Beautifulsoup 与 lxml 与 Beautifulsoup 3

Posted

技术标签:

【中文标题】Beautifulsoup 与 lxml 与 Beautifulsoup 3【英文标题】:Beautifulsoup4 with lxml vs Beautifulsoup3 【发布时间】:2012-07-03 02:35:28 【问题描述】:

我正在将一些解析器从 BeautifulSoup3 迁移到 BeautifulSoup4,我认为考虑到 lxml 超级快并且它是我与 BS4 一起使用的解析器,我认为分析它的速度将是一个好主意,以下是配置文件结果:

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

对于使用 lxml 的 BS4:

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 倍的函数?如果我将它设置为使用lxml,为什么它完全使用HTMLParser

我从 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()

【问题讨论】:

如果您不向我们提供显示此问题的示例 URL,我们将无法重现您的结果。 (另外,您确定 lxml.html 是否存在此问题,还是仅 BS4?) 只有BS4,没有单独用lxml试过这个。让我快速创建一个简单的示例,以便你们重现它 好的,只是添加了一个小例子,大家可以试试 【参考方案1】:

我认为主要问题是 Beautiful Soup 4 中的一个错误。我已经filed it 并且将在下一个版本中发布修复程序。感谢您找到这个。

也就是说,鉴于您使用的是 lxml,我完全不知道您的个人资料为什么会提到 HTMLParser 类。

【讨论】:

是的,在***测试中它也没有出现。感谢您指出它是一个错误,我希望这个问题尽快得到修复!

以上是关于Beautifulsoup 与 lxml 与 Beautifulsoup 3的主要内容,如果未能解决你的问题,请参考以下文章

[Python]BeautifulSoup安装与使用

lxml / BeautifulSoup 解析器警告

我的第二十七篇博客---beautifulsoup与csv操作方法

使用beautifulsoup与requests爬取数据

Python爬虫利器三之Xpath语法与lxml库的用法

Python爬虫利器三之Xpath语法与lxml库的用法