实际有效的Python HTML解析方法

14 投票
5 回答
4223 浏览
提问于 2025-04-16 06:40

我正在尝试用Python解析一些HTML代码。之前有一些方法是有效的……但现在没有什么可以直接用的,必须绕一些弯。

  • beautifulsoup在SGMLParser不再支持后出现了问题。
  • html5lib无法解析一半的网页内容。
  • lxml对典型的HTML要求太严格(属性和标签不能包含未知的命名空间,否则就会抛出异常,这意味着几乎没有页面能解析,比如Facebook连接的页面)。

现在还有什么其他的选择吗?(如果它们支持xpath,那就更好了)

5 个回答

3

如果你在抓取内容,有一个很好的方法可以避免那些烦人的细节,那就是使用sitescraper这个工具包。它利用机器学习来判断哪些内容是你需要的。

来自主页的信息:

>>> from sitescraper import sitescraper
>>> ss = sitescraper()
>>> url = 'http://www.amazon.com/s/ref=nb_ss_gw?url=search-alias%3Daps&field-keywords=python&x=0&y=0'
>>> data = ["Amazon.com: python", 
             ["Learning Python, 3rd Edition", 
             "Programming in Python 3: A Complete Introduction to the Python Language (Developer's Library)", 
             "Python in a Nutshell, Second Edition (In a Nutshell (O'Reilly))"]]
>>> ss.add(url, data)
>>> # we can add multiple example cases, but this is a simple example so 1 will do (I   generally use 3)
>>> # ss.add(url2, data2) 
>>> ss.scrape('http://www.amazon.com/s/ref=nb_ss_gw?url=search-alias%3Daps&field-  keywords=linux&x=0&y=0')
["Amazon.com: linux", ["A Practical Guide to Linux(R) Commands, Editors, and Shell    Programming", 
"Linux Pocket Guide", 
"Linux in a Nutshell (In a Nutshell (O'Reilly))", 
'Practical Guide to Ubuntu Linux (Versions 8.10 and 8.04), A (2nd Edition)', 
'Linux Bible, 2008 Edition: Boot up to Ubuntu, Fedora, KNOPPIX, Debian, openSUSE, and 11 Other Distributions']]
7

我用过pyparsing来做一些抓取网页的项目。它介于BeautifulSoup和完整的HTML解析器之间,而又比正则表达式这种低级的方法要好很多(用正则表达式抓取网页会让人抓狂)。

使用pyparsing,你可以通过确定你想提取的网页或数据的特定部分,来获得不错的抓取结果。这种方法避免了尝试解析网页上所有内容的问题,因为如果你关注的区域外有一些问题HTML,可能会干扰到全面的HTML解析器。

虽然这听起来像是一个升级版的正则表达式方法,但pyparsing提供了处理HTML或XML标记文本的内置功能。它避免了许多让人头疼的正则表达式问题:

  • 可以接受空格,而不需要在表达式中到处加'\s*'
  • 能够处理标签中的意外属性
  • 可以处理属性的顺序
  • 可以处理标签的大小写
  • 可以处理带有命名空间的属性名
  • 可以处理用双引号、单引号或没有引号的属性值
  • 可以处理空标签(像<blah />这样的形式)
  • 返回解析后的标签数据,可以通过对象属性访问标签属性

这里有一个来自pyparsing维基的简单例子,它可以从网页中提取<a href=xxx>标签:

from pyparsing import makeHTMLTags, SkipTo

# read HTML from a web page
page = urllib.urlopen( "http://www.yahoo.com" )
htmlText = page.read()
page.close()

# define pyparsing expression to search for within HTML    
anchorStart,anchorEnd = makeHTMLTags("a")
anchor = anchorStart + SkipTo(anchorEnd).setResultsName("body") + anchorEnd

for tokens,start,end in anchor.scanString(htmlText):
    print tokens.body,'->',tokens.href

这个例子可以提取出<a>标签,即使页面上还有其他部分包含问题HTML。pyparsing维基上还有其他HTML的例子:

虽然pyparsing并不是解决这个问题的万无一失的方法,但它让你可以更好地控制你具体感兴趣的HTML部分,处理这些部分,并跳过其他不需要的内容。

19

确保在用 lxml 解析 HTML 时使用 html 模块:

>>> from lxml import html
>>> doc = """<html>
... <head>
...   <title> Meh
... </head>
... <body>
... Look at this interesting use of <p>
... rather than using <br /> tags as line breaks <p>
... </body>"""
>>> html.document_fromstring(doc)
<Element html at ...>

这样一来,所有的错误和异常都会消失,你将得到一个非常快速的解析器,它处理 HTML 的能力往往比 BeautifulSoup 还要好。

撰写回答