以前寫的爬蟲都是單機爬蟲,尚未嘗試過度布式爬蟲,此次就是一個分佈式爬蟲的初體驗。所謂分佈式爬蟲,就是要用多臺電腦同時爬取數據,相比於單機爬蟲,分佈式爬蟲的爬取速度更快,也能更好地應對IP的檢測。本文介紹的是利用Redis數據庫實現的分佈式爬蟲,Redis是一種經常使用的菲關係型數據庫,經常使用數據類型包括String、Hash、Set、List和Sorted Set,重要的是Redis支持主從複製,主機能將數據同步到從機,也就可以實現讀寫分離。所以咱們能夠利用Redis的特性,藉助requests模塊發送請求,再解析網頁和提取數據,實現一個簡單的分佈式爬蟲。html
Python版本:Python3git
Redis版本:5.0github
IDE: Pycharmredis
因爲Windows下的安裝配置比較簡單,因此這裏只說Linux環境下安裝和配置Redis(以Ubuntu爲例)。數據庫
1)apt安裝:dom
$ sudo apt-get install redis-server分佈式
2)編譯安裝:ide
$ wget http://download.redis.io/releases/redis-5.0.0.tar.gz網站
$ tar -xzvf redis-5.0.0.tar.gzurl
$ cd redis-5.0.0
$ make
$ make install
首先找到redis.conf文件,而後輸入命令sudo vi redis.conf,進行以下操做:
註釋掉bind 127.0.0.1 # 爲了遠程鏈接,這一步還能夠將bind 127.0.0.1改成bind 0.0.0.0
protected-mode yes 改成 protected-mode no
daemonized no 改成 daemonized yes
若是6379端口被佔用,還須要改一下端口號。除此以外,要遠程鏈接還須要關閉防火牆。
chkconfig firewalld off # 關閉防火牆
systemctl status firewalld # 檢查防火牆狀態
使用的命令爲redis-cli -h <IP地址> -p <端口號>
注:Windows查看IP地址用ipconfig,Linux查看IP地址用ifconfig。
此次我爬取的網站爲:http://www.shu800.com/,在這個網站的首頁裏有五大分類,分別是性感美女、清純可愛、明星模特、動漫美女和絲襪美腿,因此要作的第一件事就是獲取這幾個分類的URL。而後,對每一個分類下的網頁進行爬取,經過查看網頁元素能夠發現以下信息:
能夠很明顯地看到每一頁的URL都是符合必定規律的,只要獲取到了尾頁的URL,將其中的頁數提取出來,也就能構造每一頁的URL了,這就比每次去獲取下一頁的URL簡單多了。而對於每個圖集下的圖片,也是用一樣的方法獲得每一頁圖片的URL。最後要作的就是從圖片網頁中將圖片的URL提取出來,而後下載保存到本地。
此次分佈式爬蟲我使用了兩臺電腦,一臺做爲主機master,另外一臺做爲從機slave。主機開啓Redis服務,爬取每一頁圖片的URL,並將爬取到的URL保存到Redis的集合中,從機遠程鏈接主機的Redis,監聽Redis中是否有URL,若是有URL則提取出來進行下載圖片,直至全部URL都被提取和下載。
1.第一段代碼是爬取每一個頁面裏的美女圖集的URL,而且把這些URL保存到數據庫中,這裏使用的是Redis中的集合,經過使用集合可以達到URL去重的目的,代碼以下:
1 def get_page(url):
2 """
3 爬取每一個頁面下的美女圖集的URL
4 :param url: 頁面URL
5 :return:
6 """
7 try: 8 r = Redis(host="localhost", port=6379, db=1) # 鏈接Redis 9 time.sleep(random.random()) 10 res = requests.get(url, headers=headers) 11 res.encoding = "utf-8" 12 et = etree.HTML(res.text) 13 href_list = et.xpath('/html/body/div[5]/div[1]/div[1]/div[2]/ul/li/a/@href') 14 for href in href_list: 15 href = "http://www.shu800.com" + href 16 r.sadd("href", href) # 保存到數據庫中 17 except requests.exceptions: 18 headers["User-Agent"] = ua.random 19 get_page(url)
2.第二段代碼是從機監聽Redis中是否有URL的代碼,若是沒有URL,等待五秒鐘再運行,由於若是不稍做等待就直接運行,很容易超過Python的遞歸深度,因此我設置了一個等待五秒鐘再運行。反之,若是有URL被添加到Redis中,就要將URL提取出來進行爬取,使用的方法是redis模塊裏的spop()方法,該方法會從Redis的集合中返回一個元素。須要注意的是,URL被提取出來後要先轉成str。
1 def get_urls():
2 """
3 監聽Redis中是否有URL,若是沒有就一直運行,若是有就提取出來進行爬取
4 :return:
5 """
6 if b"href" in r.keys(): 7 while True: 8 try: 9 url = r.spop("href") 10 url = url.decode("utf-8") # unicode轉str 11 print("Crawling URL: ", url) 12 get_image(url) 13 get_img_page(url) 14 except: 15 if b"href" not in r.keys(): # 爬取結束,退出程序 16 break 17 else: 18 continue 19 else: 20 time.sleep(5) 21 get_urls()
下圖是在主機master上運行的截圖,這裏爬取到的圖集總共有9633個:
從機slave會不斷地從Redis數據庫中提取URL來爬取,下圖是運行時的截圖:
打開文件夾看看爬下來的圖片都有什麼(都是這種標題,有點難頂啊...):
完整代碼已上傳到GitHub!