手把手教你用 Python 爬取美女圖

最近由於公司業務的需要,我開始做了一些簡單的爬蟲的工作。學了爬蟲之後,就在想,能不能用爬蟲做一些有趣的事情呢?想來想去,還是教大家寫個簡單的爬蟲,用來爬取一組美女圖。

因為只有美女圖才能吸引你們這些紳士過來圍觀。。。。。

最後附上源碼,拿去直接就可以用了。

目標

我在 bing 上搜索 美女圖,出來了這個。

手把手教你用 Python 爬取美女圖

那我們就用這個來開刀吧。

手把手教你用 Python 爬取美女圖

額。。。。。。。。

這尺度,我們還是選個保守一點的來做例子吧。。。。。。

手把手教你用 Python 爬取美女圖

配置環境

由於我們是使用 python 來做爬蟲的,所以我們要先裝好 python 環境,這個比較簡單,直接到官網下載安裝就可以了,安裝的過程也是一直下一步就行。

下載地址: https://www.python.org/downloads/

手把手教你用 Python 爬取美女圖

我們選擇相應的操作系統平臺安裝就可以了。

還有一個是 python 的網絡請求庫 requests ,我們後面將要使用這個庫進行網絡請求,來爬取數據。

這個庫的安裝也很簡單,在命令行下執行以下命令就可以了

pip3 install requests

還有一個是用來解析 html 結構,和提取元素內容的一個庫。安裝也很簡單

pip3 install beautifulsoup4

開始分析

在 Chrome(谷歌瀏覽器) 下,打開我們要爬取的地址 https://www.walltu.com/tuku/201801/212736.html , 然後按 F12 ,在網絡這一欄,我們可以看到這個頁面的請求。

手把手教你用 Python 爬取美女圖

然後,再切到 XHR 下,發現這個頁面並沒有發 ajax ,也就是說,我們要爬取的圖片地址和頁面可能是在一起的。

我們看一下這個 html 頁面裡面是什麼東西。

手把手教你用 Python 爬取美女圖

然後我們在使用元素選擇器,看一下我們要爬取的圖片是哪個元素,然後我們再到 html 代碼裡面找一下,找到這個圖片的元素

手把手教你用 Python 爬取美女圖

找到了,然後我們再到網絡請求到頁面裡面看一下,看能不能找到這個元素,果然找到了。

手把手教你用 Python 爬取美女圖

我們再瀏覽器直接打開這個地址:

手把手教你用 Python 爬取美女圖

那就說明可以通過地址直接獲取到圖片,那我們就開始了。

開始幹活

到這裡,我們就要開始正式寫代碼了,但是不要擔心,很簡單的。老司機帶路肯定是穩的!

先從下載圖片開始

我們先試一下,看能不能直接請求到圖片。打印一下請求的狀態碼和內容。

import requests
response = requests.get('https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800')
print(response.status_code)
print(response.content)

打印結果如下:

403
b'{"code":"40310014","msg":"invalid Referer header"}'

請求失敗了,但是提示我們 referer 非法。說起來也是挺好笑的,居然會提示我們錯誤的地方,這是怕我們爬不到數據嗎。。。。。。

知道問題在哪就好搞了。我們找一下這個信息要填什麼。

切換之前頁面的調試界面,選中 img ,看一下頁面上請求時用的是什麼,照抄過來就行了。

手把手教你用 Python 爬取美女圖

然後把這個東西加到請求頭試一下

import requests
headers = {
 'Referer':'https://www.walltu.com/tuku/201801/212736.html'
}
response = requests.get('https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800',headers=headers)
print(response.status_code)
print(response.content)

上面的代碼應該很容易看懂吧,即使沒有學過 python 。就是在請求的時候多添加了一個請求頭的參數

打印內容如下:

200
b'\xff\xd8\\xea\xe3o\x88...............1\x12\xc1\x1b\x19)\xbcw\x139u\x0eLD\xd8l\x02o\x81\x12c&\xc4\xc9\xf2MT\x7f\xff\xd9'

我們看到狀態碼是 200 ,說明成功了,後面打印的是圖片的二進制數據,由於圖片轉化成二進制內容很多,中間的部分信息被我省略了。

保存圖片

剛才我們通過 requests 請求到了圖片,但是二進制的圖片給我們沒有用啊,我們要看圖片,真正的圖片!

那我們就要把圖片保存起來。我們先打開一個文件,然後把請求到的內容寫入到文件裡面就行了。

import requests
headers = {
 'Referer':'https://www.walltu.com/tuku/201801/212736.html'
}
response = requests.get('https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800',headers=headers)
# 打開一個文件,第一個參數是文件路徑,第二參數是打開方式,'wb' 表示以二進制寫入的方式打開
img_file = open('img.jpg','wb')
# 然後往文件裡面寫內容
img_file.write(response.content)

這段代碼執行完,應該就可以在同個目錄下找到下載好的 img.jpg 圖片,打開就能看見下載好的圖片的了。是不是很簡單呢。

目標是爬取一組圖

我們搞半天,只是把一張圖片下載到本地而已,這麼麻煩,還不如直接在頁面上右擊保存圖片來得快呢。。。。。。

我們的目標可不是下載一張圖片,而是一整組圖片!

從第一張圖片開始爬取

第一張圖片剛才不是下載完了?

不不不,我們要是輸入這一組圖片的網頁地址,就可以下載這一組圖片的效果。也就是輸入 https://www.walltu.com/tuku/201801/212736.html 就可以下載一整組圖的效果。

要實現這個效果,可就不能像之前那樣手動去找圖片的地址了,要通過代碼找到圖片的地址。那我們就需要使用一些工具來幫我們找到這個地址了,我這裡使用的是 BeautifulSoup 來進行元素查找。

我們先看一下剛才查找的那個圖

手把手教你用 Python 爬取美女圖

觀察這個結構,發現比較靠近目標並且有特點的元素是 ,我們只要找到這個元素,再順藤摸瓜,往下找到下面的

然後再往裡面就可以找到我們要的 這個元素了。

手把手教你用 Python 爬取美女圖

代碼上,我們可以這麼寫:

import requests
from bs4 import BeautifulSoup
# 請求這個頁面
response = requests.get('https://www.walltu.com/tuku/201801/212736.html')
# BeautifulSoup 的構造函數最少需要兩個參數,第一個是要解析的內容,第二個是解析器,這裡我們使用的是 'html.parser'
content = BeautifulSoup(response.content, 'html.parser')
target_parent = content.find('dd', class_='p')
target = target_parent.p.img
img_address = target['src']
print(img_address)
 

打印結果如下:

https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800

我們這樣就拿到了第一個頁面的圖片地址。

查找下一個

我們的最終目標的是爬取一整組圖。找到了第一個圖片,那就要準備找下一個了。

手把手教你用 Python 爬取美女圖

我想很多人想到的是圖片右邊的 下一圖 這個按鈕,但是有個問題,就是到這組圖的最後一張後,這個按鈕的鏈接就會變成下一組圖的地址了,這樣就會一直循環下去,這可不行。

我把目標轉到了下面。

手把手教你用 Python 爬取美女圖

我們發現當前的圖片是有個選中的樣式的,我們應該可以找到這個元素,然後找到下一個元素,也就是下一個圖片的頁面的鏈接。這個會不會有最後一張的地址變成下一組的地址 這個問題呢?

我們看一下:

手把手教你用 Python 爬取美女圖

好像沒有,最後一個還是最後一個,沒有多出一個是跳下一組圖的元素。我們還得看一下 html 。

手把手教你用 Python 爬取美女圖

確實沒有一些多餘的東西,而且我們還發現了選中的樣式是 class="c",那就開始幹活!

import requests
from bs4 import BeautifulSoup
# 請求這個頁面
response = requests.get('https://www.walltu.com/tuku/201801/212736.html')
# BeautifulSoup 的構造函數最少需要兩個參數,第一個是要解析的內容,第二個是解析器,這裡我們使用的是 'html.parser'
content = BeautifulSoup(response.content, 'html.parser')
# 找到當前選中的圖片
index = content.find('a', class_='c')
# 找到下一個圖片的元素
next_target = index.next_sibling
if next_target is None:
 # 沒有下一個了
 print('沒有下一個了')
else:
 # 找到了下一個,我們就打印出來
 print('下一個')
 next_addr = 'https://www.walltu.com' + next_target['href']
 print(next_addr)
 

打印結果:

下一個
https://www.walltu.com/tuku/201801/212736_2.html

如果是最後一個呢?我們也看一下,我們把地址換成 https://www.walltu.com/tuku/201801/212736_7.html

再執行一次,打印結果

沒有下一個了

再配合上之前下載圖片的代碼,應該就可以把一整組圖給下載下來了。我們還需要一個文件夾把這些圖片給整理放好,其實還有剩下的兩步工作,就是新建一個文件夾,用來存放圖片,然後下載圖片的時候再給每個圖片命名,否則重複的文件名會把之前的圖片給覆蓋掉。

新建文件夾

新建文件夾很簡單

import os
# 創建文件夾
os.makedirs('文件夾的名稱')

用來存圖片的目錄名就用第一個頁面的標題吧。

給圖片命名

要給圖片命名,就要考慮唯一性,從圖片的下載地址上看,這些名稱確實是唯一的,但是都是一些隨機的名稱,也就是沒有順序,感覺也不太好,因為這些圖片實際上是有一定順序的。

實在不行,那就用頁面的地址吧。因為一個圖片對應的也是一個頁面,而且我們看一下這些頁面地址。

https://www.walltu.com/tuku/201801/212736.html
https://www.walltu.com/tuku/201801/212736_2.html
https://www.walltu.com/tuku/201801/212736_3.html
https://www.walltu.com/tuku/201801/212736_4.html

我們發現,這些還是有順序的,剛好滿足我們的需求。

在下載圖片的時候,傳入名稱就行了。這裡就不上代碼了。

整理一下思路

  1. 根據第一個頁面的標題新建一個文件夾,用來存放圖片。
  2. 解析頁面,下載第一張圖片,獲取下一個頁面的地址
  3. 循環第二步,直到下載完最後一個圖片。

整理一下代碼

我們最後整理一下代碼,把一些操作抽取成方法。

import os
import requests
from bs4 import BeautifulSoup
# 下載所有圖片
def downloadAllImg(address):
 # 解析頁面
 content = getContent(address)
 # 獲取頁面標題
 title = content.title.string
 # 新建文件夾
 os.makedirs(title)
 # 獲取圖片的地址
 download_img_addr = getDownloadImgAddr(content)
 # 獲取文件名
 file_name = getFileName(address)
 print('開始下載:'+title)
 while download_img_addr is not None:
 # 下載圖片
 downloadImg(download_img_addr,address,title,file_name)
 # 獲取下一個頁面的地址
 next_addr = getNextAddr(content)
 if next_addr is None:
 download_img_addr = None
 else:
 # 獲取下一個圖片的名稱,並賦值給 變量
 file_name = getFileName(next_addr)
 # 解析下一個頁面,並賦值給 變量
 content = getContent(next_addr)
 # 獲取下一個圖片的下載地址,並賦值給 變量
 download_img_addr = getDownloadImgAddr(content)
 print('新下載地址:'+download_img_addr)
 print('已全部下載完成')
# 解析頁面
def getContent(address):
 response = requests.get(address)
 return BeautifulSoup(response.content, 'html.parser')
# 獲取圖片的地址
def getDownloadImgAddr(content):
 target_parent = content.find('dd', class_='p')
 target = target_parent.p.img
 img_address = target['src']
 return img_address
# 獲取下一個頁面的地址
def getNextAddr(content):
 index = content.find('a', class_='c')
 next_target = index.next_sibling
 if next_target is None:
 print('沒有下一個了')
 return None
 else:
 print('下一個')
 next_addr = 'https://www.walltu.com' + next_target['href']
 print(next_addr)
 return next_addr
# 獲取文件的名稱
def getFileName(address):
 end_index = address.rfind('.')
 start_index = address.rfind('/')
 return address[start_index + 1:end_index]
# 下載圖片
def downloadImg(imgAddress,fromAddr,dir,file_name):
 print('正在下載:'+file_name)
 img = open(dir+'/'+file_name+'.jpg', 'wb')
 headers = {
 'Referer': fromAddr
 }
 img_response = requests.get(imgAddress, headers=headers)
 img.write(img_response.content)
 img.close()
 print('下載完成:'+imgAddress)
# 調用,傳入要下載的圖片的地址
downloadAllImg('https://www.walltu.com/tuku/201801/212736.html')
 

代碼到這裡就完成了,想要下載其他組圖,只要換一下,最後調用的地址就可以了。

最後,我們看一下效果吧。成功下載到了一整組圖。

手把手教你用 Python 爬取美女圖

大家快去試一下吧!


分享到:


相關文章: