天天看點

scrapy-redis實作分布式爬蟲詳解

scrapy-redis分布式爬蟲架構詳解

随着網際網路技術的發展與應用的普及,網絡作為資訊的載體,已經成為社會大衆參與社會生活的一種重要資訊管道。由于網際網路是開放的,每個人都可以在網絡上發表資訊,内容涉及各個方面。小到心情日志,大到國家大事。

網際網路已成為思想文化資訊的集散地,并具有傳統媒體無法相比的優勢:便捷性,虛拟性,互動性,多元性。網絡新聞熱點通常形成迅速,多是人們對于日常生活中的各種問題發表的各種意見,評論,态度,情緒等,随着事件的發展而變化,是反映社會熱點的重要載體之一。

相比較而言,編寫爬蟲程式擷取到的海量資料更為真實、全面,在資訊繁榮的網際網路時代更為行之有效。是以編寫爬蟲程式成為大資料時代資訊收集的必備技能。

本文主要介紹爬蟲收集資料優點、爬蟲原理、scrapy爬蟲架構,并以新聞爬取為例,詳細講解使用scrapy爬取資料的步驟以及scrapy-redis分布式。

一、爬蟲收集資料的優點

大資料時代下,人類社會的資料正以前所未有的速度增長,傳統的擷取資料的方式如問卷調查、訪談法等,其樣本容量小、信度低、且受經費和地域範圍所限,因而收集的資料往往無法客觀反映研究對象,有着較大的局限性。

以不能滿足高品質研究的需求。正如Ivor的理論所揭示的,如果輸入的是無效資訊,無論處理的程式如何精良,輸出的都是無用資訊“Garbage In,Garbage Out”。可見,對比傳統的資料收集方法,立足于海量資料的研究有以下的優點:

(一)資料的真實性

資料的真實性,使用問卷調查法收集的資料,調查者難以了解被調查者是認真填寫還是敷衍了事。使得得到的資料真實性不可靠,而通過爬蟲技術能快速擷取真實、客觀的使用者資訊,如在社交網絡上對一個公司的評價顯然要比問卷調查真實,淘寶、美團上消費者對賣家的評論就比較客觀的反應了商品的品質。

(二)樣本容量

人類當初發明計算機是因為在二戰時期工程師們已經無法計算飛彈的飛行軌迹,龐大的計算量迫使了計算機的發明,可見計算機天生就是來處理大規模批量的資料,把人們從繁重的勞動中解放出來。在同樣的成本下,人工采集和計算機采集的資料量不是一個量級的,爬蟲可以對網際網路上的海量資料進行收集、分析,能更好的反應客觀事實,而資料越全面,分析研究的結果也就越真實。

二、爬蟲原理

網絡爬蟲(Web crawler),是一種按照一定的規則,自動地抓取網際網路資訊的程式或者腳本,我們浏覽的網頁數以億計,它們在世界各地的伺服器上存儲着。使用者點選一個網頁的超連結以跳轉的方式來擷取另一個頁面的資訊,而跳轉的頁面又有連結存在,網頁便由超連結組成一個巨大且錯綜複雜的網。而Web爬蟲(Crawler),也稱蜘蛛(Spider),則是穿梭在這巨大的網際網路中下載下傳網頁解析内容的程式。它們被廣泛用于網際網路搜尋引擎,可以自動采集所有其能夠通路到的頁面内容,以擷取或更新這些網站的内容和檢索方式。

(一)爬蟲的應用

在商務智能上,企業使用爬蟲收集競争對手的情報或在社交網絡、虛拟社群上爬取使用者對企業的評價進而在産品服務上做出改進等。在資料研究上,爬蟲能快速收集網際網路上的資訊,為資料分析提供原始資料。

(二)爬蟲算法流程

從功能上來講,爬蟲一般分為資料采集,處理,儲存三個部分。傳統爬蟲從一個或若幹初始網頁的URL開始,獲得初始網頁上的URL,在抓取網頁的過程中,不斷從目前頁面上抽取新的URL放入隊列,直到滿足系統的一定停止條件。聚焦爬蟲的工作流程較為複雜,需要根據一定的網頁分析算法過濾與主題無關的連結,保留有用的連結将其放入等待抓取的URL隊列。然後,它将根據一定的搜尋政策從隊列中選擇下一步要抓取的網頁URL,并重複上述過程,直到達到系統的某一條件時停止。另外,所有被爬蟲抓取的網頁将會被系統存貯,進行一定的分析、過濾,并建立索引,以便之後的查詢和檢索;對于聚焦爬蟲來說,這一過程所得到的分析結果還可能對以後的抓取過程給出回報和指導。

scrapy-redis實作分布式爬蟲詳解

三、scrapy爬蟲架構

Scrapy是一個為了爬取網站資料,提取結構性資料而編寫的應用架構。可以應用在包括資料挖掘,資訊處理或存儲曆史資料等一系列的程式中。其最初是為了頁面抓取 (更确切來說, 網絡抓取 )所設計的, 也可以應用在擷取API所傳回的資料(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。Scrapy用途廣泛,可以用于資料挖掘、監測和自動化測試。

(一)scrapy整體架構圖

![在這裡插入圖檔描述

scrapy-redis實作分布式爬蟲詳解
圖2:scrapy架構圖
           

(二)Scrapy主要元件

1、引擎(Scrapy): 用來處理整個系統的資料流處理, 觸發事務(架構核心)。

2、排程器(Scheduler): 用來接受引擎發過來的請求, 壓入隊列中, 并在引擎再次請求的時候傳回. 可以想像成一個URL(抓取網頁的網址或者說是連結)的優先隊列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址。

3、下載下傳器(Downloader): 用于下載下傳網頁内容, 并将網頁内容傳回給蜘蛛(Scrapy下載下傳器是建立在twisted這個高效的異步模型上的)。

4、爬蟲(Spiders): 爬蟲是主要幹活的, 用于從特定的網頁中提取自己需要的資訊, 即所謂的實體(Item)。使用者也可以從中提取對外連結接,讓Scrapy繼續抓取下一個頁面。

5、項目管道(Pipeline): 負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證明體的有效性、清除不需要的資訊。當頁面被爬蟲解析後,将被發送到項目管道,并經過幾個特定的次序處理資料。

6、下載下傳器中間件(Downloader Middlewares): 位于Scrapy引擎和下載下傳器之間的架構,主要是處理Scrapy引擎與下載下傳器之間的請求及響應。

7、爬蟲中間件(Spider Middlewares): 介于Scrapy引擎和爬蟲之間的架構,主要工作是處理蜘蛛的響應輸入和請求輸出。

8、排程中間件(Scheduler Middewares): 介于Scrapy引擎和排程之間的中間件,從Scrapy引擎發送到排程的請求和響應。

四、爬蟲實戰項目

(一)scrapy安裝

Scrapy架構官方網址:http://doc.scrapy.org/en/latest

Scrapy中文維護站點:http://scrapy-chs.readthedocs…

1、Ubuntu下安裝

sudo pip install scrapy

2、mac下安裝

sudo pip install scrapy

3、Windows下安裝

Windows下安裝scrapy會出現各種依賴和不相容,個人建議先安裝anaconda,它是一個開源的、免費的python類庫的集合,貌似一下就安裝了200+的包,各種依賴包各種搞定,專治各種不服。anaconda下載下傳連結。

安裝指令: conda install scrapy

4、安裝後,隻要在指令終端輸入 scrapy,提示類似以下結果,代表已經安裝成功

scrapy-redis實作分布式爬蟲詳解
上圖為 scrapy安裝成功 
           

(二)建立scrapy項目(scrapy startproject)

在開始爬取之前,必須建立一個新的Scrapy項目。進入自定義的項目目錄中,運作下列指令,指令執行完後程式目錄結構大緻如下:

scrapy startproject tutorial    #建立項目
           
scrapy-redis實作分布式爬蟲詳解
上圖為目錄結構圖
           

下面來簡單介紹一下各個主要檔案的作用:

scrapy.cfg:項目的配置檔案

tutorial/:項目的Python子產品,将會從這裡引用代碼

tutorial/items.py:項目的字段定義檔案

tutorial/pipelines.py:項目的管道檔案

tutorial/settings.py:項目的設定檔案

tutorial/spiders/:存儲爬蟲代碼目錄

(三)定義存儲對象(tutorial/items.py)

Items是裝載我們抓取資料的容器。它們工作像簡單的Python字典,它提供更多的保護,比如對未定義的字段提供填充功能防止出錯.

Itmes.py:
           
scrapy-redis實作分布式爬蟲詳解

(四)制作爬蟲 (tutorial/spiders/)

1、在目前目錄下輸入指令,将在tutorial/spider目錄下建立一個名為hsw的爬蟲,并指定爬取域的範圍:

`scrapy genspider hsw "hsw.cn"`   #建立爬蟲
           

2、打開 tutorial/spider目錄裡的 hsw.py,預設增加了下列代碼:

hsw.py:
           
scrapy-redis實作分布式爬蟲詳解

3、要建立一個Spider, 你必須用scrapy.Spider類建立一個子類,并确定了三個強制的屬性 和 一個方法。

(1) name ="":這個爬蟲的識别名稱,必須是唯一的,在不同的爬蟲必須定義不同的名字。

(2) allow_domains=[]是搜尋的域名範圍,也就是爬蟲的限制區域,規定爬蟲隻爬取這個域名下的網頁,不存在的URL會被忽略。

(3) start_urls=():爬取的URL元祖/清單。爬蟲從這裡開始抓取資料,是以,第一次下載下傳的資料将會從這些urls開始。其他子URL将會從這些起始URL中繼承性生成。

(4) parse(self,

response):解析的方法,每個初始URL完成下載下傳後将被調用,調用的時候傳入從每一個URL傳回的Response對象來作為唯一參數,主要作用如下:

a) 負責解析傳回的網頁資料(response.body),提取結構化資料(生成item) b) 生成需要下一頁的URL請求。

4、修改parse方法,添加parse_item方法

現在我們修改hsw.py檔案将start_urls的值修改為需要爬取的第一個url

start_urls = [“http://finance.hsw.cn/hyxw/index.shtml”]

這裡先簡單介紹下xpath文法(詳見官方文檔:http://www.w3school.com.cn/xm…)

表示選擇所有含有屬性class等于listleft的dev元素下方的ul->li->h3下方a标簽的herf屬性,取清單頁所有内容頁url。

(2) //div[@class=“hd”]/h1/text()

表示選擇所有含有屬性class等于hd的dev元素下方的h1标簽,取文章标題。

(3) //div[@class=“photoarea”]//p/text()|//div[@class=“contentBox

cf”]//p/text() 同上,由于網頁中存在多種不同的頁面結構,需要相容,故使用“|”文法,表示或的意思,取文章正文。

(4) //span[@class=“article-time”]/text() 文法同上,取文章的釋出時間。

scrapy-redis實作分布式爬蟲詳解

5、然後運作一下看看,在tutorial目錄下執行:

scrapy crawl hws -o hws.csv
           

scrapy儲存資訊的最簡單的方法主要有四種,-o 輸出指定格式的檔案,指令如下:

json格式,預設為Unicode編碼:

scrapy crawl hws -o hws.json
           

json lines格式,預設為Unicode編碼:

scrapy crawl hws -o hws.jsonl
           

csv 逗号表達式,可用Excel打開:

scrapy crawl hws -o hws.csv
           

xml格式:

scrapy crawl hws -o hws.xml
           

五、scrapy-redis分布式

scrapy是python界出名的一個爬蟲架構。Scrapy是一個為了爬取網站資料,提取結構性資料而編寫的應用架構。可以應用在包括資料挖掘,資訊處理或存儲曆史資料等一系列的程式中。

雖然scrapy能做的事情很多,但是要做到大規模的分布式應用則捉襟見肘。有能人改變了scrapy的隊列排程,将起始的網址從start_urls裡分離出來,改為從redis讀取,多個用戶端可以同時讀取同一個redis,進而實作了分布式的爬蟲。

(一)scrapy-redis安裝

安裝:pip install scrapy-redis 官方站點:https://github.com/rolando/scrapy-redis
           

(二)scrapy-redis架構

scrapy-redis實作分布式爬蟲詳解

(三)scrapy-Redis元件詳解

如上圖所示,scrapy-redis在scrapy的架構上增加了redis,基于redis的特性拓展了如下四種元件:Scheduler,Duplication Filter,Item Pipeline,Base Spider

1、Scheduler: scrapy改造了python本來的collection.deque(雙向隊列)形成了自己的Scrapy

queue,但是Scrapy多個spider不能共享待爬取隊列Scrapy

queue,即Scrapy本身不支援爬蟲分布式,scrapy-redis 的解決是把這個Scrapy

queue換成redis資料庫(也是指redis隊列),從同一個redis-server存放要爬取的request,便能讓多個spider去同一個資料庫裡讀取。Scrapy中跟“待爬隊列”直接相關的就是排程器Scheduler,它負責對新的request進行入列操作(加入Scrapy

queue),取出下一個要爬取的request(從Scrapy

queue中取出)等操作。它把待爬隊列按照優先級建立了一個字典結構,然後根據request中的優先級,來決定該入哪個隊列,出列時則按優先級較小的優先出列。為了管理這個比較進階的隊列字典,Scheduler需要提供一系列的方法。但是原來的Scheduler已經無法使用,是以使用Scrapy-redis的scheduler元件。

2、Duplication Filter

Scrapy中用集合實作這個request去重功能,Scrapy中把已經發送的request指紋放入到一個集合中,把下一個request的指紋拿到集合中比對,如果該指紋存在于集合中,說明這個request發送過了,如果沒有則繼續操作。這個核心的判重功能是這樣實作的:

scrapy-redis實作分布式爬蟲詳解

在scrapy-redis中去重是由Duplication Filter元件來實作的,它通過redis的set不重複的特性,巧妙的實作了DuplicationFilter去重。scrapy-redis排程器從引擎接受request,将request的指紋存入redis的set檢查是否重複,并将不重複的request push寫入redis的 request queue。

引擎請求request(Spider發出的)時,排程器從redis的request queue隊列裡根據優先級pop 出⼀個request 傳回給引擎,引擎将此request發給spider處理。

3、Item Pipeline:

引擎将(Spider傳回的)爬取到的Item給Item Pipeline,scrapy-redis 的Item Pipeline将爬取到的

Item 存入redis的 items queue。修改過Item Pipeline可以很友善的根據 key 從 items queue

提取item,進而實作 items processes叢集。

4、Base Spider

不在使用scrapy原有的Spider類,重寫的RedisSpider繼承了Spider和RedisMixin這兩個類,RedisMixin是用來從redis讀取url的類。

當我們生成一個Spider繼承RedisSpider時,調用setup_redis函數,這個函數會去連接配接redis資料庫,然後會設定signals(信号):一個是當spider空閑時候的signal,會調用spider_idle函數,這個函數調用schedule_next_request函數,保證spider是一直活着的狀态,并且抛出DontCloseSpider異常。一個是當抓到一個item時的signal,會調用item_scraped函數,這個函數會調用schedule_next_request函數,擷取下一個request。

5、 總結

總結一下scrapy-redis的總體思路:這套元件通過重寫scheduler和spider類,實作了排程、spider啟動和redis的互動;

實作新的dupefilter和queue類,達到了判重和排程容器和redis的互動,因為每個主機上的爬蟲程序都通路同一個redis資料庫,是以排程和判重都統一進行統一管理,達到了分布式爬蟲的目的;當spider被初始化時,同時會初始化一個對應的scheduler對象,這個排程器對象通過讀取settings,配置好自己的排程容器queue和判重工具dupefilter;

每當一個spider産出一個request的時候,scrapy引擎會把這個reuqest遞交給這個spider對應的scheduler對象進行排程,scheduler對象通過通路redis對request進行判重,如果不重複就把他添加進redis中的排程器隊列裡。當排程條件滿足時,scheduler對象就從redis的排程器隊列中取出一個request發送給spider,讓他爬取;

當spider爬取的所有暫時可用url之後,scheduler發現這個spider對應的redis的排程器隊列空了,于是觸發信号spider_idle,spider收到這個信号之後,直接連接配接redis讀取strart_url池,拿去新的一批url入口,然後再次重複上邊的工作。

(四)從零搭建scrapy-redis分布式爬蟲

1、scrapy-Redis分布式政策:

Slaver端從Master端拿任務(Request/url/ID)進行資料抓取,在抓取資料的同時也生成新任務,并将任務抛給Master。Master端隻有一個Redis資料庫,負責對Slaver送出的任務進行去重、加入待爬隊列。

優點:scrapy-redis預設使用的就是這種政策,我們實作起來很簡單,因為任務排程等工作scrapy-redis都已經幫我們做好了,我們隻需要繼承RedisSpider、指定redis_key就行了。

缺點:scrapy-redis排程的任務是Request對象,裡面資訊量比較大(不僅包含url,還有callback函數、headers等資訊),導緻的結果就是會降低爬蟲速度、而且會占用Redis大量的存儲空間。當然我們可以重寫方法實作排程url。

scrapy-redis實作分布式爬蟲詳解

2、安裝Redis

下載下傳redis:http://redis.io/download
           

安裝完成後,拷貝一份Redis安裝目錄下的redis.conf到任意目錄,建議儲存到:/etc/redis/redis.conf 打開你的redis.conf配置檔案,示例: 非Windows系統: sudo vim /etc/redis/redis.conf Master端redis.conf裡注釋bind 127.0.0.1,Slave端才能遠端連接配接到Master端的Redis資料庫。

3、建立項目

使用上面的scrapy的項目我們來修改一下,這個爬蟲繼承了RedisSpider,它能夠支援分布式的抓取,采用的是basic spider,需要寫parse函數。其次就是不再有start_urls了,取而代之的是redis_key,scrapy-redis将key從Redis裡pop出來,成為請求的url位址。

修改spiders/hsw.py

scrapy-redis實作分布式爬蟲詳解

修改settings.py

scrapy-redis實作分布式爬蟲詳解

4、執行程式

通過runspider方法執行爬蟲的py檔案(也可以分次執行多條),爬蟲(們)将處于等待準備狀态:

scrapy runspider hsw.py
           

在Master端的redis-cli輸入push指令,參考格式:

lpush myspider:start_urls http://finance.hsw.cn/hyxw/
           
scrapy-redis實作分布式爬蟲詳解

5、擷取資料

所有Slaver端将開始爬取資料,資料将儲存在Redis資料庫中,并共享Redis資料庫的請求隊列、請求指紋集合和資料隊列。

scrapy-redis實作分布式爬蟲詳解

繼續閱讀