利用Python多线程实现图片下载器
作者:Charles的皮卡丘 发布时间:2022-02-12 06:07:41
导语
之前有很多小伙伴说想学习一下多线程图片下载器,虽然好像已经过去很久了,不过还是上来安排一波吧。至于题目为什么说是构建一个小型数据集,因为公众号之后的文章应该还会用到它来构建一些简单的图像分类数据集,换句话说,后续一段时间,公众号会主要写一些深度学习机器学习相关的文章,下期文章揭晓具体内容。
废话不多说,让我们愉快地开始近期最后一篇爬虫文章~
开发工具
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
来源:https://mp.weixin.qq.com/s/pmLwqASYSf7bImfHkR9RqA


猜你喜欢
- 我就废话不多说了,还是直接看代码吧!import pandas as pd# 伪造一些数据fake_data = {'subject
- 我们在使用selenium库调用Chromedriver.exe时需要很多的配置参数下面列出了常用参数chrome_options.add_
- 前言由于项目需要生成多条数据,并保存到数据库当中,在程序中封装了一个List集合对象,然后需要把该集合中的实体插入到数据库中,项目使用了Sp
- 本文实例讲述了mysql show操作。分享给大家供大家参考,具体如下:SHOW CHARACTER SET显示所有可用的字符集SHOW C
- 1.按姓氏笔画排序:Select * From TableName Order By CustomerName Collate Chines
- 上周对线上某几个磁盘进行了fio硬盘性能测试,测试完成之后的结果需要绘制成图像展示出来。我在官网上查找
- 后台服务在运行时发现一个问题,运行约15分钟后,接口请求报错pymysql.err.InterfaceError: (0, '
- 概述从今天开始我们将开启一段自然语言处理 (NLP) 的旅程. 自然语言处理可以让来处理, 理解, 以及运用人类的语言, 实现机器语言和人类
- 前言之前公司设计的网站比较混乱,很多地方不统一,其中一个就是弹出层,导致这个原因是因为,公司的UI换了好几个人,而他们每个人做出来的都不太一
- 集合的特性无序、不重复、可迭代常用api创建一个集合需要显式地使用set()方法来声明,如果使用字面量{}来声明解析器会认为这是一个字典。a
- 今天跟大家分享下selenium中根据父子、兄弟、相邻节点定位的方法,很多人在实际应用中会遇到想定位的节点无法直接定位,需要通过附近节点来相
- 情境还原: 公司一项目新上线,刚上线的第2天,在后台发现数据库服务器与IIS服务器的网络IO出现瓶颈,1GB的网络带宽,占用了70%-100
- // 1.采用计算属性来获取$store中的值computed: { listenstage() {
- 关于书写习惯,遵循曾经总结过的风格标准,现在一点都没有变。并且近来翻看高手作品,横向连排似乎在大产品项目中逐渐成为主流,个人认为如此维护效率
- 背景今天突然想到之前被要求做同性质银行的数据分析。妈耶!十几个银行,每个银行近5年的财务数据,而且财务报表一般都是 pdf 的,我们将 pd
- 想必大家都很喜欢用Word打字,用Excel进行计算和规划,用PowerPoint作幻灯片进行展示…,但是这只用到了Office系列产品的很
- win10系统本地安装MySQL8.0.20,亲测可用,也是参考了其他大神的操作1. 下载Mysql ,官网下载地址:MySQL官网:链接直
- 编写tasks.pyfrom celery import Celeryfrom tornado.httpclient import HTTP
- python实现学员管理系统这个小程序是我刚刚接触python时,导师带着做的第一个小项目。通过这次练习,我学会了很多东西。下面是具体的代码
- 最近老婆大人的公司给老婆大人安排了一个根据关键词查询google网站排名的差事。老婆大人的公司是做seo的,查询的关键词及网站特别的多,看着