1. 程式人生 > >python 網路爬蟲與資訊採取之異常處理

python 網路爬蟲與資訊採取之異常處理

本篇文章轉自Ryan Mitchell 寫的python:網路資料採集
網路是十分複雜的。網頁資料格式不友好,網站伺服器宕機,目標資料的標籤找不到,都是很麻煩的事情。網路資料採集最痛苦的遭遇之一,就是爬蟲執行的時候你洗洗睡了,夢想著明天一早資料就都會採集好放在資料庫裡,結果第二天醒來,你看到的卻是一個因某種資料格式異常導致執行錯誤的爬蟲,在前一天當你不再盯著螢幕去睡覺之後,沒過一會兒爬蟲就不再運行了。那個時候,你可能想罵發明網際網路(以及那些奇葩的網路資料格式)的人,但是你真正應該斥責的人是你自己,為什麼一開始不估計可能會出現的異常!
讓我們看看爬蟲 import 語句後面的第一行程式碼,如何處理那裡可能出現的異常:
html = urlopen("http://www.pythonscraping.com/pages/page1.html")


這行程式碼主要可能會發生兩種異常:
• 網頁在伺服器上不存在(或者獲取頁面的時候出現錯誤)
• 伺服器不存在第一種異常發生時,程式會返回 HTTP 錯誤。
HTTP 錯誤可能是“404 Page Not Found”“500Internal Server Error”等。所有類似情形,urlopen 函式都會丟擲“HTTPError”異常。我們可以用下面的方式處理這種異常:

try: html =  urlopen("http://www.pythonscraping.com/pages/page1.html")
except HTTPError as e:
 print(e) # 返回空值,中斷程式,或者執行另一個方案
else: # 程式繼續。

注意:如果你已經在上面異常捕捉那一段程式碼裡返回或中斷(break), # 那麼就不需要使用else語句了,這段程式碼也不會執行如果程式返回 HTTP 錯誤程式碼,程式就會顯示錯誤內容,不再執行 else 語句後面的程式碼。
如果伺服器不存在(就是說連結 http://www.pythonscraping.com/ 打不開,或者是 URL 連結寫錯了),urlopen 會返回一個 None 物件。這個物件與其他程式語言中的 null 類似。我們可以增加一個判斷語句檢測返回的 html 是不是None:
if html is None:
print(“URL is not found”)
else: # 程式繼續
網頁已經從伺服器成功獲取,如果網頁上的內容並非完全是我們期望的那樣,仍然可能會出現異常。每當你呼叫 BeautifulSoup 物件裡的一個標籤時,增加一個檢查條件保證標籤確實存在是很聰明的做法。如果你想要呼叫的標籤不存在,BeautifulSoup 就會返初見網路爬蟲 | 9回 None 物件。不過,如果再呼叫這個 None 物件下面的子標籤,就會發生 AttributeError錯誤。下面這行程式碼(nonExistentTag 是虛擬的標籤,BeautifulSoup 物件裡實際沒有)print(bsObj.nonExistentTag)會返回一個 None 物件。處理和檢查這個物件是十分必要的。如果你不檢查,直接呼叫這個None 物件的子標籤,麻煩就來了。如下所示。
print(bsObj.nonExistentTag.someTag)


AttributeError: 'NoneType' object has no attribute 'someTag'
我們怎麼才能避免這兩種情形的異常呢?最簡單的方式就是對兩種情形進行檢查:

try: badContent = bsObj.nonExistingTag.anotherTag
except AttributeError as e:
    print("Tag was not found")
else: 
     if badContent == None:
          print ("Tag was not found")
     else: print(badContent)
 `初看這些檢查與錯誤處理的程式碼會覺得有點兒累贅,但是,我們可以重新簡單組織一下程式碼,讓它變得不那麼難寫(更重要的是,不那麼難讀)。例如,下面的程式碼是上面爬蟲的另一種寫法:
from urllib.request import urlopenfrom

urllib.error
import HTTPErrorfrom

bs4
import BeautifulSoup


def getTitle(url): try

    : html = urlopen(url) except HTTPError as e:
return None
try: bsObj = BeautifulSoup(html.read())
title = bsObj.body.h1 except AttributeError as e:
return None
return titletitle = getTitle("http://www.pythonscraping.com/pages/page1.html")
if title == None:
    print("Title could not be found")else:
    print(title)

第 1 章在這個例子中,我們建立了一個 getTitle 函式,可以返回網頁的標題,如果獲取網頁的時候遇到問題就返回一個 None 物件。在 getTitle 函式裡面,我們像前面那樣檢查了HTTPError,然後把兩行 BeautifulSoup 程式碼封裝在一個 try 語句裡面。這兩行中的任何一行有問題,AttributeError 都可能被丟擲(如果伺服器不存在,html 就是一個 None 物件,html.read() 就會丟擲 AttributeError)。其實,我們可以在 try 語句裡面放任意多行程式碼,或者放一個在任意位置都可以丟擲 AttributeError 的函式。在寫爬蟲的時候,思考程式碼的總體格局,讓程式碼既可以捕捉異常又容易閱讀,這是很重要的。如果你還希望能夠很大程度地重用程式碼,那麼擁有像 getSiteHTML 和 getTitle 這樣的通用函式(具有周密的異常處理功能)會讓快速穩定地網路資料採集變得簡單易行。