Python分散式爬蟲!你以為你會了嗎?你看看這篇教程!萬字長文!
背景
一、前沿
1.1 爬蟲是什麼?
網路爬蟲(又被稱為網頁蜘蛛,網路機器人,在FOAF社群中間,更經常的稱為網頁追逐者),是一種按照一定的規則,自動的抓取全球資訊網資訊的程式或者指令碼。
1.2 為什麼是Python?
簡單易學:簡單到沒有學習過任何程式語言的人稍微看下資料就能編寫出爬蟲 解釋型程式語言:編寫完後可以直接執行,無須編譯
程式碼重用性高:可以直接把包含某個功能的模組帶入其它程式中使用
跨平臺性:幾乎所有的python程式都可以不加修改的執行在不同的作業系統
從零基礎到專案實戰視訊獲取地址群:125240963
2.2 URL 的含義
概念:
URL(協議(服務方式) + IP地址(包括埠號) + 具體地址),即統一資源定位符,也就是我們說的網址,統一資源定位符是對可以從網際網路上得到的資源的位置和訪問方法的一種簡潔的表示,是網際網路上標準資源的地址。網際網路上的每個檔案都有一個唯一的URL,它包含的資訊指出檔案的位置以及瀏覽器應該怎麼處理它。爬蟲爬取資料時必須要有一個目標的URL才可以獲取資料,因此,它是爬蟲獲取資料的基本依據。
相關:
URI = Universal Resource Identifier 統一資源標誌符
URL = Universal Resource Locator 統一資源定位符
URN = Universal Resource Name 統一資源名稱
2.4 代理基本原理
2.4.1基本原理
在本機和伺服器之間搭建了一個橋,此時本機不是直接向 Web 伺服器發起請求,而是向代理伺服器發出請求,這個過程 Web 伺服器識別出的真實的 IP 就不再是我們本機的 IP 了,就成功實現了 IP 偽裝,這就是代理的基本原理
2.4.2代理的作用
1、突破自身 IP 訪問限制,訪問一些平時不能訪問的站點
2、訪問一些單位或團體內部資源
3、隱藏真實 IP
2.4.3爬蟲代理
在爬取過程中可能遇到同一個 IP 訪問過於頻繁的問題,網站就會讓我們輸入驗證碼或登入或者直接封鎖 IP,這樣會給爬取帶來極大的不便。讓伺服器誤以為是代理伺服器的在請求自己。這樣在爬取過程中通過不斷更換代理,就不會被封鎖,可以達到很好的爬取效果
三、爬蟲入門
3.2 一個入門栗子
其它策略
Timeout設定
3.4 動態渲染頁面抓取
Splash 是一個 JavaScript 渲染服務,是一個帶有 HTTP API 的輕量級瀏覽器,同時它對接了 Python 中的 Twisted 和 QT 庫,利用它我們同樣可以實現動態渲染頁面的抓取。
非同步方式處理多個網頁渲染過程
獲取渲染後的頁面的原始碼或截圖
通過關閉圖片渲染或者使用 Adblock 規則來加快頁面渲染速度
可執行特定的 JavaScript 指令碼
可通過 Lua 指令碼來控制頁面渲染過程
獲取渲染的詳細過程並通過 HAR(HTTP Archive)格式呈現
3.5 爬蟲完整流程
四、爬蟲框架
4.1 PySpider簡介
一個國人編寫的強大的網路爬蟲系統並帶有強大的WebUI。採用Python語言編寫,分散式架構,支援多種資料庫後端,強大的WebUI支援指令碼編輯器,任務監視器,專案管理器以及結果檢視器
4.3 Scrapy簡介
Scrapy是一個為了爬取網站資料,提取結構性資料而編寫的應用框架。 可以應用在包括資料探勘,資訊處理或儲存歷史資料等一系列的程式中。
5.3 scrapy專案指令
crawl:使用spider進行爬取
check:檢查專案是否有錯
list: 列出當前專案中所有可用的spider,每行輸出一個spider
edit:僅僅是提供一個快捷方式。開發者可以自由選擇其他工具或者IDE來編寫除錯spiderparse
parse:獲取給定的URL並使用相應的spider分析處理
bench:執行benchmark測試
5.4 scrapy選擇器
BeautifulSoup 是在程式設計師間非常流行的網頁分析庫,它基於HTML程式碼的結構來構造一個Python物件, 對不良標記的處理也非常合理,但它有一個缺點:慢。
lxml 是一個基於 ElementTree (不是Python標準庫的一部分)的python化的XML解析庫(也可以解析HTML)。
Scrapy提取資料有自己的一套機制。它們被稱作選擇器(seletors),因為他們通過特定的 XPath 或者 CSS 表示式來“選擇” HTML檔案中的某個部分。
XPath 是一門用來在XML檔案中選擇節點的語言,也可以用在HTML上。
CSS 是一門將HTML文件樣式化的語言。選擇器由它定義,並與特定的HTML元素的樣式相關連。
Scrapy選擇器構建於 lxml 庫之上,這意味著它們在速度和解析準確性上非常相似
屬性
name: 定義spider名字的字串(string)
allowed_domains: 包含了 spider 允許爬取的域名(domain)列表(list)
start_urls: URL列表。當沒有制定特定的URL時,spider將從該列表中開始進行爬取
custom_settings: 該設定是一個dict.當啟動spider時,該設定將會覆蓋專案級的設定. 由於設定必須在初始化(instantiation)前被更新,所以該屬性 必須定義為class屬性
crawler: 該屬性在初始化class後,由類方法 from_crawler() 設定, 並且連結了本spider例項對應的 Crawler 物件
settings: crawler 的配置管理器,擴充套件(extensions)和中介軟體(middlewares)使用它用來訪問 Scrapy 的配置
logger: self.logger.info('日誌:%s', response.status)
方法
from_crawler: 如果存在,則呼叫此類方法以從 Crawler 建立 pipeline 例項。它必須返回一個新的pipeline例項。 Crawler 物件提供對所有 Scrapy 核心元件(如settings 和 signals)的訪問; 它是 pipeline 訪問它們並將其功能掛鉤到Scrapy中的一種方法
start_requests: 該方法必須返回一個可迭代物件(iterable)。該物件包含了spider用於爬取的第一個Request
make_requests_from_url: 該方法接受一個URL並返回用於爬取的 Request 物件
parse: 當response沒有指定回撥函式時,該方法是Scrapy處理下載的response的預設方法
log: 使用 scrapy.log.msg() 方法記錄(log)message
closed: 當spider關閉時,該函式被呼叫
5.6 Item Pipeline
當 Item 在 Spider 中被收集之後,它將會被傳遞到Item Pipeline,一些元件會按照一定的順序執行對Item的處理。每個item pipeline元件(有時稱之為“Item Pipeline”)是實現了簡單方法的Python類。他們接收到Item並通過它執行一些行為,同時也決定此Item是否繼續通過pipeline,或是被丟棄而不再進行處理。
六、scrapy 搭建專案
6.1 爬蟲思路
6.2 實際專案分析
專案結構
七、分散式爬蟲
7.1 單主機爬蟲架構
本機維護一個爬蟲佇列,scheduler 進行排程
Q:多臺主機協作的關鍵是什麼?
A:共享爬蟲佇列
單主機爬蟲架構
7.2 分散式爬蟲架構
image
分散式爬蟲架構
7.3 問題
Q1:佇列怎麼選?
A1: Redis佇列
Redis 非關係型資料庫,key-value形式儲存,結構靈活
是記憶體中的資料結構儲存系統,處理速度快,效能好
提供佇列、集合等多種儲存結構,方便佇列維護
Q2:怎麼去重?
A2:Redis集合
Redis 提供集合資料結構,在redis集合中儲存每個request的指紋
在向redis集合中儲存request指紋的時候,先驗證指紋是否存在?
[如果存在]:則不新增request到佇列
[不存在]:則將request加入佇列,並將指紋加入集合
Q3:怎樣防止中斷?
A3:啟動判斷
在每臺從機 scrapy 啟動時 都會首先判斷當前 redis reqeust佇列是否為空
[不為空]:從佇列中取得下一個 request ,進行執行爬蟲
[空]:重新開始爬取,第一臺從機執行爬取向佇列中新增request
Q4:怎樣實現該架構?
A4:Scrapy-Redis
scrapy是Python的一個非常好用的爬蟲框架,功能非常強大,但是當我們要爬取的頁面非常多的時候,單個主機的處理能力就不能滿足我們的需求了(無論是處理速度還是網路請求的併發數),這時候分散式爬蟲的優勢就顯現出來,人多力量大。而scrapy-Redis就是結合了分散式資料庫redis,重寫了scrapy一些比較關鍵的程式碼(scrapy的排程器、佇列等元件),將scrapy變成一個可以在多個主機上同時執行的分散式爬蟲。
github地址:https://github.com/rmax/scrapy-redis
7.4 原始碼解讀
閱讀原始碼前:需要了解 scrapy 的執行原理,否則並沒什麼用。
scrapy-redis 工程的主體還是 redis 和 scrapy 兩個庫,將兩個庫的核心功能結合,實現分散式。
1 connection.py
負責根據setting中配置例項化redis連線。被dupefilter和scheduler呼叫,總之涉及到redis存取的都要使用到這個模組
2 dupefilter.py
通過繼承 BaseDupeFilter 重寫他的方法,實現了基於redis的 request 判重。scrapy-redis使用 redis的一個 set 中插入 fingerprint(不同spider的key不同)
spider名字+DupeFilter的key就是為了在不同主機上的不同爬蟲例項,只要屬於同一種spider,就會訪問到同一個set,而這個set就是他們的url判重池 。
DupeFilter 判重會在 scheduler 類中用到,每一個request在進入排程之前都要進行判重,如果重複就不需要參加排程,直接捨棄就好了
image
3 picklecompat.py
loads 和 dumps 兩個函式,其實就是實現了一個 serializer,因為 redis 資料庫不能儲存複雜物件(value部分只能是字串,字串列表,字串集合和hash,key部分只能是字串),所以儲存前需要先序列化成文字才行
這個 serializer 主要用於 scheduler 存 reuqest 物件。
為什麼不用json格式?(item pipeline 的序列化預設用的就是 json)
4 pipelines.py
pipeline 檔案實現了一個 item pipieline 類,和 scrapy 的 item pipeline 是同一個物件,從settings中獲取我們配置的REDISITEMSKEY作為key,把item序列化之後存入redis資料庫對應的value中(這個value是list,我們的每個item是這個list中的一個結點),這個pipeline把提取出的item存起來,主要是為了方便我們延後處理資料。
7 spider.py
設計的這個spider從redis中讀取要爬的url,然後執行爬取,若爬取過程中返回更多的url,那麼繼續進行直至所有的request完成。之後繼續從redis中讀取url,迴圈這個過程。
分析:在這個spider中通過connect signals.spideridle訊號實現對crawler狀態的監視。當idle時,返回新的makerequestsfromurl(url)給引擎,進而交給排程器排程。