1. 程式人生 > >【Python3爬蟲】爬取美女圖新姿勢--Redis分散式爬蟲初體驗

【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