2012-10-14 197 views
4

我現在正在使用美麗的湯來解析網頁,我聽說它非常有名,很好,但它似乎並不正常。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() 

我覺得這是一種直接的。我打開網頁並將其傳遞給美麗的裝置。但這裏是我的了:

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網站應該精心設計的,所以我也不是很確定發生了什麼事情。有沒有人有這個想法?

+0

我沒有安裝我的Python 2.7安裝BS4,但這個工程沒有在3.2和3.3的問題。 – poke

回答

10

the docs

如果可以的話,我建議你安裝並使用lxml來提高速度。如果您使用的是早於2.7.2的Python 2版本或早於3.2.2的Python版本 ,則必須安裝lxml或 html5lib-Python的內置HTML解析器並不是非常重要良好的舊版本 版本。

你的代碼工作是(關於Python 2.7,Python的3.3),如果你對Python 2.7版安裝更強大的分析器(如LXML或html5lib):

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錯誤可能有關。

+0

我想我使用Python2.7.2(目前我不能使用那臺電腦,所以我不是100 %肯定)。因此,如果我安裝更好的解析器,如lxml,我根本不需要修改我的代碼? (我認爲try和except部分是針對與Beautifulsoup無關的urllib)。只是想確保我理解正確。謝謝。 – JLTChiu

+0

@JLTChiu:是的,你不需要修改代碼。 'try/except'能夠在Python 2和Python 3上運行相同的腳本(Python 2上的'urllib2'和Python 3上的'urllib.request') – jfs

+0

非常感謝,我非常感謝你的幫助。 – JLTChiu

7

您不能使用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。這取決於你想做什麼,你可以用正則表達式讀取網頁的內容,或嘗試得到一個完全渲染頁面內容有headless browser

+2

*「您無法使用任何HTML解析器來閱讀網頁」* - 我認爲這是虛假陳述。 Web瀏覽器正是這樣做的,他們使用完善的HTML解析器來解析網頁內容。當然,他們在它上面添加了更多的功能,評估腳本和所有的東西,但他們仍然首先解析基礎HTML。在這種情況下,內置解析器似乎無法接受特定的HTML(儘管它對我和Vor來說工作正常),因此需要更強大的解析器。它仍然保持HTML解析器。 – poke

+0

[你至少可以在這種情況下](http://stackoverflow.com/a/12886926/4279) – jfs

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()作爲參數

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

到目前爲止,我沒有從這種做法有任何問題:)