【Python3爬蟲】爬取美女圖新姿勢--Redis分散式爬蟲初體驗
一、寫在前面
之前寫的爬蟲都是單機爬蟲,還沒有嘗試過分散式爬蟲,這次就是一個分散式爬蟲的初體驗。所謂分散式爬蟲,就是要用多臺電腦同時爬取資料,相比於單機爬蟲,分散式爬蟲的爬取速度更快,也能更好地應對IP的檢測。本文介紹的是利用Redis資料庫實現的分散式爬蟲,Redis是一種常用的菲關係型資料庫,常用資料型別包括String、Hash、Set、List和Sorted Set,重要的是Redis支援主從複製,主機能將資料同步到從機,也就能夠實現讀寫分離。因此我們可以利用Redis的特性,藉助requests模組傳送請求,再解析網頁和提取資料,實現一個簡單的分散式爬蟲。
二、基本環境
Python版本:Python3
Redis版本:5.0
IDE: Pycharm
三、環境配置
由於Windows下的安裝配置比較簡單,所以這裡只說Linux環境下安裝和配置Redis(以Ubuntu為例)。
1.安裝Redis
1)apt安裝:
$ sudo apt-get install redis-server
2)編譯安裝:
$ wget http://download.redis.io/releases/redis-5.0.0.tar.gz
$ tar -xzvf redis-5.0.0.tar.gz
$ cd redis-5.0.0
$ make
$ make install
2.配置Redis
首先找到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 # 檢查防火牆狀態
3.遠端連線Redis
使用的命令為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來爬取,下圖是執行時的截圖:
開啟資料夾看看爬下來的圖片都有什麼(都是這種標題,有點難頂啊...):
完整程式碼已上傳到GitHu