1. 程式人生 > >python網路爬蟲-資料採集之遍歷單個爬蟲

python網路爬蟲-資料採集之遍歷單個爬蟲

     之所以稱之為爬蟲(Web Carwler)是因為它們可以沿著網路爬行。它們的本質就是一種遞迴方式。為了找到URL連結,它們必須首先獲取網頁內容,檢查這個頁面的內容,在尋找另外一個URL,然後後獲取URL對應的網頁內容,不斷迴圈這一過程。不過要注意的是:你可以這樣重複採集網頁,但不意味著你一直都應該這麼做。當你需要的所有資料都在一個頁面上時,前面例子中的爬蟲就足以解決問題了。使用網路爬蟲的時候,你必須非常謹慎地考慮需要消耗多少網路流量,還要經歷思考能不能讓採集目標伺服器負載更低一些。

      在本篇博文中,我們將建立一個專案來實現“維基百科六度分隔理論”的查詢方法。也就是說,我們要實現從埃裡克.艾德爾的詞條頁面(https://en.wikipedia.org/wiki/Eric_Idle)開始,經過最少的連結點選找到凱文.貝肯的詞條介面(https://en.wikipedia.org/wiki/Kevin_Bacon)。

     你應該已經知道如何寫一段獲取維基百科網站任何頁面並提取頁面連結的Python程式碼了:

from urllib.request import urlopen
from bs4 import BeautifulSoup
html=urlopen("https://en.wikipedia.org/wiki/Eric_Idle")
bsObj=BeautifulSoup(html,"html.parser")
for link in bsObj.findAll("a"):
      if 'href' in link.attrs:
          print(link.attrs['href'])
     你會發現結果為一系列的連結,其中有些是我們需要的,有些不是我們需要的。其實維基百科的每個頁面都充滿了側邊欄、頁首、頁尾連結,以及連線到分類頁面、對話頁面和其他不包含詞條的頁面的連結。經過對採集頁面的分析,發現那些指向詞條頁面(不是指向其他內容頁面)的連結,會發現他們有三個特點:

     1.它們都在id是bodyContent的div標籤裡

     2.URL連結不包含分號

     3.URL連結都已/wiki/開頭

      因此我們可以稍微調整程式碼來獲取詞條連結

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
html=urlopen("https://en.wikipedia.org/wiki/Eric_Idle")
bsObj=BeautifulSoup(html,"html.parser")
for link in bsObj.find("div",{"id":"bodyContent"}).findAll("a",href=re.compile("^(/wiki/)((?!:).)*$")):
      if 'href' in link.attrs:
          print(link.attrs['href'])
    執行後,就會看到維基百科上埃裡克.艾德爾詞條裡所有指向其他詞條的連結

    當然,寫程式來找出這個靜態的維基百科詞條裡所有的詞條連結很有趣,不過沒有什麼實際用處。我們需要讓這段程式更像下面的形式:

    1.一個函式getLinks,可以用維基百科詞條/wiki/<詞條名稱>形式的URL連結作為引數,然後以同樣的形式返回一個列表,裡面包含所有的詞條URL連結。

    2. 一個主函式,以某個起始詞條為引數呼叫getLinks,再從返回的URL列表裡隨機選擇一個詞條連結,再呼叫getLinks,直到我們主動停止,或者在新的介面上沒有詞條連結了,程式才停止執行。

from urllib.request import urlopen
from bs4 import BeautifulSoup
import datetime
import random
import re
random.seed(datetime.datetime.now())

def getLinks(articleUrl):
    html=urlopen("https://en.wikipedia.org"+articleUrl)
    bsObj=BeautifulSoup(html,"html.parser")
    return bsObj.find("div",{"id":"bodyContent"}).findAll("a",href=re.compile("^(/wiki/)((?!:).)*$"))

links=getLinks("/wiki/Kevin_Bacon")

while len(links)>0:
    newArticle=links[random.randint(0,len(links)-1)].attrs["href"]
    print(newArticle)
    links=getLinks(newArticle)
    執行結果如下圖所示:


如果不手動停止,程式會一直執行到頁面上沒有詞條連結為止。匯入需要的Python庫後,程式首先做的是用系統的當前時間生成一個隨機數生成器。這樣可以保證在每次程式執行的時候,維基百科詞條的選擇都是一個全新的隨機路徑。

     然後我們定義了getLinks函式,其引數是維基百科詞條頁面中的/wiki/<詞條名稱>形式的URL連結,前面加上維基百科的域名,http://en.wikipedia.org,再用域名中的網頁獲取一個BeautifulSoup物件。之後用前面介紹過的慘呼抽取一列詞條連結所在的標籤a並返回它們。

     程式的主程式首先把起始頁面:https://en.wikipedia.org/wiki/Kevin_Bacon裡的詞條連結列表(links變數)設定成連結列表。然後用一個迴圈,從頁面中隨機找一個詞條連結標籤並抽取href屬性,列印這個頁面連結,再把這個連結傳入getLinks函式,重新獲取新的連結列表。當然,這裡只是簡單地構建一個從一個頁面到另外一個頁面的爬蟲,要解決“維基百科六度分隔理論”問題還有一點工作要做。我們還應該儲存URL連結資料並分析資料。後續會有博文繼續介紹。同時在本博文中,程式的編寫時需要注意一樣處理的問題,參考前面的構建穩定連結的內容修改程式,增加異常處理的部分。