利用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实现进程同步和通信的方法
Jan 02 Python
python try except 捕获所有异常的实例
Oct 18 Python
使用matplotlib中scatter方法画散点图
Mar 19 Python
python实现海螺图片的方法示例
May 12 Python
python+numpy实现的基本矩阵操作示例
Jul 19 Python
Python有参函数使用代码实例
Jan 06 Python
Python dict和defaultdict使用实例解析
Mar 12 Python
Python 如何创建一个简单的REST接口
Jul 30 Python
如何实现一个python函数装饰器(Decorator)
Oct 12 Python
Python中正则表达式对单个字符,多个字符和匹配边界等使用
Jan 27 Python
一行代码python实现文件共享服务器
Apr 22 Python
利用Python第三方库实现预测NBA比赛结果
Jun 21 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
第一个无线电台是由谁发明的
2021/03/01 无线电
ThinkPHP实现将本地文件打包成zip下载
2014/06/26 PHP
php输出含有“#”字符串的方法
2017/01/18 PHP
PHP环形链表实现方法示例
2017/09/15 PHP
Thinkphp 框架扩展之行为扩展原理与实现方法分析
2020/04/23 PHP
理解JavaScript中的事件
2006/09/23 Javascript
javascript 类定义的4种方法
2009/09/12 Javascript
让Firefox支持event对象实现代码
2009/11/07 Javascript
由JavaScript中call()方法引发的对面向对象继承机制call的思考
2011/09/12 Javascript
JAVASCRIPT车架号识别/验证函数代码 汽车车架号验证程序
2012/01/08 Javascript
解决js正则匹配换行问题实现代码
2012/12/10 Javascript
jQuery文本框(input textare)事件绑定方法教程
2013/04/24 Javascript
JavaScript打印iframe内容示例代码
2013/08/20 Javascript
jquery中获得元素尺寸和坐标的方法整理
2014/05/18 Javascript
基于JavaScript代码实现随机漂浮图片广告
2016/01/05 Javascript
javascript防篡改对象实例详解
2017/04/10 Javascript
webpack处理 css\less\sass 样式的方法
2017/08/21 Javascript
angular内置provider之$compileProvider详解
2017/09/27 Javascript
webpack分离css单独打包的方法
2018/06/12 Javascript
Vue项目服务器部署之子目录部署方法
2019/05/12 Javascript
JS控制GIF图片的停止与显示
2019/10/24 Javascript
python处理csv数据的方法
2015/03/11 Python
python中安装模块包版本冲突问题的解决
2017/05/02 Python
Python命令行解析模块详解
2018/02/01 Python
浅谈Python中的zip()与*zip()函数详解
2018/02/24 Python
django orm 通过related_name反向查询的方法
2018/12/15 Python
Python使用GitPython操作Git版本库的方法
2020/02/29 Python
Django def clean()函数对表单中的数据进行验证操作
2020/07/09 Python
canvas如何实现多张图片编辑的图片编辑器
2020/03/10 HTML / CSS
SEPHORA丝芙兰捷克官网:购买香水、化妆品和护肤品
2018/11/26 全球购物
Linux的文件类型
2016/07/05 面试题
Linux内核产生并发的原因
2016/11/08 面试题
JAVA高级程序员面试题
2013/09/06 面试题
高中军训感想300字
2014/03/04 职场文书
五好文明家庭事迹材料
2014/12/20 职场文书
大学生入党自传2015
2015/06/26 职场文书