利用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基础教程之lambda表达式使用方法
Feb 12 Python
Python 时间操作例子和时间格式化参数小结
Apr 24 Python
在Linux命令行终端中使用python的简单方法(推荐)
Jan 23 Python
Python实现购物车功能的方法分析
Nov 10 Python
Python+matplotlib+numpy实现在不同平面的二维条形图
Jan 02 Python
Django 限制用户访问频率的中间件的实现
Aug 23 Python
python+webdriver自动化环境搭建步骤详解
Jun 03 Python
Python 实现一个手机号码获取妹子名字的功能
Sep 25 Python
python的mysql数据库建立表与插入数据操作示例
Sep 30 Python
numpy 矩阵形状调整:拉伸、变成一位数组的实例
Jun 18 Python
python实现简单猜单词游戏
Dec 24 Python
python软件测试Jmeter性能测试JDBC Request(结合数据库)的使用详解
Jan 26 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
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
2009/03/13 PHP
php去除HTML标签实例
2013/11/06 PHP
thinkphp文件处理类Dir.class.php的用法分析
2014/12/08 PHP
程序员的表白神器“520”大声喊出来
2016/05/20 PHP
PHP微信开发之文本自动回复
2016/06/23 PHP
CI框架(ajax分页,全选,反选,不选,批量删除)完整代码详解
2016/11/01 PHP
php递归函数怎么用才有效
2018/02/24 PHP
Document 对象的常用方法
2009/07/31 Javascript
JavaScript 开发规范要求(图文并茂)
2010/06/11 Javascript
用box固定长宽实现图片自动轮播js代码
2014/06/09 Javascript
简述AngularJS的控制器的使用
2015/06/16 Javascript
JQuery 设置checkbox值二次无效的解决方法
2016/07/22 Javascript
兼容浏览器的js事件绑定函数(详解)
2017/05/09 Javascript
JS实现简易的图片拖拽排序实例代码
2017/06/09 Javascript
使用javascript做在线算法编程
2018/05/25 Javascript
小程序实现多个选项卡切换
2020/06/19 Javascript
js实现3D旋转效果
2020/08/18 Javascript
[48:00]EG vs LGD 2018国际邀请赛淘汰赛BO3 第二场 8.26
2018/08/29 DOTA
git进行版本控制心得详谈
2017/12/10 Python
利用python如何处理百万条数据(适用java新手)
2018/06/06 Python
用Python和WordCloud绘制词云的实现方法(内附让字体清晰的秘笈)
2019/01/08 Python
Python 中Django验证码功能的实现代码
2019/06/20 Python
Python OpenCV 使用滑动条来调整函数参数的方法
2019/07/08 Python
Python assert关键字原理及实例解析
2019/12/13 Python
Pytorch maxpool的ceil_mode用法
2020/02/18 Python
Python虚拟环境virtualenv创建及使用过程图解
2020/12/08 Python
基于tensorflow __init__、build 和call的使用小结
2021/02/26 Python
英国工艺品购物网站:Minerva Crafts
2018/01/29 全球购物
澳大利亚最好的电动自行车:Leon Cycle
2020/12/19 全球购物
泰国第一在线超市:Tops
2021/02/13 全球购物
《盲人摸象》教学反思
2014/02/16 职场文书
贯彻落实“八项规定”思想汇报
2014/09/13 职场文书
工作汇报开头与结尾怎么写
2014/11/08 职场文书
督导岗位职责范本
2015/04/10 职场文书
2015年销售部工作总结范文
2015/04/27 职场文书
幼儿园百日安全活动总结
2015/05/07 职场文书