前言:
最近自己在做圖片處理工具,最開始的初衷只是爲了做一個圖片深度學習項目,做的時候缺少大量的圖片素材,手動去下載自己又是比較懶,並且操作起來非常的麻煩,於是自己寫了一個單頁面全圖片的爬蟲,等自己實現完功能之後,發現又有很多功能是可以優化的,於是在這個基礎上我又做了一下功能升級,最終出了一個爬取指定網站所有圖片的版本,當然,這個版本還有很多可以優化的點,我會在下面的實際過程中進行說明。本篇着重說明指定頁面的圖片抓取。
項目目標:
指定某一頁面進行圖片資源進行爬取,保存到本地硬盤。
項目分析:
1、本項目我們要實現某一個指定網站的頁面URL,也就是提取href的鏈接。並將所有的內鏈創建到下一個任務當中去。
2、除了頁面中的href鏈接,我們還要讀取頁面中所有圖片元素,通過get方式進行訪問,讀取後保存。
簡單分析了一下,我們開始代碼的實現
首先完成第2項的功能,我們要將頁面圖片元素提取出來,並寫入到一個指定的文件目錄當中,根據url中的文件名進行保存處理,考慮到我們未來功能複用性,所以我單獨爲單頁面文件下載實現了一個類,(當然最終實現之後,發現Python中存在一些問題,這裏我們在尾部再做解釋)
我們先定義一個類,這裏命名叫“DownloadImage.py”,因爲是通過curl方式進行抓取採集圖片列表,我們要定義一個header頭屬性,以及一個保存圖片的本地的地址,定義代碼如下:
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/'
因爲這個類我們要複用,所以單獨放到一個py文件中,方便後面進行引用。
在類的構造方法中,我們需要進行一個參數的初始化。爲了下載指定頁面的圖片,那麼我們需要指定一個頁面(必要參數),爲了路徑可定義化,我們考慮增加了一個可選的本地存放的路徑參數。 另外,因爲每個頁面其實有些圖片我們是不需要的,比如一些頁面的logo.gif,style.css中的樣式圖片我們並不需要,那我們這裏就定義了一個圖片過濾參數。
定義完之後我們需要對對象中的參數進行賦值,並初始化相關的參數。
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()
首頁我們在傳入Url之後,將這個url賦給個類,方便對象中直接調用,然後我們要將url進行一個格式化,解析一次。
這個方法名就是initUrl(),方法的主用要途對過 urlparse方法,將url的域名和參數進行分離。整理成我們需要的格式。
原因是因爲在http的頁面當中,我們定義圖片會有幾種格式:
1.絕對路徑,大部分網站的圖片url都是這樣,單獨配置了域名資源進行顯示
2.相對路徑,有很多網站只有一臺服務器,會把靜態資源和html文件放在一起
3.某些站點的域名證書綁定是兼容性的,所以也會有//前綴進行http和https的兼容處理。
處理完url之後,我們將圖片的過濾增加進去, 方法我不再細說,處理方式是通過正則進入搜索匹配來過濾的,比如傳入[‘png’,‘gif’],那麼所有的png和gif都不再被下載。
然後我們再說一下makeDir,初始化時會判斷文件下載目錄是否存在,如果不存在,則新建。
def makeDir(self):
if not os.path.exists(self.downloadPath):
os.makedirs(self.downloadPath)
最後,我們通過curl獲取傳參的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
最終類代碼如下:
# 抓取指定網頁所有圖片保存到本地
import requests
import os
from urllib.parse import *
from lxml import etree as et
import re
import sys
# 請求頭
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))
相關的頭文件引用,大家可以參考python手冊,這裏不再細說。
新建一個單頁的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()
在控制檯中運行:python3 download_image_page.py -i https://www.baidu.com
可以看到執行結果。
這裏大家注意了,因爲我最開始要做的是單頁面採集,最開始設計的時候並未考慮圖片的採集控制,這裏算是一個優化點。
第一階段結束,因爲篇幅原因,整站部分的說明我將在下一篇中進行講解說明。當然,代碼已經上傳,感興趣的朋友可以先行clone。
代碼地址:https://gitee.com/python_play/download_image
本文是“明哥陪你學Python”系列章節之一,如果你對Python有更多興趣,或有問題,可以私信與明哥聯繫,我會陪你一起解決,其它相關章節可以從首頁中的“明哥陪你學Python”列表進行查看。
本系列教程及源碼地址:點擊訪問
最後:如果你正在學習Python的路上,或者準備打算學習Python、明哥會陪着你陪你一起共同進步!
手打不易,有用的話,請記得關注轉發。