爬蟲實戰:一鍵爬光指定網站所有圖片(一)

前言:

​ 最近自己在做圖片處理工具,最開始的初衷只是為了做一個圖片深度學習項目,做的時候缺少大量的圖片素材,手動去下載自己又是比較懶,並且操作起來非常的麻煩,於是自己寫了一個單頁面全圖片的爬蟲,等自己實現完功能之後,發現又有很多功能是可以優化的,於是在這個基礎上我又做了一下功能升級,最終出了一個爬取指定網站所有圖片的版本,我會在下面的實際過程中進行說明。本篇著重說明指定頁面的圖片抓取。

本教程最終結果已錄視頻:


項目目標:

​ 指定某一頁面進行圖片資源進行爬取,保存到本地硬盤。

項目分析:

​ 1、本項目我們要實現某一個指定網站的頁面URL,也就是提取href的鏈接。並將所有的內鏈創建到下一個任務當中去。

​ 2、除了頁面中的href鏈接,我們還要讀取頁面中所有圖片元素,通過get方式進行訪問,讀取後保存。

簡單分析了一下,我們開始代碼的實現

首先完成第2項的功能,我們要將頁面圖片元素提取出來,並寫入到一個指定的文件目錄當中,根據url中的文件名進行保存處理,考慮到我們未來功能複用性,所以我單獨為單頁面文件下載實現了一個類,(當然最終實現之後,發現Python中存在一些問題,這裡我們在尾部再做解釋)

我們先定義一個類,這裡命名叫“DownloadImage.py”,因為是通過curl方式進行抓取採集圖片列表,我們要定義一個header頭屬性,以及一個保存圖片的本地的地址,定義代碼如下:

<code>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/'/<code>

因為這個類我們要複用,所以單獨放到一個py文件中,方便後面進行引用。

在類的構造方法中,我們需要進行一個參數的初始化。為了下載指定頁面的圖片,那麼我們需要指定一個頁面(必要參數),為了路徑可定義化,我們考慮增加了一個可選的本地存放的路徑參數。 另外,因為每個頁面其實有些圖片我們是不需要的,比如一些頁面的logo.gif,style.css中的樣式圖片我們並不需要,那我們這裡就定義了一個圖片過濾參數。

定義完之後我們需要對對象中的參數進行賦值,並初始化相關的參數。

<code>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()/<code>

首頁我們在傳入Url之後,將這個url賦給個類,方便對象中直接調用,然後我們要將url進行一個格式化,解析一次。

這個方法名就是initUrl(),方法的主用要途對過 urlparse方法,將url的域名和參數進行分離。整理成我們需要的格式。

原因是因為在http的頁面當中,我們定義圖片會有幾種格式:

1.絕對路徑,大部分網站的圖片url都是這樣,單獨配置了域名資源進行顯示

2.相對路徑,有很多網站只有一臺服務器,會把靜態資源和html文件放在一起

3.某些站點的域名證書綁定是兼容性的,所以也會有//前綴進行http和https的兼容處理。

處理完url之後,我們將圖片的過濾增加進去, 方法我不再細說,處理方式是通過正則進入搜索匹配來過濾的,比如傳入['png','gif'],那麼所有的png和gif都不再被下載。

然後我們再說一下makeDir,初始化時會判斷文件下載目錄是否存在,如果不存在,則新建。

<code>def makeDir(self):
if not os.path.exists(self.downloadPath):
os.makedirs(self.downloadPath)/<code>

最後,我們通過curl獲取傳參的url頁面中所有的圖片地址!

<code>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/<code>

最終類代碼如下:

<code># 抓取指定網頁所有圖片保存到本地
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))/<code>

相關的頭文件引用,大家可以參考python手冊,這裡不再細說。

新建一個單頁的download_image_page.py文件。

<code>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()/<code>

在控制檯中運行:python3 download_image_page.py -i https://www.baidu.com

可以看到執行結果。

這裡大家注意了,因為我最開始要做的是單頁面採集,最開始設計的時候並未考慮圖片的採集控制,這裡算是一個優化點。

第一階段結束,因為篇幅原因,整站部分的說明我將在下一篇中進行講解說明。當然,代碼已經上傳,感興趣的朋友可以先行clone。

代碼地址:https://gitee.com/python_play/download_image

本文是“明哥陪你學Python”系列章節之一,如果你對Python有更多興趣,或有問題,可以私信與明哥聯繫,我會陪你一起解決,其它相關章節可以從首頁中的“明哥陪你學Python”列表進行查看。

本系列教程及源碼地址:https://gitee.com/python_play/study_python

最後:如果你正在學習Python的路上,或者準備打算學習Python、明哥會陪著你陪你一起共同進步!

手打不易,有用的話,請記得關注轉發。


分享到:


相關文章: