上次寫的教程讓女票高興了很久,但她高興的原因恐怕并不是學會了爬蟲,這點我還是非常清醒的。這篇教程的續(xù)集我很早就想好,但礙于實在沒有時間將它寫出來,終于咖啡館的網(wǎng)絡不好用,又沒帶書,只好耐著性子寫完它,算給自己為了爬蟲癡迷那幾天一個交代。我還是盡量寫的通俗,以求能讓更多的人看懂,比如我可愛的女票。
重要的前提,我假定你們已經(jīng)看過第一篇爬蟲教程,并且已經(jīng)實操了,那么我們跳過環(huán)境設置,直入主題。最近開了博客(www.readlist.cn),我將教程放在那里,歡迎大家有空去看看,漲個人氣。
我們的目的是爬取網(wǎng)頁中的圖片,可能你已經(jīng)發(fā)現(xiàn)了,我們只能下載網(wǎng)頁中的20張圖片。實際上,我們用瀏覽器瀏覽該網(wǎng)頁時,頁面中的照片不止20張,隨著滾動條的滾動,好像網(wǎng)頁在不斷的加載新的照片,可不可以貪心的把所有的照片下載下來呢?當然可以!
還用用chorme打開我們爬蟲的目標網(wǎng)頁,頁面上右擊選擇顯示網(wǎng)頁源代碼,我們在新打開的標簽頁看到了該網(wǎng)頁的源代碼。

有了前面的基礎,我們可以輕松的找到我們需要的圖片地址,<img class="pic" src="后面跟著的就是我們需要的圖片地址。按command+F搜索這串代碼,發(fā)現(xiàn)chrome在該源代碼中找到20個對象,這與我們第一篇教程得到的結果是相符的。接下來,你可以試試,無論你怎么滾動滾動條,源代碼不變,也就是源代碼只有前20張照片的地址,那么后面的圖片地址在哪里?

異步加載
其實,這個網(wǎng)頁用到了一種常見的網(wǎng)頁加載技術——異步加載。試想一下,該網(wǎng)頁可能有成千上萬的照片,如果當瀏覽器訪問時,全部顯示顯然要花很長時間才能全部加載,浪費時間浪費帶寬,解決這一不合理狀況的就是異步加載技術。你瀏覽該網(wǎng)頁時,瀏覽器只會加載前20張照片,當你滾動條滑動最下面時,瀏覽器認為你還需要閱讀更多的內容,就會向服務器提出申請說,“這個用戶想看更多的,再來些“,服務器會再發(fā)20張圖片的內容給瀏覽器,以此類推。
上述過程,你可以通過在網(wǎng)頁空白處右鍵點擊檢查,下面的chrome工具欄中的Network標簽會告訴你瀏覽器是怎么實現(xiàn)我們上面所述的異步加載。滾動滾動條至最下面,你會發(fā)現(xiàn)工具欄中出現(xiàn)了21個對象,其中20個為圖片,就是頁面新加載的20張圖片,剩下1個是json文件。繼續(xù)滾動,這里會再增加21個,以此類推,有沒有很有意思。

我們可以將json理解為一個包裹,這個包裹里放著的就是20張圖片的地址,我們每滾動到頁尾,就會向服務器申請一個包裹,然后瀏覽器拆開包裹,將里面的內容顯示在網(wǎng)頁上??墒?,服務器里存放了無數(shù)個包裹,它怎么知道我們需要哪個包裹,有過網(wǎng)購經(jīng)驗的MM肯定可以想到,每個包裹都有一個唯一的身份證,我們稱之為“快遞單號”。這樣,一切就可以解釋,瀏覽器將我們需要的包裹號發(fā)送給服務器,服務器然后如實將該包裹發(fā)送回來。我們可以仔細看下json,選中json文件,在右側的工具欄中選擇Preview標簽,里面的html中放著的是有新增加圖片地址的源代碼,last_key是下一段代碼的包裹號,所以不難推測,源代碼中有一個last_key指向本包裹。

我們重新捋一下思路,首先爬取源代碼中的圖片,然后向服務器發(fā)送包裹號,獲取包裹,解析其中的內容,然后再發(fā)送包裹號,再解析包裹中的內容,以此類推。接下來,終于可以上代碼了。
#-*-coding:utf8-*-
import re
import requests
import json
url = 'http://www.qdaily.com/categories/17'
url_more = 'http://www.qdaily.com/categories/categorymore/17/'
html = requests.get(url).text
last_key = re.search('lastKey="(.*?)"',html,re.S).group(1)
for i in range(3):
pic_url = re.findall('"pic" src="(.*?)"',html,re.S)
j = 0
for each in pic_url:
url = 'http://www.qdaily.com' + each
print('now downloading:' + url)
pic = requests.get(url)
fp = open('pic//' + str(i) +str(j) + '.jpg','wb')
fp.write(pic.content)
fp.close()
j += 1
url = url_more + last_key + 'json'
data = requests.get(url)
html = json.loads(data.text)[u'data'][u'html']
last_key = str(json.loads(data.text)[u'data'][u'last_key'])
代碼解析
#-*-coding:utf8-*-的意思上字符編碼是utf-8。
import re import requests import json的意思上導入re、requests 和json庫,告訴電腦,我們下面要用這三個庫中的程序了。
前面我們分析得到下一個包裹的包裹號,但是到底怎么獲取它呢?可以在檢查工具欄中,點擊Headers,查看到json的地址。

接下來定義兩個變量(就是存儲容器)存放兩個地址,我們接下來需要用到這兩個地址。
url = 'http://www.qdaily.com/categories/17'
url_more = 'http://www.qdaily.com/categories/categorymore/17/'
然后獲取url中地址的源代碼,并且在源代碼中查找last_key。
html = requests.get(url).text
last_key = re.search('lastKey="(.*?)"',html,re.S).group(1)
下面的代碼是我們這篇教程的核心,用循環(huán)來不斷向獲取新的包裹,拆開它,通過里面的圖片地址下載圖片,我們這里只循環(huán)3次,下載60張圖片,當然你想循環(huán)多少次就改一下數(shù)字即可,相信你可以辦到。for i in range(3):就是循環(huán)語句,表示接下來的語句要執(zhí)行三次。
邏輯是非常清楚的:
- 從源代碼中獲取圖片地址
pic_url = re.findall('"pic" src="(.*?)"',html,re.S)
- 將圖片下載到指定文件夾
j = 0
for each in pic_url:
url = 'http://www.qdaily.com' + each
print('now downloading:' + url)
pic = requests.get(url)
fp = open('pic//' + str(i) +str(j) + '.jpg','wb')
fp.write(pic.content)
fp.close()
j += 1
- 獲取下一批圖片的源代碼
url = url_more + last_key + 'json'
data = requests.get(url)
html = json.loads(data.text)[u'data'][u'html']
- 獲取下一批圖片源代碼中包含的last_key
last_key = str(json.loads(data.text)[u'data'][u'last_key'])
我沒有詳細解釋代碼的具體含義,因為接下來我要去逛書店,沒有耐心了。如果你有疑問,歡迎到我的博客留言提問,有問必答。
執(zhí)行程序
將上面到代碼保存為picdownloader2.py,置于根目錄下,并且新建文件夾pic。打開終端,寫下如下代碼,回車即可
python picdownloader2.py
終于完成了“教女朋友爬蟲”的續(xù)集,關于爬蟲的教程先告一段落。上次的教程讓女票(領導)甚是開心,順便提出了新要求,要我繼續(xù)寫教程,因為她還要學很多,學markdown,學印象筆記,學Hexo博客。。。再一次硬廣,歡迎關注我的博客,微博。
今天是女票麻麻的生日,未來丈母娘生日快樂。
