利用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编写分析Python程序性能的工具的教程
Apr 01 Python
python中如何使用正则表达式的集合字符示例
Oct 09 Python
Python字符串、整数、和浮点型数相互转换实例
Aug 04 Python
python+selenium实现自动抢票功能实例代码
Nov 23 Python
python树莓派红外反射传感器
Jan 21 Python
Python Pillow.Image 图像保存和参数选择方式
Jan 09 Python
python+opencv3生成一个自定义纯色图教程
Feb 19 Python
浅谈Django QuerySet对象(模型.objects)的常用方法
Mar 28 Python
python调用API接口实现登陆短信验证
May 10 Python
Python 解决空列表.append() 输出为None的问题
May 23 Python
Python OpenCV实现传统图片格式与base64转换
Jun 13 Python
python接口测试返回数据为字典取值方式
Feb 12 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
简单示例AJAX结合PHP代码实现登录效果代码
2008/07/25 PHP
用PHP来计算某个目录大小的方法
2014/04/01 PHP
PHP session会话操作技巧小结
2016/09/27 PHP
laravel入门知识点整理
2020/09/15 PHP
Riot.js 快速的JavaScript单元测试框架
2009/11/09 Javascript
dojo随手记 gird组件引用
2011/02/24 Javascript
jquery简单实现滚动条下拉DIV固定在头部不动
2013/11/25 Javascript
JavaScript数值转换的三种方式总结
2014/07/31 Javascript
jQuery基于ajax实现星星评论代码
2015/08/07 Javascript
js实现点击文本框显示日期选择器特效代码分享
2020/05/21 Javascript
如何使用jquery easyui创建标签组件
2015/11/18 Javascript
JavaScript动态设置div的样式的方法
2015/12/26 Javascript
angularjs2中父子组件的数据传递的实例代码
2017/07/05 Javascript
Vue项目全局配置微信分享思路详解
2018/05/04 Javascript
javascript少儿编程关于返回值的函数内容
2018/05/27 Javascript
vue-router懒加载的3种方式汇总
2021/02/28 Vue.js
python通过ElementTree操作XML获取结点读取属性美化XML
2013/12/02 Python
理解python正则表达式
2016/01/15 Python
python安装Scrapy图文教程
2017/08/14 Python
python Pandas 读取txt表格的实例
2018/04/29 Python
Python进阶之全面解读高级特性之切片
2019/02/19 Python
Python-openCV读RGB通道图实例
2020/01/17 Python
Django搭建项目实战与避坑细节详解
2020/12/06 Python
html5定位并在百度地图上显示的示例
2014/04/27 HTML / CSS
HTML5页面嵌入小程序没有返回按钮及返回页面空白的问题
2020/05/28 HTML / CSS
Wedgwood美国官网:英国骨瓷,精美礼品及家居装饰
2018/02/17 全球购物
美国帽子俱乐部商店:Hat Club
2019/07/05 全球购物
您熟悉ORM(Object-Relation Mapping)吗?请谈谈您所理解的ORM
2016/02/08 面试题
历史学专业大学生找工作的自我评价
2013/10/16 职场文书
车贷收入证明范本
2014/01/09 职场文书
大二学生职业生涯规划书
2014/02/05 职场文书
六一儿童节主持词
2014/03/21 职场文书
公司活动总结范文
2014/07/01 职场文书
假期安全教育广播稿
2014/10/04 职场文书
教导主任个人总结
2015/03/03 职场文书
2015年高一班主任工作总结
2015/05/13 职场文书