Python 領域運用:網絡爬蟲
1. 爬蟲簡介
網絡爬蟲,又稱為網頁蜘蛛,是一種按照一定的規(guī)則、自動地抓取萬維網信息的程序。爬蟲是一個自動下載網頁的程序,它有選擇的訪問萬維網上的網頁與相關的鏈接,獲取所需要的信息。
爬蟲有著廣泛的應用:
- 搜索引擎,谷歌百度等搜索引擎使用爬蟲抓取網站的頁面
- 輿情分析與數據挖掘,通過抓取微博排行榜的文章,掌握輿情動向
- 數據聚合,比如企查查,抓取企業(yè)官網的詳細信息
- 導購、價格比對,通過抓取購物網站的商品頁面獲取商品價格,為買家提供價格參考
在面向計算機專業(yè)的人才招聘市場上,以爬蟲為關鍵字搜索,可以獲得大量的職位招聘:
2. 爬蟲的工作原理
爬蟲的工作原理如下:
- 從一個或若干初始網頁的 URL 開始
- 自動下載初始網頁上的 HTML 文件
- 分析 HTML 文件中包含的鏈接,爬取鏈接指向的網頁
- 不斷重復以上過程,直到達到某個條件時停止
下面以爬取慕課網的 wiki 為例,說明爬蟲的工作原理:
-
排蟲程序選擇 http://idcbgp.cn/wiki 作為入口
-
下載網頁 http://idcbgp.cn/wiki 的內容,大致如下:
<html data-n-head-ssr>
<head >
<title>慕課網教程丨Wiki寶典</title>
<meta name="description" content="慕課網wiki教程平臺">
</head>
<body>
<div>
<div class="text">
<a href="/wiki/Javascriptbase">JavaScript 入門教程</a>
<p><span>58小節(jié)</span>
</div>
<div class="text">
<a href="/wiki/typescriptlession">TypeScript 入門教程</a>
<p><span>38小節(jié)</span>
</div>
<div class="text">
<a href="/wiki/vuelession">Vue 入門教程</a>
<p><span>39小節(jié)</span>
</div>
</div>
</body>
</html>
- 分析 HTML 文件中的 a 標簽,發(fā)現有如下 3 個 a 標簽
- <a href="/wiki/Javascriptbase">JavaScript 入門教程</a>
- <a href="/wiki/typescriptlession">TypeScript 入門教程</a>
- <a href="/wiki/vuelession">Vue 入門教程</a>
-
爬蟲爬取以上 3 個 a 標簽中的鏈接
-
不斷重復以上步驟,可以將慕課網的全部 wiki 文章抓取到本地
3. 爬蟲入門
3.1 基本的爬取技術
在互聯網早期,網站的內容以靜態(tài)的 HTML 文件為主,不帶任何反爬蟲措施。比如,要爬取某個博客站點的全部文章,首先獲取網站的首頁,就順著首頁的鏈接爬到文章頁,再把文章的時間、作者、正文等信息保存下來。
使用 Python 的 requests 庫就可以爬取由靜態(tài)網頁構成的網站:
- 使用 requests 庫下載指定 URL 的網頁
- 使用 XPath、BeautifulSoup 或者 PyQuery 對下載的 HTML 文件進行解析
- 獲取 HTML 文件中特定的字段,例如文章的時間、標題等信息,將它們保存
- 獲取 HTML 文件中包含的鏈接,并順著鏈接爬取內容
- 爬取到數據后,可以使用 MySQL、MongoDB 等來保存數據,實現持久化存儲,同時方便以后的查詢操作
3.2 爬取客戶端渲染的網頁
在互聯網早期,網站的內容都是一些簡單的、靜態(tài)的頁面,服務器后端生成網頁內容,然后返回給瀏覽器,瀏覽器獲取 html 文件之后就可以直接解析展示了,這種生成 HTML 文件的方式被稱為服務器端渲染。
而隨著前端頁面的復雜性提高,出現了基于 ajax 技術的前后端分離的開發(fā)模式,即后端不提供完整的 html 頁面,而是提供一些 api 返回 json 格式的數據,前端調用后端的 API 獲取 json 數據,在前端進行 html 頁面的拼接,最后后展示在瀏覽器上,這種生成 HTML 文件的方式被稱為客戶端渲染。
簡單的使用 requests 庫無法爬取客戶端渲染的頁面:
- requests 爬下來的頁面內容并不包含真正的數據
- 只能通過調用后端的 API 才能獲取頁面的數據
有兩種方式爬取客戶端渲染的網頁:
- 分析網頁的調用后端 API 的接口
這種方法需要分析網站的 JavaScript 邏輯,找到調用后端 API 的的代碼,分析 API 的相關參數。分析后再用爬蟲模擬模擬調用后端 API,從而獲取真正的數據。
很多情況下,后端 API 的接口接口帶著加密參數,有可能花很長時間也無法破解,從而無法調用后端 API。
- 用模擬瀏覽器的方式來爬取數據
在無法解析后端 API 的調用方式的情況下,有一種簡單粗暴的方法:直接用模擬瀏覽器的方式來爬取,比如用 Selenium、Splash 等庫模擬瀏覽器瀏覽網頁,這樣爬取到的網頁內容包含有真實的數據。這種方法繞過分析 JavaScript 代碼邏輯的過程,大大降低了難度。
3.3 爬蟲相關的庫和框架
- 實現 HTTP 請求操作
- urllib:提供操作 URL 的功能
- requests:基于 urllib 的 HTTP 請求庫,發(fā)出一個 HTTP 請求,等待服務器響應的網頁
- selenium:自動化測試工具,通過這個庫調用瀏覽器完成某些操作,比如輸入驗證碼
- 從網頁中提取信息
- beautifulsoup:對 html 和 XML 進行解析,從網頁中提取信息
- pyquery:jQuery 的 Python 實現,能夠以 jQuery 的語法來操作解析 HTML 文檔
- lxml:對 html 和 XML 進行解析,支持 XPath 解析方式
- tesserocr:一個 OCR 庫,在遇到驗證碼的時候,可使用該庫進行識別
- 爬蟲框架
-
Scrapy:Scrapy 是用 python 實現的一個為了爬取網站數據,提取結構性數據而編寫的應用框架。用這個框架可以輕松爬下來如亞馬遜商品信息之類的數據
-
PySpider: pyspider 是用 python 實現的功能強大的網絡爬蟲系統(tǒng),能在瀏覽器界面上進行腳本的編寫和爬取結果的實時查看,后端使用常用的數據庫進行爬取結果的存儲,還能定時設置任務與任務優(yōu)先級等
-
Newpaper: Newspaper可以用來提取新聞、文章和內容分析
4. 提升爬蟲的效率
4.1 多任務爬蟲
爬蟲是 IO 密集型的任務,大多數情況下,爬蟲都在等待網絡的響應。如果使用用單線程的爬蟲來抓取數據,爬蟲必須等待當前頁面抓取完畢后,才能請求抓取下一個網頁。大型網站包含有數十萬的網頁,使用單線程抓取網頁的速度是無法接受的。
使用多進程或者多線程的技術,爬蟲可以同時請求多個網頁,可以成倍地提高爬取速度。
假設爬蟲需要獲取 baidu.com、taobao.com、qq.com 首頁,通過使用多線程技術,可以并行的抓取網頁,代碼如下:
import requests
import threading
def fetch(url):
response = requests.get(url)
print('Get %s: %s' % (url, response))
t0 = threading.Thread(target = fetch, args = ("https://www.baidu.com/",))
t1 = threading.Thread(target = fetch, args = ("https://www.taobao.com/",))
t2 = threading.Thread(target = fetch, args = ("https://www.qq.com/",))
t0.start()
t1.start()
t2.start()
t0.join()
t1.join()
t2.join()
- 函數 fetch,函數 fetch 獲取指定 url 的網頁
- 創(chuàng)建 3 個線程
- 線程 t0 調用 fetch 獲取 baidu.com 首頁
- 線程 t1 調用 fetch 獲取 taobao.com 首頁
- 線程 t2 調用 fetch 獲取 qq.com 首頁
- 線程是并行執(zhí)行的,可以將抓取速度提高為原來的 3 倍
4.2 分布式爬蟲
多線程、多進程能加速爬取速度,但終究還是單機的爬蟲,性能提升有限。要爬取超大規(guī)模的網站,需要使用分布式爬蟲。分布式爬蟲把爬蟲的關鍵功能部署到多臺機器上,多臺機器同時爬取數據。
下圖展示了一種典型的分布式爬蟲的架構:
- 分布式爬蟲的功能由 4 臺機器承擔:1 臺 master 和 3 臺 slave
- 分布式爬蟲的關鍵是共享一個請求隊列,請求隊列保存了需要爬取的網頁的 URL 地址
- 維護該隊列的主機稱為 master
- 負責數據的抓取、數據處理和數據存儲的主機稱為 slave
- master 負責管理 slave 連接、任務調度與分發(fā)、結果回收并匯總等
- slave 從 master 那里領取任務,并獨自完成任務最后上傳結果