前言:
? 最近自己在做圖片處理工具卖子,最開始的初衷只是為了做一個(gè)圖片深度學(xué)習(xí)項(xiàng)目搀矫,做的時(shí)候缺少大量的圖片素材夏伊,手動(dòng)去下載自己又是比較懶驳规,并且操作起來(lái)非常的麻煩,于是自己寫了一個(gè)單頁(yè)面全圖片的爬蟲署海,等自己實(shí)現(xiàn)完功能之后,發(fā)現(xiàn)又有很多功能是可以優(yōu)化的医男,于是在這個(gè)基礎(chǔ)上我又做了一下功能升級(jí)砸狞,最終出了一個(gè)爬取指定網(wǎng)站所有圖片的版本,當(dāng)然镀梭,這個(gè)版本還有很多可以優(yōu)化的點(diǎn)刀森,我會(huì)在下面的實(shí)際過(guò)程中進(jìn)行說(shuō)明。本篇著重說(shuō)明指定頁(yè)面的圖片抓取报账。
項(xiàng)目目標(biāo):
? 指定某一頁(yè)面進(jìn)行圖片資源進(jìn)行爬取研底,保存到本地硬盤埠偿。
項(xiàng)目分析:
? 1、本項(xiàng)目我們要實(shí)現(xiàn)某一個(gè)指定網(wǎng)站的頁(yè)面URL榜晦,也就是提取href的鏈接冠蒋。并將所有的內(nèi)鏈創(chuàng)建到下一個(gè)任務(wù)當(dāng)中去。
? 2乾胶、除了頁(yè)面中的href鏈接抖剿,我們還要讀取頁(yè)面中所有圖片元素,通過(guò)get方式進(jìn)行訪問(wèn)识窿,讀取后保存斩郎。
簡(jiǎn)單分析了一下,我們開始代碼的實(shí)現(xiàn)
首先完成第2項(xiàng)的功能喻频,我們要將頁(yè)面圖片元素提取出來(lái)缩宜,并寫入到一個(gè)指定的文件目錄當(dāng)中,根據(jù)url中的文件名進(jìn)行保存處理甥温,考慮到我們未來(lái)功能復(fù)用性锻煌,所以我單獨(dú)為單頁(yè)面文件下載實(shí)現(xiàn)了一個(gè)類,(當(dāng)然最終實(shí)現(xiàn)之后窿侈,發(fā)現(xiàn)Python中存在一些問(wèn)題炼幔,這里我們?cè)谖膊吭僮鼋忉專?/p>
我們先定義一個(gè)類,這里命名叫“DownloadImage.py”史简,因?yàn)槭峭ㄟ^(guò)curl方式進(jìn)行抓取采集圖片列表乃秀,我們要定義一個(gè)header頭屬性,以及一個(gè)保存圖片的本地的地址圆兵,定義代碼如下:
headers = {
# 用戶代理
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
_downloadDir = './img/'
因?yàn)檫@個(gè)類我們要復(fù)用跺讯,所以單獨(dú)放到一個(gè)py文件中,方便后面進(jìn)行引用殉农。
在類的構(gòu)造方法中刀脏,我們需要進(jìn)行一個(gè)參數(shù)的初始化。為了下載指定頁(yè)面的圖片超凳,那么我們需要指定一個(gè)頁(yè)面(必要參數(shù))愈污,為了路徑可定義化,我們考慮增加了一個(gè)可選的本地存放的路徑參數(shù)轮傍。 另外暂雹,因?yàn)槊總€(gè)頁(yè)面其實(shí)有些圖片我們是不需要的,比如一些頁(yè)面的logo.gif创夜,style.css中的樣式圖片我們并不需要杭跪,那我們這里就定義了一個(gè)圖片過(guò)濾參數(shù)。
定義完之后我們需要對(duì)對(duì)象中的參數(shù)進(jìn)行賦值,并初始化相關(guān)的參數(shù)涧尿。
def __init__(self,url,download_path=None,filter=[]):
self.url = url
self.initUrl()
self.filter =filter
# 定義圖片下載圖徑
if download_path:
self.downloadPath=self._downloadDir + download_path
else:
self.downloadPath=self._downloadDir + self.urlParse.netloc
self.makeDir()
self.getImages()
首頁(yè)我們?cè)趥魅險(xiǎn)rl之后系奉,將這個(gè)url賦給個(gè)類,方便對(duì)象中直接調(diào)用姑廉,然后我們要將url進(jìn)行一個(gè)格式化缺亮,解析一次。
這個(gè)方法名就是initUrl()庄蹋,方法的主用要途對(duì)過(guò) urlparse方法瞬内,將url的域名和參數(shù)進(jìn)行分離。整理成我們需要的格式限书。
原因是因?yàn)樵趆ttp的頁(yè)面當(dāng)中虫蝶,我們定義圖片會(huì)有幾種格式:
1.絕對(duì)路徑,大部分網(wǎng)站的圖片url都是這樣倦西,單獨(dú)配置了域名資源進(jìn)行顯示
2.相對(duì)路徑能真,有很多網(wǎng)站只有一臺(tái)服務(wù)器,會(huì)把靜態(tài)資源和html文件放在一起
3.某些站點(diǎn)的域名證書綁定是兼容性的扰柠,所以也會(huì)有//前綴進(jìn)行http和https的兼容處理粉铐。
處理完url之后,我們將圖片的過(guò)濾增加進(jìn)去卤档, 方法我不再細(xì)說(shuō)蝙泼,處理方式是通過(guò)正則進(jìn)入搜索匹配來(lái)過(guò)濾的,比如傳入['png','gif']劝枣,那么所有的png和gif都不再被下載汤踏。
然后我們?cè)僬f(shuō)一下makeDir,初始化時(shí)會(huì)判斷文件下載目錄是否存在舔腾,如果不存在溪胶,則新建。
def makeDir(self):
if not os.path.exists(self.downloadPath):
os.makedirs(self.downloadPath)
最后稳诚,我們通過(guò)curl獲取傳參的url頁(yè)面中所有的圖片地址哗脖!
def getImages(self):
response = requests.get(self.url, headers=self.headers)
if response.status_code == 200:
html = et.HTML(response.text)
images = html.xpath('//img/@src')
if self.filter:
match = '|'.join(self.filter)
self.Imageurls = []
for value in images:
if not re.search(match,value):
self.Imageurls.append(value)
else:
self.Imageurls=images
else:
return None
最終類代碼如下:
# 抓取指定網(wǎng)頁(yè)所有圖片保存到本地
import requests
import os
from urllib.parse import *
from lxml import etree as et
import re
import sys
# 請(qǐng)求頭
class DownloadImage(object):
headers = {
# 用戶代理
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
_downloadDir = './img/'
def __init__(self,url,download_path=None,filter=[]):
self.url = url
self.initUrl()
self.filter =filter
# 定義圖片下載圖徑
if download_path:
self.downloadPath=self._downloadDir + download_path
else:
self.downloadPath=self._downloadDir + self.urlParse.netloc
self.makeDir()
self.getImages()
#通用圖片路徑方法格式化
def initUrl(self):
self.urlParse=urlparse(self.url)
def getImages(self):
response = requests.get(self.url, headers=self.headers)
if response.status_code == 200:
html = et.HTML(response.text)
images = html.xpath('//img/@src')
if self.filter:
match = '|'.join(self.filter)
self.Imageurls = []
for value in images:
if not re.search(match,value):
self.Imageurls.append(value)
else:
self.Imageurls=images
else:
return None
#格式化圖片URL
def formatImageUrls(self,url):
imgParase = urlparse(url)
if not imgParase.netloc:
imgpath = "%s://%s/%s" %(self.urlParse.scheme,self.urlParse.netloc,imgParase.path)
else:
imgpath = urljoin(self.url,url)
return imgpath
# 保存圖片
def downloadImage(self,url):
print("download :" + url)
arr = url.split('/')
file_name = self.downloadPath +'/' + arr[-1]
# file_name = self.downloadPath +'/' + arr[-2] +'/' + arr[-1]
try:
response = requests.get(url, headers=self.headers)
with open(file_name, 'wb') as fp:
for data in response.iter_content(128):
fp.write(data)
self.start = self.start+1
return file_name
except:
print("download error")
def makeDir(self):
if not os.path.exists(self.downloadPath):
os.makedirs(self.downloadPath)
def run(self):
for img in self.Imageurls:
self.downloadImage(self.formatImageUrls(img))
相關(guān)的頭文件引用,大家可以參考python手冊(cè)扳还,這里不再細(xì)說(shuō)才避。
新建一個(gè)單頁(yè)的download_image_page.py文件。
import argparse
from DownloadImage import DownloadImage
def getArgv():
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--uri', dest='Url', type=str, default='root', help='target Url')
args= parser.parse_args()
return args.Url
if __name__ == '__main__':
url = getArgv()
obj=DownloadImage(url,None)
obj.run()
在控制臺(tái)中運(yùn)行:python3 download_image_page.py -i https://www.baidu.com
可以看到執(zhí)行結(jié)果氨距。
這里大家注意了桑逝,因?yàn)槲易铋_始要做的是單頁(yè)面采集,最開始設(shè)計(jì)的時(shí)候并未考慮圖片的采集控制衔蹲,這里算是一個(gè)優(yōu)化點(diǎn)。
第一階段結(jié)束,因?yàn)槠蛴呤唬静糠值恼f(shuō)明我將在下一篇中進(jìn)行講解說(shuō)明橱健。當(dāng)然,代碼已經(jīng)上傳沙廉,感興趣的朋友可以先行clone拘荡。
代碼地址:https://gitee.com/python_play/download_image
本文是“明哥陪你學(xué)Python”系列章節(jié)之一,如果你對(duì)Python有更多興趣撬陵,或有問(wèn)題珊皿,可以私信與明哥聯(lián)系,我會(huì)陪你一起解決巨税,其它相關(guān)章節(jié)可以從首頁(yè)中的“明哥陪你學(xué)Python”列表進(jìn)行查看蟋定。
本系列教程及源碼地址:點(diǎn)擊訪問(wèn)
最后:如果你正在學(xué)習(xí)Python的路上,或者準(zhǔn)備打算學(xué)習(xí)Python草添、明哥會(huì)陪著你陪你一起共同進(jìn)步驶兜!
手打不易,有用的話远寸,請(qǐng)記得關(guān)注轉(zhuǎn)發(fā)抄淑。