1. 程式人生 > >網頁內容爬取:如何提取正文內容 BEAUTIFULSOUP的輸出

網頁內容爬取:如何提取正文內容 BEAUTIFULSOUP的輸出

總計 排除 XML html pack prettify 樣式 start ack

創建一個新網站,一開始沒有內容,通常需要抓取其他人的網頁內容,一般的操作步驟如下:

根據url下載網頁內容,針對每個網頁的html結構特征,利用正則表達式,或者其他的方式,做文本解析,提取出想要的正文。

為每個網頁寫特征分析這個還是太耗費開發的時間,我的思路是這樣的。

Python的BeautifulSoup包大家都知道吧,

import BeautifulSoup
soup = BeautifulSoup.BeautifulSoup(html)

利用這個包先把html裏script,style給清理了:

[script.extract() for script in soup.findAll(‘script‘)]
[style.extract() for style in soup.findAll(‘style‘)]

清理完成後,這個包有一個prettify()函數,把代碼格式給搞的標準一些:

soup.prettify()

然後用正則表達式,把所有的HTML標簽全部清理了:

reg1 = re.compile("<[^>]*>")
content = reg1.sub(‘‘,soup.prettify())

剩下的都是純文本的文件了,通常是一行行的,把空白行給排除了,這樣就會知道總計有多少行,每行的字符數有多少,我用excel搞了一些每行字符數的統計,如下圖:

技術分享

x坐標為行數,y坐標為該行的字符數

很明顯,會有一個峰值,81~91行就應該是這個網頁的正文部分。我只需要提取81~91行的文字就行了。

問題來了,照著這個思路,有什麽好的算法能夠通過數據分析的方式統計出長文本的峰值在哪幾行?

BeautifulSoup不僅僅只是可以查找,定位和修改文檔內容,同樣也可以用一個好的 格式進行輸出顯示。BeautifulSoup可以處理不同類型的輸出:

  • 格式化的輸出
  • 非格式化的輸出

格式化輸出

BeautifulSoup中有內置的方法prettfy()來實現格式化輸出。比如: view plaincopyprint?

  1. from bs4 import BeautifulSoup
  2. html_markup = “””<p class=”ecopyramid”>
  3. <ul id=”producers”>
  4. <li class=”producerlist”>
  5. <div class=”name”>plants</div>
  6. <div class=”number”>100000</div>
  7. </li>
  8. <li class=”producerlist”>
  9. <div class=”name”>algae</div>
  10. Output in Beautiful Soup
  11. <div class=”number”>100000</div>
  12. </li>
  13. </ul>”””
  14. soup = BeautifulSoup(html_markup,“lxml”)
  15. print(soup.prettify())

輸出:

技術分享 prettify()可以用於BeautifulSoup對象也可以用於任何標簽對象。比如: view plaincopyprint?

  1. producer_entry = soup.ul
  2. print(producer_entry.prettify())


非格式化輸出

可以使用str()和unicode()來進行非格式化輸出。 如果我們對BeautifulSoup對象和標簽對象使用str()方法,那麽得到的就是一般的字符串輸出樣式。 我們也可以使用前篇講到的encode()方法來指定編碼格式的輸出。 對BeautifulSoup對象或標簽對象使用decode()方法來得到Unicode字符串。

BeautifulSoup中的輸出格式化

HTML實體編碼可以放進HTML文檔中用來表示特別的字符和標識。這些標識不存在於鍵盤上,這些HTML實體編碼只是當瀏覽器打開後才回看到效果。 在輸出方法中,只有這幾個HTML編碼有點例外。>和<和&三個符號。除此之外其他的特別標識都是被轉換成Unicode編碼當創建BeautifulSoup對象時,且當使用Prettify()方法或者其他方法輸出時,我們只能得到UTF-8格式的字符串。 html_markup = “””<html>
<body>& &amp; ampersand
¢ &cent; cent
? &copy; copyright
÷ &divide; divide
> &gt; greater than
</body>
</html> 輸出:

技術分享 可以看到兩個沒有被轉換。BeautifulSoup自帶的輸出格式器來控制輸出。輸出格式器有以下幾種類型。
  • miimal
  • html
  • None
  • function
我們可以在輸出方法中傳遞上述輸出格式器參數,如prettify(),ncode(),decode()

miimal格式化

在這種格式化模式下,字符串被處理成一個有效的HTML代碼。這是默認的格式化輸出,此時輸出結果就和前面的一樣。不能轉換&amp;, &gt;和&lt;

Html格式化

這種格式化模式下,BeautifulSoup將會將Unicode字符轉換成HTML編碼形式。
print(soup.prettify(formatter=”html”))

輸出: 技術分享

None格式化

這種情況下,BeautifulSoup不會改變字符串。這會導致產生一個非法的HTML代碼。 view plaincopyprint?

  1. print(soup.prettify(formatter=None))

輸出:

技術分享

函數格式化

我們可以定義一個函數來處理字符串。比如去掉a字符。 view plaincopyprint?

  1. def remove_chara(markup):
  2. return markup.replace(“a”,””)
  3. soup = BeautifulSoup(html_markup,“lxml”)
  4. print(soup.prettify(formatter=remove_chara))

輸出:

技術分享 註意,其中字符a被替換掉了,但是註意的是&amp;, &gt;,和&lt;也被轉換了。

使用get_text()

從網頁中得到文本是常見的工作,BeautifulSoup提供了get_text()方法來達到目的。 如果我們只想得到BeautifulSoup對象的文本或標簽對象的文本內容,我們可以使用get_text()方法。比如: view plaincopyprint?

  1. html_markup = “””<p class=”ecopyramid”>
  2. <ul id=”producers”>
  3. <li class=”producerlist”>
  4. <div class=”name”>plants</div>
  5. <div class=”number”>100000</div>
  6. </li>
  7. <li class=”producerlist”>
  8. <div class=”name”>algae</div>
  9. <div class=”number”>100000</div>
  10. </li>
  11. </ul>”””
  12. soup = BeautifulSoup(html_markup,“lxml”)
  13. print(soup.get_text())

輸出:

plants
100000 algae
100000 get_text()方法返回BeautifulSoup對象或標簽對象中的文本內容,其為一個Unicode字符串。但是get_text()有個問題是它同樣也會返回javascript代碼。

去掉javascript代碼的方法如下: view plaincopyprint?

  1. [x.extract() for x in soup_packtpage.find_all(‘script’)]

這樣就會用處掉所有腳本元素。

網頁內容爬取:如何提取正文內容 BEAUTIFULSOUP的輸出