利用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设置windows桌面壁纸的实现代码
Jan 28 Python
python读写ini文件示例(python读写文件)
Mar 25 Python
Python中的XML库4Suite Server的介绍
Apr 14 Python
Python操作配置文件ini的三种方法讲解
Feb 22 Python
Python3.6实现带有简单界面的有道翻译小程序
Apr 16 Python
python 实现查找文件并输出满足某一条件的数据项方法
Jun 12 Python
Python 中Django安装和使用教程详解
Jul 03 Python
使用python实现unix2dos和dos2unix命令的例子
Aug 13 Python
Python模块/包/库安装的六种方法及区别
Feb 24 Python
Python 爬取必应壁纸的实例讲解
Feb 24 Python
Python Excel vlookup函数实现过程解析
Jun 22 Python
pandas 按日期范围筛选数据的实现
Feb 20 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/03 咖啡文化
mysql 中InnoDB和MyISAM的区别分析小结
2008/04/15 PHP
PHP 飞信好友免费短信API接口开源版
2010/07/22 PHP
php实现的数字验证码及数字运算验证码
2015/07/30 PHP
PHP正则表达式过滤html标签属性(DEMO)
2016/05/04 PHP
php中实现进程锁与多进程的方法
2016/09/18 PHP
PHP快速导出百万级数据到CSV或者EXCEL文件
2020/11/27 PHP
给Javascript数组插入一条记录的代码
2007/08/30 Javascript
不提示直接关闭网页窗口的JS示例代码
2013/12/17 Javascript
jQuery使用animate创建动画用法实例
2015/08/07 Javascript
Javascript实现登录记住用户名和密码功能
2017/03/22 Javascript
详解React 16 中的异常处理
2017/07/28 Javascript
使用vue-cli编写vue插件的方法
2018/02/26 Javascript
javascript删除数组元素的七个方法示例
2019/09/09 Javascript
JavaScript实现表单验证功能
2020/12/09 Javascript
python实现人人网登录示例分享
2014/01/19 Python
python基础教程之popen函数操作其它程序的输入和输出示例
2014/02/10 Python
Python入门篇之字典
2014/10/17 Python
bat和python批量重命名文件的实现代码
2016/05/19 Python
Python处理Excel文件实例代码
2017/06/20 Python
Python引用传值概念与用法实例小结
2017/10/07 Python
使用python编写监听端
2018/04/12 Python
python实现简单的文字识别
2018/11/27 Python
Python unittest 简单实现参数化的方法
2018/11/30 Python
Python XML转Json之XML2Dict的使用方法
2019/01/15 Python
python 标准差计算的实现(std)
2019/07/29 Python
基于Python 中函数的 收集参数 机制
2019/12/21 Python
Python环境下安装PyGame和PyOpenGL的方法
2020/03/25 Python
Selenium自动化测试工具使用方法汇总
2020/06/12 Python
音频处理 windows10下python三方库librosa安装教程
2020/06/20 Python
详细分析Python垃圾回收机制
2020/07/01 Python
五分钟学会怎么用Pygame做一个简单的贪吃蛇
2021/01/06 Python
市场营销职业生涯规划书范文
2014/01/12 职场文书
特色蛋糕店创业计划书
2014/01/28 职场文书
手把手教你导入Go语言第三方库
2021/08/04 Golang
Python采集股票数据并制作可视化柱状图
2022/04/04 Python