BeautifulSoup 无法解析网页?

问题描述 投票:0回答:5

我现在使用beautiful soup来解析网页,听说它很有名而且很好用,但似乎效果不太好。

这就是我所做的

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 网站应该设计得很好,所以我不太确定到底发生了什么。有人对此有想法吗?

python parsing beautifulsoup
5个回答
10
投票

来自文档

如果可以的话,我建议您安装并使用 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 - 更强大的 SCRIPT 标签解析 bug 可能与之相关。


8
投票

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

在该页面上有这个内联 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。根据您想要执行的操作,您可以使用正则表达式读取页面内容,或者尝试使用 无头浏览器

获取完全渲染的页面内容

2
投票

你需要将 html5lib 解析器与 BeautifulSoup 一起使用

要安装 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']

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

到目前为止,我没有从这种方法中遇到任何麻烦:)


0
投票
сам решил попробовать, вот что получилось :)
find_text = 'введите текст запроса'
html = urlopen(f'https://САЙТ.com/ru/search/?q={find_text}&target_type=posts&order=relevance')
bsObj = BeautifulSoup(html.read())
#строка выдачи
tm_pagination = bsObj.find('div', class_ = 'tm-pagination__pages').findAll('a')
last_page = int(tm_pagination[-1].text.strip())
#построчный перебор
link_list = []
for page_num in range(1,last_page+1):
    html = urlopen(f'https://САЙТ.com/ru/search/page{page_num}/?q={find_text}&target_type=posts&order=relevance')
    bsObj = BeautifulSoup(html.read())
    for elem in bsObj.findAll('a', class_ ='tm-article-snippet__readmore'):
        link_list.append('https://САЙТ.com' + elem['href'])
print(len(link_list))
print(*link_list[:10],sep = '\n')
тут выводятся ссылки которые напарсил код. потом чтение ссылок:
def parse_one_article(article_url):
    html = urlopen(article_url)
    bsObj = BeautifulSoup(html.read(), 'html.parser')
    content = bsObj.find('div', class_ ='tm-article-body').text #tm-article-presenter__body
    return(content)
with concurrent.futures.ThreadPoolExecutor() as executor:
    future_to_url = {executor.submit(parse_one_article,link): link for link in link_list}
    pages_text = []
    for future in concurrent.futures.as_completed(future_to_url):
        article_url = future_to_url[future]
        try:
            article_text = future.result()
            if article_text:
                pages_text.append(article_text)
        except Exception as err:
            print(f'Error{article_url}:{err}')
print(pages_text[2])
© www.soinside.com 2019 - 2024. All rights reserved.