Python 3實(shí)戰(zhàn)爬蟲之爬取京東圖書的圖片詳解
前言
最近工作中遇到一個(gè)需求,需要將京東上圖書的圖片下載下來,假如我們想把京東商城圖書類的圖片類商品圖片全部下載到本地,通過手工復(fù)制粘貼將是一項(xiàng)非常龐大的工程,此時(shí),可以用Python網(wǎng)絡(luò)爬蟲實(shí)現(xiàn),這類爬蟲稱為圖片爬蟲,接下來,我們將實(shí)現(xiàn)該爬蟲。
實(shí)現(xiàn)分析
首先,打開要爬取的第一個(gè)網(wǎng)頁,這個(gè)網(wǎng)頁將作為要爬取的起始頁面。我們打開京東,選擇圖書分類,由于圖書所有種類的圖書有很多,我們選擇爬取所有編程語言的圖書圖片吧,網(wǎng)址為:https://list.jd.com/list.html?cat=1713,3287,3797&page=1&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main
如圖:
進(jìn)去后,我們會發(fā)現(xiàn)總共有251頁。
那么我們怎么才能自動爬取第一頁以外的其他頁面呢?
可以單擊“下一頁”,觀察網(wǎng)址的變化。在單擊了下一頁之后,發(fā)現(xiàn)網(wǎng)址變成了https://list.jd.com/list.html?cat=1713,3287,3797&page=2&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main。
我們可以發(fā)現(xiàn),在這里要獲取第幾頁是通過URL網(wǎng)址識別的,即通過GET方式請求的。在這個(gè)GET請求中,有多個(gè)字段,其中有一個(gè)字段為page,對應(yīng)值為2,由此,我們可以得到該網(wǎng)址中的關(guān)鍵信息為:https://list.jd.com/list.html?cat=1713,3287,3797&page=2。接下來,我們根據(jù)推測,將page=2改成page=6,發(fā)現(xiàn)我們能夠成功進(jìn)入第6頁。
由此,我們可以想到自動獲取多個(gè)頁面的方法:可以使用for循環(huán)實(shí)現(xiàn),每次循環(huán)后,對應(yīng)的網(wǎng)址中page字段加1,即自動切換到下一頁。
在每頁中,我們都要提取對應(yīng)的圖片,可以使用正則表達(dá)式匹配源碼中圖片的鏈接部分,然后通過urllib.request.urlretrieve()將對應(yīng)鏈接的圖片保存到本地。
但是這里有一個(gè)問題,該網(wǎng)頁中的圖片不僅包括列表中的商品圖片,還包括旁邊的一些無關(guān)圖片,所以我們可以先進(jìn)行一次信息過濾,第一次信息過濾將中間的商品列表部分?jǐn)?shù)據(jù)留下,將其他部分的數(shù)據(jù)過濾掉??梢詥螕粲益I,然后查看網(wǎng)頁的源代碼,如圖:
可以通過商品列表中的第一個(gè)商品名為“JAVA從入門到精通”快速定位到源碼中的對應(yīng)位置,然后觀察其商品列表部分的特殊標(biāo)識,可以看到,其上方有處“<div id="plist”代碼,然后我們在源碼中搜索該代碼,發(fā)現(xiàn)只有一個(gè)地方有,隨后打開其他頁的對應(yīng)頁面,發(fā)現(xiàn)仍然具有這個(gè)規(guī)律,說明該特殊標(biāo)識可以作為有效信息的起始過濾位置。當(dāng)然,你可以使用其他的代碼作為特殊標(biāo)識,但是該特殊標(biāo)識要滿足唯一性,并且要包含要爬取的信息。
那么,有效信息到什么代碼位置結(jié)束呢?
同樣,我們通過在源碼中查找該頁商品列表中最后一個(gè)圖書,快速定位到源碼位置,進(jìn)行分析,我們可以找到一個(gè)這樣的代碼作為標(biāo)識,如圖:
所以,如果要進(jìn)行第一次過濾,我們的正則表達(dá)式可以構(gòu)造為:
<div id="plist".+? <div class="page clearfix">
進(jìn)行了第一次信息過濾后,留下來的圖片鏈接就是我們想爬取的圖片了,下一步需要在第一次過濾的基礎(chǔ)上,再將圖片鏈接信息過濾出來。
此時(shí),需要觀察網(wǎng)頁中對應(yīng)圖片的源代碼,我們觀察到其中兩張圖片的對應(yīng)源碼:
圖片1:
<img width="200" height="200" data-img="1" src="http://img13.360buyimg.com/n7/jfs/t6130/167/771989293/235186/608d0264/592bf167Naf49f7f6.jpg">
圖片2:
<img width="200" height="200" data-img="1" src="http://img10.360buyimg.com/n7/g14/M03/0E/0D/rBEhV1Im1n8IAAAAAAcHltD_3_8AAC0FgC-1WoABweu831.jpg">
對比兩張圖片代碼,發(fā)現(xiàn)其基本格式是一樣的,只是圖片的鏈接網(wǎng)址不一樣,所以此時(shí),我們根據(jù)該規(guī)律構(gòu)造出提取圖片鏈接的正則表達(dá)式:
<img width="200" height="200" data-img="1" src="http://(.+?\.jpg)">
剛開始到這里,我以為就結(jié)束了,后來在爬取的過程中我發(fā)現(xiàn)每一頁都少爬取了很多圖片,再次查看源碼發(fā)現(xiàn),每頁后面的幾十張圖片又是另一種格式:
<img width="200" height="200" data-img="1" data-lazy-img="http://img10.360buyimg.com/n7/jfs/t3226/230/618950227/110172/7749a8bc/57bb23ebNfe011bfe.jpg">
所以,完整的正則表達(dá)式應(yīng)該是這兩種格式的或:
<img width="200" height="200" data-img="1" src="http://(.+?\.jpg)">|<img width="200" height="200" data-img="1" data-lazy-img="http://(.+?\.jpg)">
到這里,我們根據(jù)該正則表達(dá)式,就可以提取出一個(gè)頁面中所有想要爬取的圖片鏈接。
所以,根據(jù)上面的分析,我們可以得到該爬蟲的編寫思路與過程,具體如下:
- 建立一個(gè)爬取圖片的自定義函數(shù),該函數(shù)負(fù)責(zé)爬取一個(gè)頁面下的我們想爬取的圖片,爬取過程為:首先通過
urllib.request.utlopen(url).read()
讀取對應(yīng)網(wǎng)頁的全部源代碼,然后根據(jù)上面的第一個(gè)正則表達(dá)式進(jìn)行第一次信息過濾,過濾完成之后,在第一次過濾結(jié)果的基礎(chǔ)上,根據(jù)上面的第二個(gè)正則表達(dá)式進(jìn)行第二次信息過濾,提取出該網(wǎng)頁上所有的目標(biāo)圖片的鏈接,并將這些鏈接地址存儲的一個(gè)列表中,隨后遍歷該列表,分別將對應(yīng)鏈接通過urllib.request.urlretrieve(imageurl,filename=imagename)
存儲到本地,為了避免程序中途異常崩潰,我們可以建立異常處理。 - 通過for循環(huán)將該分類下的所有網(wǎng)頁都爬取一遍,鏈接可以構(gòu)造為url='https://list.jd.com/list.html?cat=1713,3287,3797&page=' + str(i)
完整的代碼如下:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import re import urllib.request import urllib.error import urllib.parse sum = 0 def craw(url,page): html1=urllib.request.urlopen(url).read() html1=str(html1) pat1=r'<div id="plist".+? <div class="page clearfix">' result1=re.compile(pat1).findall(html1) result1=result1[0] pat2=r'<img width="200" height="200" data-img="1" src="http://(.+?\.jpg)">|<img width="200" height="200" data-img="1" data-lazy-img="http://(.+?\.jpg)">' imagelist=re.compile(pat2).findall(result1) x=1 global sum for imageurl in imagelist: imagename='./books/'+str(page)+':'+str(x)+'.jpg' if imageurl[0]!='': imageurl='http://'+imageurl[0] else: imageurl='http://'+imageurl[1] print('開始爬取第%d頁第%d張圖片'%(page,x)) try: urllib.request.urlretrieve(imageurl,filename=imagename) except urllib.error.URLError as e: if hasattr(e,'code') or hasattr(e,'reason'): x+=1 print('成功保存第%d頁第%d張圖片'%(page,x)) x+=1 sum+=1 for i in range(1,251): url='https://list.jd.com/list.html?cat=1713,3287,3797&page='+str(i) craw(url,i) print('爬取圖片結(jié)束,成功保存%d張圖'%sum)
運(yùn)行結(jié)果如下:
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
CentOS 7下Python 2.7升級至Python3.6.1的實(shí)戰(zhàn)教程
Centos是目前最為流行的Linux服務(wù)器系統(tǒng),其默認(rèn)的Python 2.x,這篇文章主要給大家分享了關(guān)于在CentOS 7下Python 2.7升級至Python3.6.1的實(shí)戰(zhàn)教程,文中將升級的步驟一步步的介紹的非常詳細(xì),對大家的理解和學(xué)習(xí)具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-07-07python GUI庫圖形界面開發(fā)之PyQt5信號與槽基礎(chǔ)使用方法與實(shí)例
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5信號與槽基礎(chǔ)使用方法與實(shí)例,需要的朋友可以參考下2020-03-03python np.arange 步長0.1的問題需要特別注意
這篇文章主要介紹了python np.arange 步長0.1的問題需要特別注意,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05Python實(shí)現(xiàn)正則表達(dá)式匹配任意的郵箱方法
今天小編就為大家分享一篇Python實(shí)現(xiàn)正則表達(dá)式匹配任意的郵箱方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-12-12Pandas實(shí)現(xiàn)復(fù)制dataframe中的每一行
這篇文章主要介紹了Pandas實(shí)現(xiàn)復(fù)制dataframe中的每一行方式,2024-02-02pycharm中dgl安裝報(bào)錯FileNotFoundError:Could not find&nb
這篇文章主要介紹了pycharm中dgl安裝報(bào)錯FileNotFoundError:Could not find module ‘E:\XXXX\XXXX\lib\site-packages\dgl\dgl.dl問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02