底層:?jiǎn)尉W(wǎng)頁(yè)多圖下載
一系冗、實(shí)驗(yàn)說(shuō)明
1.1. 環(huán)境登錄
無(wú)需密碼自動(dòng)登錄,系統(tǒng)用戶名shiyanlou
1.2. 環(huán)境介紹
本實(shí)驗(yàn)環(huán)境采用帶桌面的Ubuntu Linux環(huán)境绢记,實(shí)驗(yàn)中會(huì)用到桌面上的程序:
- Xfce終端: Linux命令行終端扁达,打開(kāi)后會(huì)進(jìn)入shell環(huán)境,可以使用Linux命令
- Firefox:瀏覽器蠢熄,可以用在需要前端界面的課程里罩驻,只需要打開(kāi)環(huán)境里寫的HTML/JS頁(yè)面即可
- GVim:非常好用的編輯器,最簡(jiǎn)單的用法可以參考課程Vim編輯器
1.3. 環(huán)境使用
使用GVim編輯器輸入實(shí)驗(yàn)所需的代碼及文件护赊,使用Xfce終端運(yùn)行所需命令進(jìn)行操作惠遏。
實(shí)驗(yàn)報(bào)告可以在個(gè)人主頁(yè)中查看,其中含有每次實(shí)驗(yàn)的截圖及筆記骏啰,以及每次實(shí)驗(yàn)的有效學(xué)習(xí)時(shí)間(指的是在實(shí)驗(yàn)桌面內(nèi)操作的時(shí)間节吮,如果沒(méi)有操作,系統(tǒng)會(huì)記錄為發(fā)呆時(shí)間)判耕。這些都是您學(xué)習(xí)的真實(shí)性證明透绩。
實(shí)驗(yàn)樓虛擬機(jī),自帶了python2.X和python3.X版本壁熄,無(wú)需安裝帚豪,本實(shí)驗(yàn)基于 python2。
二草丧、課程介紹
這一節(jié)呢狸臣,利用上一節(jié)提到的知識(shí)點(diǎn),進(jìn)行單網(wǎng)頁(yè)的圖片爬取和下載至本地
三昌执、功能詳解
- 從網(wǎng)頁(yè)的html中烛亦,獲取我們需要的圖片鏈接,打開(kāi)網(wǎng)頁(yè)懂拾,這個(gè)頁(yè)面下煤禽,一共有10張圖片是我們需要爬取的,查看網(wǎng)頁(yè)源碼岖赋,找到這十張圖片的代碼檬果,都是
- der查閱這個(gè)鏈接html時(shí)中文全為亂碼知牌,我也就放棄了中文匹配祈争,我用的笨方法就是先找父標(biāo)簽,依次往里直至尋找到img標(biāo)簽角寸,具體路徑如下
body標(biāo)簽 -> wrapper -> container -> pagecontent -> maincontent -> postContent -> picture -> p (查閱HTML源碼菩混,我只用了后面三個(gè))
匹配用到的正則表達(dá)式(我用id和class匹配):
'<div.*?class="postContent.*?>.*?<p>(.*?)</p>' 獲取圖片鏈接那段html代碼
'<div.*?id="picture.*?>.*?<p>(.*?)</p>' 查閱上級(jí)獲得的html中,picture那塊代碼
'<img.*?src="(.*?)".*?>' 從上一個(gè)表達(dá)式中扁藕,獲取圖片鏈接
- 從鏈接中獲得圖片名沮峡,也是正則表達(dá)式獲取
'.*/(.*?.jpg)' 從圖片鏈接中,提取圖片名亿柑,這個(gè)是最簡(jiǎn)單的
- 打開(kāi)圖片鏈接邢疙,在本地創(chuàng)建文件,保存望薄,這里呢疟游,有個(gè)小功能,保證以后更新不重復(fù)下載
判斷文件時(shí)候存在痕支,如果存在颁虐,不下載,節(jié)約時(shí)間
如果文件不存在卧须,下一步創(chuàng)建新文件另绩,讀寫模式打開(kāi)
打開(kāi)圖片鏈接,將緩存寫入到文件中
關(guān)閉圖片文件花嘶,完成
以上呢就是本節(jié)內(nèi)容要實(shí)現(xiàn)的全部功能笋籽,接下來(lái)貼上代碼
四、功能代碼
這里呢椭员,按功能的先后順序车海,逆序貼代碼,不過(guò)代碼有點(diǎn)長(zhǎng)拆撼,我會(huì)在'def'后面附上注釋
#文件名:meizi_page_download
import urllib2
import os
import re
#loadurl()這個(gè)函數(shù)呢容劳,是防打開(kāi)鏈接超時(shí),如果超時(shí)返回空字符闸度,則主調(diào)函數(shù)會(huì)再次調(diào)用(while語(yǔ)句就可以實(shí)現(xiàn)),正常的話返回html代碼蚜印,一個(gè)網(wǎng)頁(yè)不算大莺禁,如果你的網(wǎng)絡(luò)超級(jí)好,timeout可以縮短
def loadurl(url):
try:
conn = urllib2.urlopen(url,timeout=5)
html = conn.read()
return html
except urllib2.URLError:
return ''
except Exception:
print("unkown exception in conn.read()")
return ''
#這里是圖片保存的代碼被調(diào)函數(shù)窄赋,timeout=5設(shè)置超時(shí)時(shí)間哟冬,一個(gè)500k不到的圖片楼熄,5秒時(shí)間算長(zhǎng)的了,超時(shí)的話浩峡,返回失敗
def download(url,filename):
try:
conn = urllib2.urlopen(url,timeout=5)
f = open(filename,'wb')
f.write(conn.read())
f.close()
return True
except urllib2.URLError:
print 'load',url,'error'
return False
except Exception:
print("unkown exception in conn.read()")
return ''
#保存圖片的邏輯代碼塊
def save_pic(url,path):
searchname = '.*/(.*?.jpg)'
name = re.findall(searchname,url)
filename = path +'/'+ name[0]
print filename + ':start' #控制臺(tái)顯示信息
#下面的代碼可岂,當(dāng)下載成功,break跳出就好了翰灾,如果存在缕粹,直接結(jié)束這個(gè)函數(shù)
#定義了在下載圖片時(shí)遇到錯(cuò)誤的重試次數(shù)
tryTimes = 3
#當(dāng)重試次數(shù)沒(méi)有用完時(shí),則嘗試下載
while tryTimes != 0:
tryTimes -= 1
if os.path.exists(filename):
print filename,' exists, skip'
return True
elif os.path.exists(filename):
os.mknod(filename)
if download(url,filename):
break
if tryTimes != 0:
print(filename + ": over")
else:
print(url + " :Failed to download")
#控制臺(tái)顯示信息
#這個(gè)函數(shù)纸淮,相當(dāng)于一個(gè)中介平斩,我只是把for循環(huán)代碼提出就得到了這個(gè)函數(shù)
def pic_list(picList,path):
picurl = ''
for picurl in picList:
save_pic(picurl,path)
#圖片下載的主邏輯函數(shù),獲取圖片鏈接咽块,然后傳給pic_list()绘面,等結(jié)果(其實(shí)也沒(méi)結(jié)果,就是等退出)
def picurl(url,path):
if os.path.exists(path):
print path, 'exist'
else:
os.makedirs(path)
html = ''
while True:#這里和下載圖片是一個(gè)道理侈沪,細(xì)看即可
html = loadurl(url)
if html == '':
print 'load', url,'error'
continue
else:
break
#其實(shí)這里呢揭璃,也是后期發(fā)現(xiàn)的一個(gè)小bug,這個(gè)網(wǎng)站的前后代碼有不同(目前而言發(fā)現(xiàn)的一處)亭罪,在rePicContent1運(yùn)行到后面瘦馍,是匹配不到的,導(dǎo)致rePicList返回的結(jié)果也是空皆撩,也就造成了這個(gè)符號(hào)[0]報(bào)錯(cuò)扣墩,因?yàn)闆](méi)有任何值,越界錯(cuò)誤,單線程會(huì)在這里報(bào)錯(cuò)并停止運(yùn)行扛吞。rePicContent2其實(shí)是我解決bug的另一個(gè)匹配正則式呻惕,被我發(fā)現(xiàn)的頁(yè)面是這個(gè)--http://www.meizitu.com/a/454.html,有興趣的去對(duì)比看看
rePicContent1 = '<div.*?id="picture.*?>.*?<p>(.*?)</p>'
rePicContent2 = '<div.*?class="postContent.*?>.*?<p>(.*?)</p>'
rePicList = '<img.*?src="(.*?)".*?>'
#這里對(duì)re.S做個(gè)介紹滥比,re.S是可以不添加的亚脆,加上之后,它的作用就是能忽略換行符盲泛,將兩條作為一條來(lái)匹配濒持。html代碼碰上換行的概率是很高的,所以我一致采用re.S(下文有配圖)
picContent = re.findall(rePicContent1, html,re.S)
if len(picContent) <=0:
picContent = re.findall(rePicContent2, html,re.S)
if len(picContent) <=0:
print 'load false, over download this page and return'
return False
else:
picList = re.findall(rePicList,picContent[0],re.S)
pic_list(picList,path)
#url = 'http://www.meizitu.com/a/454.html'這兩行是我函數(shù)測(cè)試所用
#picurl(url,'/home/shiyanlou/Desktop/demo454')
聲明寺滚,在運(yùn)行代碼的時(shí)候柑营,保險(xiǎn)起見(jiàn)別插入中文,特別是linux環(huán)境村视,容易報(bào)錯(cuò)官套,另外在這里附上re.S的截圖(沒(méi)有3吧)代碼到這里就結(jié)束了,底層的圖片獲取鏈接并保存,完成奶赔,附上實(shí)驗(yàn)樓的截圖一張(一開(kāi)始報(bào)錯(cuò)惋嚎,第二次就好了,運(yùn)行之前,請(qǐng)確保你有外網(wǎng)權(quán)限站刑,用下Firefox看下網(wǎng)站就行另伍,如果沒(méi)用,請(qǐng)本機(jī)測(cè)試)
請(qǐng)繼續(xù)下一個(gè)實(shí)驗(yàn)
Python3教程绞旅、項(xiàng)目網(wǎng)站--傳送門