BeautifulSoup无法解析网页?

时间:2012-10-14 21:18:03

标签: python parsing beautifulsoup

我现在正在使用美丽的汤来解析网页,我听说它很有名,很好,但看起来不太合适。

这就是我做的事情

import urllib2
from bs4 import BeautifulSoup

page = urllib2.urlopen("http://www.cnn.com/2012/10/14/us/skydiver-record-attempt/index.html?hpt=hp_t1")
soup = BeautifulSoup(page)
print soup.prettify()

我认为这很简单。我打开网页并将其传递给beautifulsoup。但这就是我得到的:

Warning (from warnings module):

File "C:\Python27\lib\site-packages\bs4\builder\_htmlparser.py", line 149

"Python's built-in HTMLParser cannot parse the given document. This is not a bug in Beautiful Soup. The best solution is to install an external parser (lxml or html5lib), and use Beautiful Soup with that parser. See http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser for help."))

...

HTMLParseError: bad end tag: u'</"+"script>', at line 634, column 94

我认为CNN网站设计得很好,所以我不太清楚会发生什么。有没有人对此有所了解?

4 个答案:

答案 0 :(得分:10)

来自the docs

  

如果可以的话,我建议你安装并使用lxml来提高速度。如果你是   使用早于2.7.3的Python 2版本或Python版本   3。早于3.2.2,安装lxml或者必须安装   html5lib-Python的内置HTML解析器在旧版本中并不是很好   版本

如果在Python 2.7上安装更强大的解析器(例如lxml或html5lib),您的代码将按原样(在Python 2.7,Python 3.3上)工作:

try:
    from urllib2 import urlopen
except ImportError:
    from urllib.request import urlopen # py3k

from bs4 import BeautifulSoup # $ pip install beautifulsoup4

url = "http://www.cnn.com/2012/10/14/us/skydiver-record-attempt/index.html?hpt=hp_t1"
soup = BeautifulSoup(urlopen(url))
print(soup.prettify())

HTMLParser.py - more robust SCRIPT tag parsing错误可能与此有关。

答案 1 :(得分:8)

您不能使用BeautifulSoup或任何HTML解析器来阅读网页。您永远不能保证网页是一个格式良好的文档。让我解释一下这个案例中发生的事情。

在该页面上有这个INLINE javascript:

var str="<script src='http://widgets.outbrain.com/outbrainWidget.js'; type='text/javascript'></"+"script>";

您可以看到它正在创建一个将脚本标记放到页面上的字符串。现在,如果你是一个HTML解析器,这是一个非常棘手的事情。当你突然点击<script>标签时,你会继续读取你的标记。现在,不幸的是,如果你这样做了:

<script>
alert('hello');
<script>
alert('goodby');

大多数解析器会说:好的,我找到了一个开放的脚本标记。哦,我找到了另一个开放的脚本标签!他们一定忘了关闭第一个!并且解析器会认为两者都是有效的脚本。

因此,在这种情况下,BeautifulSoup会看到<script>标记,而即使它在javascript字符串中,看起来它可能是一个有效的起始标记,而BeautifulSoup有一个癫痫发作,以及它应该。

如果你再看一下这个字符串,你可以看到他们做了这件有趣的工作:

... "</" + "script>";

这看起来很奇怪吗?如果不进行额外的字符串连接就行str = " ... </script>"不是更好吗?这实际上是一个常见的技巧(愚蠢的人将脚本标记写成字符串,这是一种不好的做法),使解析器不会中断。因为如果你这样做:

var a = '</script>';

在内联脚本中,解析器会出现并且真正看到</script>并认为整个脚本标记已经结束,并将该脚本标记的其余内容作为纯文本抛出到页面上。这是因为即使您的JS语法无效,您也可以在技术上将关闭脚本标记放在任何位置。从解析器的角度来看,最好尽早退出脚本标记,而不是尝试将html代码渲染为javascript。

因此,您无法使用常规HTML解析器来解析网页。这是一场非常非常危险的比赛。无法保证您将获得格式良好的HTML。根据您要执行的操作,您可以使用正则表达式阅读页面内容,或尝试使用headless browser

获取完全呈现的页面内容

答案 2 :(得分:2)

你需要使用带BeautifulSoup的html5lib解析器

要安装reqd解析器,请使用pip:

pip install html5lib

然后以这种方式使用该解析器

import mechanize
br = mechanize.Browser()
html = br.open("http://google.com/",timeout=100).read()
soup = BeautifulSoup(html,'html5lib')
a_s = soup.find_all('a')
for i in range(0,len(a_s)):
 print a_s[i]['href']

答案 3 :(得分:1)

您可以做的最简单的事情之一是,将内容指定为“lxml”。您可以通过将“lxml”添加到urlopen()函数作为参数

来实现

page = urllib2.urlopen(“[url]”,“lxml”)

然后你的代码如下。

import urllib2from bs4 import BeautifulSoup page = urllib2.urlopen("http://www.cnn.com/2012/10/14/us/skydiver-record-attempt/index.html?hpt=hp_t1","lxml") soup = BeautifulSoup(page) print soup.prettify()

到目前为止,我没有遇到任何麻烦:)