如果您覺得我們寫得還不錯,記得 點贊 + 關注 + 評論 三連🥰🥰🥰,鼓勵我們寫出更好的教程💪
前情回顧
在上篇教程爬蟲養成記——先跨進這個精彩的世界(女生定製篇)中我們已經可以將所有小哥哥的封面照片抓取下來,但僅僅是封面圖片在質量和數量上怎麼能滿足小仙女們的要求呢?在本篇教程中,我們串起一根姻緣“線”,來把這一系列的小哥哥們都收入囊中。
出門先化妝
小仙女們出門約會總會“淡妝濃抹總相宜”,那爬蟲出門去爬取數據,也得打扮打扮啊,不然怎麼能讓男神們都乖乖地跟着走呢?
爬蟲的“化妝”可不是“妝前乳 --> 粉底 --> 遮瑕 --> 散粉 --> 畫眉 --> 口紅”等這些步驟,其目的是爲了讓對方網站更加確信來訪者不是爬蟲程序,而是一個活生生的人。人們通過操控瀏覽器來訪問網站,那麼爬蟲程序只需要模仿瀏覽器就可以了。 那就來看看瀏覽器在打開網頁時都畫了那些“妝”。
打開Chrome並打開調試臺,切換到NetWork選項卡,此時訪問 https://www.nanrentu.cc/sgtp/, 這是時候會看到調試臺裏出現了很多鏈接信息,這麼多鏈接到底哪個是我們所需要的呢?回想一下上一篇內容,首先是要獲得HTML文檔,再從此文檔中提取出圖片的鏈接,所以目標有了,就是找到瀏覽器獲取到這個HTML文檔的那個鏈接。
Chrome知道這麼多鏈接信息肯定會讓開發者陷入茫然,所以給鏈接進行了歸類,點擊上方Doc分類,再點擊那唯一的一條鏈接,就會看到獲取此HTML文檔鏈接的詳細信息了。此時我們關注主要Request Headers 這個裏面的內容。瀏覽器通過http協議與服務器交互獲取信息,爬蟲是通過模仿瀏覽器發出http協議獲取信息,其中最重要的一個模仿點就是Request Headers。
http協議裏面的“瓶瓶罐罐”
讓男生看女孩子化妝用的那些瓶瓶罐罐估計會陷入沉思,這是BB霜,那是粉底液,還有散粉、眼影、遮瑕膏,更不用說各種色號的口紅啦。那女孩子看到這http裏面的各項內容時估計也會一臉懵逼,其這比化妝品簡單多了,我們只需簡單瞭解,就能給爬蟲畫出精緻妝容。
:authority: www.nanrentu.cc
:method: GET // 自定義請求頭 請求方法
:path: /sgtp/ // 自定義請求頭 請求路徑
:scheme: https // 自定義請求頭 請求方式
// 所接受的內容格式
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
// 所接受的編碼方式
accept-encoding: gzip, deflate, br
// 所接受的語言
accept-language: zh-CN,zh;q=0.9
// 緩存控制:告訴服務器客戶端希望得到一個最新的資源
cache-control: max-age=0
cookie: UM_distinctid=170a5a00fa25bf-075185606c88b7-396d7407-100200-170a5a00fa3507; Hm_lvt_45e50d2aec057f43a3112beaf7f00179=1583326696,1583756661; CNZZDATA1274895726=1196969733-1583323670-%7C1583752625; Hm_lpvt_45e50d2aec057f43a3112beaf7f00179=1583756721
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: none
sec-fetch-user: ?1
// 屏蔽HTTPS頁面出現HTTP請求警報
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
這麼多的信息不用都給爬蟲加上,因爲這網站的防爬措施等級不高,暫時只要關鍵的兩個就可以了。
- cookie: 這是存儲在瀏覽器裏面一段文本,有時包含了驗證信息和一些特殊的請求信息
- user-agent:用於標識此請求是由什麼工具所發出的
關於User-Agent的詳細信息可以參考此篇博文 談談 UserAgent 字符串的規律和僞造方法
但是當爬取其他網站時可能會有所需要,在這裏贅述這麼多原因就是希望大家能明白僞裝爬蟲的重要性,以及怎麼獲取這些僞裝信息。
// 建立一個名叫headers的字典
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
'cookie': 'UM_distinctid=170a5a00fa25bf-075185606c88b7-396d7407-100200-170a5a00fa3507; CNZZDATA1274895726=1196969733-1583323670-%7C1583925652; Hm_lvt_45e50d2aec057f43a3112beaf7f00179=1583326696,1583756661,1583926583; Hm_lpvt_45e50d2aec057f43a3112beaf7f00179=1583926583'
}
// 發送請求時帶上請求頭
response = requests.get(baseUrl,headers=headers)
順藤摸瓜
一個網站是由若干個網頁組合而成的,網頁中充滿着各種超鏈接,從這網頁鏈接到那個網頁,如果我們想要更多小哥哥,那就得首先分析出串聯起他們那些超鏈接,然後就可以順藤摸瓜咯。
當把鼠標發放到標題上時,標題的顏色發生了變化,證明這一元素爲超連接,點擊標題瀏覽器會自動打開一個tab標籤頁,來顯示網頁,注意到下方的頁碼標籤,是這些元素串聯起了整個圖集。
點擊“末頁”觀察url發生了什麼變化
末頁的url:https://www.nanrentu.cc/sgtp/36805_7.html
首頁的url:https://www.nanrentu.cc/sgtp/36805.html
看起來有點意思了,末頁的url比首頁的url多了“_7”,接下來再點擊分別進入第2頁,第3頁……觀察url的變化,可得出下表。
頁面 | url |
---|---|
首頁 | https://www.nanrentu.cc/sgtp/36805.html |
第2頁 | https://www.nanrentu.cc/sgtp/36805_2.html |
第3頁 | https://www.nanrentu.cc/sgtp/36805_3.html |
第4頁 | https://www.nanrentu.cc/sgtp/36805_4.html |
第5頁 | https://www.nanrentu.cc/sgtp/36805_5.html |
第6頁 | https://www.nanrentu.cc/sgtp/36805_6.html |
第7頁 | https://www.nanrentu.cc/sgtp/36805_7.html |
多點幾個組圖,也會發現同樣規律。這樣就明瞭很多了,我們已經分析清楚了這個跟“藤”的開頭與結尾,接下來就可以敲出代碼讓爬蟲開始“摸瓜”咯。
摸瓜第1步:提取標題鏈接
這個操作與上篇博文中所介紹的一樣,打開調試臺切換到Elements選項卡就能開始探索提取了。
摸瓜第2步:提取末頁鏈接,得出組圖頁數
通過觀察HTML元素結構,可發現包含末頁的 <li> 標籤爲其父元素<ul>的倒數第二個子元素,所以可得出以下的css選擇器
.page > ul > li:nth-last-child(2) > a
摸瓜第3步:根據首尾鏈接構造url
爲了構造url更加方便,我們可以把首頁 https://www.nanrentu.cc/sgtp/36805.html 變爲 https://www.nanrentu.cc/sgtp/36805_1.html, 在瀏覽器中打開帶有後綴的這個網址,依然能夠成功訪問到首頁,不要問我爲什麼?這可能就是程序員之間的一種默契吧~
摸瓜第4步:存儲圖片,摸瓜成功
完整的代碼如下:
import requests
from pyquery import PyQuery as pq
import uuid
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
'cookie': 'UM_distinctid=170a5a00fa25bf-075185606c88b7-396d7407-100200-170a5a00fa3507; CNZZDATA1274895726=1196969733-1583323670-%7C1583925652; Hm_lvt_45e50d2aec057f43a3112beaf7f00179=1583326696,1583756661,1583926583; Hm_lpvt_45e50d2aec057f43a3112beaf7f00179=1583926583'
}
def saveImage(imgUrl,name):
imgResponse = requests.get(imgUrl)
fileName = "學習文件/%s.jpg" % name
if imgResponse.status_code == 200:
with open(fileName, 'wb') as f:
f.write(imgResponse.content)
f.close()
def getPic(urlArray):
for url in urlArray:
res = requests.get(url,headers=headers)
if res.status_code == 200:
doc = pq(res.text)
imgSrc = doc('.info-pic-list > a > img').attr('src')
print(imgSrc)
saveImage(imgSrc,uuid.uuid1().hex)
def createUrl(indexUrl,allPage):
baseUrl = indexUrl.split('.html')[0]
urlArray = []
for i in range(1,allPage):
tempUrl = baseUrl+"_"+str(i)+".html"
urlArray.append(tempUrl)
return urlArray
def getBoys(link):
# 摸瓜第1步:獲取首頁連接
picIndex = link.attr('href')
# 摸瓜第2步:打開首頁,提取末頁鏈接,得出組圖頁數
res = requests.get(picIndex,headers=headers)
print("當前正在抓取的 picIndex: " + picIndex)
if res.status_code == 200:
with open("picIndex.html",'w',encoding="utf-8") as f:
f.write(res.text)
doc = pq(res.text)
lastLink = doc('.page > ul > li:nth-last-child(2) > a').attr('href')
# 字符串分割,得出全部的頁數
if(lastLink is None):
return
# 以.html 爲分割符進行分割,取結果數組中的第一項
temp = lastLink.split('.html')[0]
# 再以下劃線 _ 分割,取結果數組中的第二項,再轉爲數值型
allPage = int(temp.split('_')[1])
# 摸瓜第3步:根據首尾鏈接構造url
urlArray = createUrl(picIndex,allPage)
# 摸瓜第4步:存儲圖片,摸瓜成功
getPic(urlArray)
def main():
baseUrl = "https://www.nanrentu.cc/sgtp/"
response = requests.get(baseUrl,headers=headers)
if response.status_code == 200:
with open("index.html",'w',encoding="utf-8") as f:
f.write(response.text)
doc = pq(response.text)
# 得到所有圖集的標題連接
titleLinks = doc('.h-piclist > li > a').items()
# 遍歷這些連接
for link in titleLinks:
getBoys(link)
if __name__ == "__main__":
main()
運行結果:
回首掏
回顧整個爬蟲程序,它是連續式流水線作業,每一步之間都是環環相扣,所以在寫程序前自己一定要把整個流水線的每個環節都考慮清楚,把它們之間的順序依賴關係化成一個簡易的流程圖,對着流程圖再寫程序就會清晰很多。我們可以把每一個模塊都寫成一個函數,先對函數做好單元測試,再把這些函數按順序組合起來就行啦。分而治之,有機組合這就是編程的奧義。再複雜的項目,都是由一個個模塊組建起來的,這和搭積木是一樣的道理。
這個流程圖只用單項箭頭畫出了獲取一張圖片的全部過程,這就相當於一個工人在幹活,我們的計算機是一個大工廠裏面有成千上萬個工人,只讓一個工人幹活其他的人都在爲他加油嘛?那也太說不過去,在下一篇文章中,我們將畫出完整的流程圖,分析出其他工人沒活幹的原因,然後充分調動起計算機的算力,來提升程序的運行效率。
如果您覺得我們寫得還不錯,記得 點贊 + 關注 + 評論 三連🥰🥰🥰,鼓勵我們寫出更好的教程💪
想要學習更多精彩的實戰技術教程?來圖雀社區逛逛吧。