利用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抢过年的火车票附源码
Dec 07 Python
Python+微信接口实现运维报警
Aug 27 Python
python如何获取服务器硬件信息
May 11 Python
Python爬虫工程师面试问题总结
Mar 22 Python
wxPython的安装与使用教程
Aug 31 Python
详解django中使用定时任务的方法
Sep 27 Python
Python将8位的图片转为24位的图片实现方法
Oct 24 Python
Python操作Excel插入删除行的方法
Dec 10 Python
pycharm创建一个python包方法图解
Apr 10 Python
Django model.py表单设置默认值允许为空的操作
May 19 Python
PHP基于phpqrcode类库生成二维码过程解析
May 28 Python
Python爬虫爬取新闻资讯案例详解
Jul 14 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冒泡排序算法代码详细解读
2011/07/17 PHP
PHP写的获取各搜索蜘蛛爬行记录代码
2012/08/21 PHP
PHP 利用Mail_MimeDecode类提取邮件信息示例
2014/01/26 PHP
自己写了一个php检测文件编码的函数
2014/04/21 PHP
php实现给图片加灰色半透明效果的方法
2014/10/20 PHP
thinkphp Apache配置重启Apache1 restart 出错解决办法
2017/02/15 PHP
PHP receiveMail实现收邮件功能
2018/04/25 PHP
Laravel中如何轻松容易的输出完整的SQL语句
2020/07/26 PHP
showModelessDialog()使用详解
2006/09/21 Javascript
Nodejs+express+html5 实现拖拽上传
2014/08/08 NodeJs
jQuery+css3实现文字跟随鼠标的上下抖动
2015/07/31 Javascript
用jQuery获取table中行id和td值的实现代码
2016/05/19 Javascript
浅谈JavaScript 标准对象
2016/06/02 Javascript
Nodejs进阶:基于express+multer的文件上传实例
2016/11/21 NodeJs
动手写一个angular版本的Message组件的方法
2017/12/16 Javascript
ajax请求+vue.js渲染+页面加载的示例
2018/02/11 Javascript
Vue2 轮播图slide组件实例代码
2018/05/31 Javascript
使用jquery Ajax实现上传附件功能
2018/10/23 jQuery
vue elementUI使用tabs与导航栏联动
2019/06/21 Javascript
layui内置模块layim发送图片添加加载动画的方法
2019/09/23 Javascript
删除目录下相同文件的python代码(逐级优化)
2012/05/25 Python
学习python之编写简单乘法口诀表实现代码
2016/02/27 Python
Python基于递归算法求最小公倍数和最大公约数示例
2018/07/27 Python
pytorch查看torch.Tensor和model是否在CUDA上的实例
2020/01/03 Python
Pytorch 定义MyDatasets实现多通道分别输入不同数据方式
2020/01/15 Python
python使用信号量动态更新配置文件的操作
2020/04/01 Python
1688平价精选商城:阿里集团旗下,工厂出厂价格直销
2017/04/24 全球购物
HearthSong官网:儿童户外玩具、儿童益智玩具
2017/10/16 全球购物
英国手机壳购买网站:Case Hut
2019/04/11 全球购物
酒吧创业计划书
2014/01/18 职场文书
社区党员先进事迹
2014/01/22 职场文书
党员应该树立反腐倡廉的坚定意识思想汇报
2014/09/12 职场文书
法人代表证明书格式
2014/10/01 职场文书
2015年政务公开工作总结
2015/05/19 职场文书
如何书写民事调解协议书?
2019/06/25 职场文书
工厂无线对讲系统解决方案
2022/02/18 无线电