爬虫实战:一键爬光指定网站所有图片(一)

前言:

​ 最近自己在做图片处理工具,最开始的初衷只是为了做一个图片深度学习项目,做的时候缺少大量的图片素材,手动去下载自己又是比较懒,并且操作起来非常的麻烦,于是自己写了一个单页面全图片的爬虫,等自己实现完功能之后,发现又有很多功能是可以优化的,于是在这个基础上我又做了一下功能升级,最终出了一个爬取指定网站所有图片的版本,当然,这个版本还有很多可以优化的点,我会在下面的实际过程中进行说明。本篇着重说明指定页面的图片抓取。

项目目标:

​ 指定某一页面进行图片资源进行爬取,保存到本地硬盘。

项目分析:

​ 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、明哥会陪着你陪你一起共同进步!

手打不易,有用的话,请记得关注转发。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容