教材:《Web Scraping with Python——Collecting Data from the Modern Web》? 2015 by Ryan Mitchell
之所以叫網絡爬蟲(Web crawler),是因為它們可以沿著網絡爬行。本質就是一種遞歸方式。為了找到 URL 鏈接,爬蟲必須首先獲取網頁內容,檢查這個頁面的內容,再尋找另一個 URL,然后獲取 URL 對應的網頁內容,不斷循環這一過程。
提取頁面鏈接:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://en.wikipedia.org/wiki/Kevin_Bacon")
bsObj = BeautifulSoup(html)
for link in bsObj.findAll("a"):
? ? if 'href' in link.attrs:
? ? print(link.attrs['href'])
過濾多余的連接:
以僅提取“詞條鏈接”為例,相比于“其他鏈接”,“詞條鏈接”:
? 都在 id 是 bodyContent 的 div 標簽里?
? URL 鏈接不包含分號
? URL 鏈接都以 /wiki/ 開頭
——利用find()方法和正則表達式過濾“其他鏈接”:
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("http://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 的集合 set 類型)。只有“新”鏈接才會被采集,之后再從頁面中搜索其他鏈接:
遍歷首頁上每個鏈接,并檢查是否已經在全局變量集合 pages 里面了(已經采集的頁面集合)。如果不在,就打印到屏幕上,并把鏈接加入pages 集合,再用 getLinks 遞歸地處理這個鏈接。
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
pages = set()
def getLinks(pageUrl):
global pages
html = urlopen("http://en.wikipedia.org"+pageUrl)
bsObj = BeautifulSoup(html)
for link in bsObj.findAll("a", href=re.compile("^(/wiki/)")):
if 'href' in link.attrs:
if link.attrs['href'] not in pages:
# we meet the new page
newPage = link.attrs['href']
print(newPage)
pages.add(newPage)
getLinks(newPage)
getLinks("")
收集整個網站數據的組合程序:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
pages = set()
def getLinks(pageUrl):
global pages
html = urlopen("http://en.wikipedia.org"+pageUrl)
bsObj = BeautifulSoup(html, "html.parser")
try:
print(bsObj.h1.get_text())
print(bsObj.find(id ="mw-content-text").findAll("p")[0])
print(bsObj.find(id="ca-edit").find("span").find("a").attrs['href'])
except AttributeError:
print("This page is missing something! No worries though!")
for link in bsObj.findAll("a", href=re.compile("^(/wiki/)")):
if 'href' in link.attrs:
if link.attrs['href'] not in pages:
#We have encountered a new page
newPage = link.attrs['href']
print("----------------\n"+newPage)
pages.add(newPage)
getLinks(newPage)
getLinks("")