利用Python多线程实现图片下载器


Posted in Python onMarch 25, 2022

导语

之前有很多小伙伴说想学习一下多线程图片下载器,虽然好像已经过去很久了,不过还是上来安排一波吧。至于题目为什么说是构建一个小型数据集,因为公众号之后的文章应该还会用到它来构建一些简单的图像分类数据集,换句话说,后续一段时间,公众号会主要写一些深度学习机器学习相关的文章,下期文章揭晓具体内容。

废话不多说,让我们愉快地开始近期最后一篇爬虫文章~

开发工具

Python版本:3.7.8

相关模块:

requests模块;

alive-progress模块;

pyfreeproxy模块;

user_agent模块;

beautifulsoup4模块;

lxml模块;

以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

原理简介

我看了下,发现大家基本都是从百度,必应和谷歌来根据给定的关键字下载相关的图片数据的,所以我们也选用这三个数据源。具体而言,百度的图片搜索接口如下:

'https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&lm=7&fp=result&ie=utf-8&oe=utf-8&st=-1&word={}&queryWord={}&face=0&pn={}&rn={}'

为了可以多线程地进行图片搜索,我们先根据想要下载的图片数量来构造所有请求页的链接如下:

search_urls, pagesize = [], 30
for pn in range(math.ceil(search_limits * 1.2 / pagesize)):
    search_url = base_url.format(quote(keyword), quote(keyword), pn * pagesize, pagesize)
    search_urls.append(search_url)

然后再多线程请求所有构造好的搜索链接:

# 多线程请求获取所有图片链接
def searchapi(self, search_urls, image_urls, bar):
    while len(search_urls) > 0:
        search_url = search_urls.pop(0)
        response = self.get(search_url)
        if response is None: 
            bar()
            continue
        response.encoding = 'utf-8'
        response_json = json.loads(response.text.replace(r"\'", ""), encoding='utf-8', strict=False)
        for item in response_json['data']:
            if 'objURL' in item.keys():
                image_urls.add(self.parseurl(item['objURL']))
            elif 'replaceUrl' in item.keys() and len(item['replaceUrl']) == 2:
                image_urls.add(item['replaceUrl'][1]['ObjURL'])
        bar()
task_pool, image_urls = [], set()
with alive_bar(min(len(search_urls), search_limits)) as bar:
    for idx in range(num_threadings):
        task = threading.Thread(
            target=searchapi,
            args=(self, search_urls, image_urls, bar)
        )
        task_pool.append(task)
        task.start()
    for task in task_pool: task.join()

线程结束的条件为我们构造的所有请求页链接search_urls全部被用完。这里我们用的最基本的python的threading库,感觉python应该还有很多更加好用的多线程库,感兴趣的小伙伴可以自己查查资料,不必拘泥于我写的内容。threading库的话调用方便,只需要target指定目标函数,args指定目标函数输入的参数,然后start一下就行,所以我图省事就直接用它了。

类似地,我们也可以根据得到的image_urls写个多线程的图片下载器:

'''下载'''
def download(self, keyword, search_limits=1000, num_threadings=5, savedir='outputs'):
    touchdir(savedir)
    # 获得image_urls
    self.logging(f'Start to search images from {self.source_name}')
    image_urls = self.search(keyword, search_limits, num_threadings)
    # 多线程下载图片
    self.logging(f'Start to download images from {self.source_name}')
    def downloadapi(self, savepaths, image_urls, bar):
        assert len(savepaths) == len(image_urls)
        while len(image_urls) > 0:
            savepath, image_url = savepaths.pop(0), image_urls.pop(0)
            response = self.get(image_url)
            if response is None: 
                bar()
                continue
            with open(savepath, 'wb') as fp: fp.write(response.content)
            filetype = imghdr.what(savepath)
            if filetype in ['jpg', 'jpeg', 'png', 'bmp', 'gif']:
                savepath_correct = f'{savepath}.{filetype}'
                shutil.move(savepath, savepath_correct)
            else:
                os.remove(savepath)
            bar()
    task_pool, savepaths = [], []
    for idx in range(len(image_urls)):
        savename = f'image_{str(idx).zfill(8)}'
        savepaths.append(os.path.join(savedir, savename))
    with alive_bar(len(image_urls)) as bar:
        for idx in range(num_threadings):
            task = threading.Thread(
                target=downloadapi,
                args=(self, savepaths, image_urls, bar)
            )
            task_pool.append(task)
            task.start()
        for task in task_pool: task.join()

然后必应的图片搜索接口如下:

# 构建所有urls
base_url = 'https://cn.bing.com/images/async?q={}&first={}&count={}&cw=1536&ch=240&relp={}&tsc=ImageBasicHover&datsrc=I&layout=RowBased&mmasync=1&dgState=x*1063_y*768_h*186_c*5_i*71_r*10&IG=D6A4AD486F3A49F1BE164BC50750D641&SFX=3&iid=images.5555'
search_urls, pagesize = [], 35
for pn in range(math.ceil(search_limits * 1.2 / pagesize)):
    search_url = base_url.format(quote(keyword), pn * pagesize, pagesize, pagesize)
    search_urls.append(search_url)

谷歌的图片搜索接口如下:

# 构建所有urls
base_url = 'https://www.google.com/search?'
search_urls, pagesize = [], 20
for pn in range(math.ceil(search_limits * 1.2 / pagesize)):
    params = {
        'q': keyword,
        'ijn': pn,
        'start': pn * pagesize,
        'tbs': '',
        'tbm': 'isch',
    }
    search_urls.append(base_url + urlencode(params))

具体的多线程搜索和下载图片的写法和百度的类似,大功告成啦。

效果展示

你只需要pip安装一下,就可以直接在终端运行了。安装命令如下:

pip install pyimagedl

使用方式如下:

Usage: imagedl [OPTIONS]

Options:
  --version                  Show the version and exit.
  -k, --keyword TEXT         想要搜索下载的图片关键字, 若不指定, 则进入imagedl终端版
  -s, --savedir TEXT         下载的图片的保存路径
  -t, --target TEXT          指定图片搜索下载的平台, 例如"baidu"
  -l, --limits INTEGER       下载的图片数量
  -n, --nthreadings INTEGER  使用的线程数量
  --help                     Show this message and exit.

例如,在终端输入:

imagedl -k 狗狗 -s dogs -t baidu -l 1000

利用Python多线程实现图片下载器

到此这篇关于利用Python多线程实现图片下载器的文章就介绍到这了,更多相关Python图片下载内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
采用python实现简单QQ单用户机器人的方法
Jul 03 Python
分析Python中设计模式之Decorator装饰器模式的要点
Mar 02 Python
Python开发最牛逼的IDE——pycharm
Aug 01 Python
对Python发送带header的http请求方法详解
Jan 02 Python
pandas实现将dataframe满足某一条件的值选出
Jun 12 Python
对Python生成器、装饰器、递归的使用详解
Jul 19 Python
python实现将文件夹内的每张图片批量分割成多张
Jul 22 Python
python3.6连接mysql数据库及增删改查操作详解
Feb 10 Python
keras 获取某层输出 获取复用层的多次输出实例
May 23 Python
Python代码注释规范代码实例解析
Aug 14 Python
Django 实现图片上传和下载功能
Dec 31 Python
pycharm 实现调试窗口恢复
Feb 05 Python
Python实现灰色关联分析与结果可视化的详细代码
聊聊基于pytorch实现Resnet对本地数据集的训练问题
pycharm安装深度学习pytorch的d2l包失败问题解决
利用For循环遍历Python字典的三种方法实例
Mar 25 #Python
Python装饰器详细介绍
Mar 25 #Python
python中数组和列表的简单实例
Mar 25 #Python
Python if else条件语句形式详解
You might like
多php服务器实现多session并发运行
2006/10/09 PHP
从PHP的源码中深入了解stdClass类
2014/04/18 PHP
PHP处理Json字符串解码返回NULL的解决方法
2014/09/01 PHP
form表单传递数组数据、php脚本接收的实例
2017/02/09 PHP
PHP简单实现欧拉函数Euler功能示例
2017/11/06 PHP
Ajax搜索结果页面下方的分页按钮的生成
2012/04/05 Javascript
JQuery弹出炫丽对话框的同时让背景变灰色
2014/05/22 Javascript
JSON与XML优缺点对比分析
2015/07/17 Javascript
jQuery插件ajaxFileUpload异步上传文件
2016/10/19 Javascript
jQuery轻松实现无缝轮播效果
2017/03/22 jQuery
JS判断一个数是否是水仙花数
2017/06/11 Javascript
Vue应用部署到服务器的正确方式
2017/07/15 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
2017/07/17 Javascript
使用Nuxt.js改造已有项目的方法
2018/08/07 Javascript
react build 后打包发布总结
2018/08/24 Javascript
JS canvas实现画板和签字板功能
2021/02/23 Javascript
python 合并文件的具体实例
2013/08/08 Python
python+opencv实现的简单人脸识别代码示例
2017/11/14 Python
python 实现矩阵上下/左右翻转,转置的示例
2019/01/23 Python
python实现整数的二进制循环移位
2019/03/08 Python
Python学习笔记之pandas索引列、过滤、分组、求和功能示例
2019/06/03 Python
Python数据分析模块pandas用法详解
2019/09/04 Python
django自定义非主键自增字段类型详解(auto increment field)
2020/03/30 Python
解决TensorFlow调用Keras库函数存在的问题
2020/07/06 Python
scrapy头部修改的方法详解
2020/12/06 Python
Java中会存在内存泄漏吗,请简单描述
2016/12/22 面试题
女方婚礼新郎答谢词
2014/01/11 职场文书
股份合作协议书
2014/09/10 职场文书
未婚证明书模板
2014/10/08 职场文书
2016特色励志班级口号
2015/12/24 职场文书
《家》读后感:万惜拯救,冷暖自知
2019/09/25 职场文书
AI:如何训练机器学习的模型
2021/04/16 Python
详解JS WebSocket断开原因和心跳机制
2021/05/07 Javascript
常用的Python代码调试工具总结
2021/06/23 Python
记一次Mysql不走日期字段索引的原因小结
2021/10/24 MySQL
Python OpenCV之常用滤波器使用详解
2022/04/07 Python