一个函数下载,一个函数创建文件夹并保存,但是一张张图片下载太慢了。
尝试通过Queue put get执行两个函数,但是put那里会卡住不执行get部分的下载函数。
# 一张张下载
def get_geturl():
for row_i in range(row_num):
for line_i in range(line_num):
pic_url = get(origin_pic_url, headers=req_header)
if pic_url.status_code == 200:
pic_url = get(origin_pic_url, headers=req_header).json()['result']
pic_name = pic_url
save_pic(pic_url, pic_name, id, device_name)
elif pic_url.status_code == 400:
print('token过期,重新操作')
get_token()
pic_url = get(origin_pic_url, headers=req_header).json()['result']
save_pic(pic_url, pic_name, id, device_name)
else:
print('获取下载链失败')
def save_pic(pic_url, pic_name, id, device_name):
#判断目录是否存在,不存在建立
down_pic = f"{down_path}/{id}/{device_name}/{pic_name}"
res = get(pic_url)
with open(f'{down_pic}.jpg', 'wb') as f:
f.write(res.content)
f.close()
# 尝试多进程下载但是失败的
def get_geturl(q):
for row_i in range(row_num):
for line_i in range(line_num):
pic_url = get(origin_pic_url, headers=req_header)
if pic_url.status_code == 200:
pic_url = get(origin_pic_url, headers=req_header).json()['result']
pic_name = pic_url
q.put(pic_url)
q.put(pic_name)
q.put(id)
q.put(device_name)
elif pic_url.status_code == 400:
print('token过期,重新操作')
get_token()
pic_url = get(origin_pic_url, headers=req_header).json()['result']
q.put(pic_url)
q.put(pic_name)
q.put(id)
q.put(device_name)
else:
print('获取下载链失败')
def save_pic(q):
while not q.empty():
pic_url = q.get()
pic_name = q.get()
id = q.get()
device_name = q.get()
#判断目录是否存在,不存在建立
down_pic = f"{down_path}/{id}/{device_name}/{pic_name}"
res = get(pic_url)
with open(f'{down_pic}.jpg', 'wb') as f:
f.write(res.content)
f.close()
if __name__ == "__main__":
q = Queue(6)
p1 = Process(target=get_geturl, args=(q,))
p2 = Process(target=save_pic, args=(q,))
p3 = Process(target=save_pic, args=(q,))
p4 = Process(target=save_pic, args=(q,))
p5 = Process(target=save_pic, args=(q,))
p6 = Process(target=save_pic, args=(q,))
p1.start()
p2.start()
p3.start()
p4.start()
p5.start()
p6.start()
p1.join()
p2.join()
p3.join()
p4.join()
p5.join()
p6.join()
望采纳!!点击回答右侧采纳即可采纳!!!我帮你看看代码
python多线程下载图片,请采纳哦!!1!!1:
import urllib.parse as parse
from urllib import request
import random
from queue import Queue
import threading
import time
import json
import os
def get_time(): # 时间戳处理
str_time = str(time.time())
str_time = str_time[:str_time.find('.')] + str_time[str_time.find('.') + 1:str_time.find('.') + 4]
time.sleep(1.25) # 没得到一个时间戳,休眠1.25秒
return str_time
def get_url():
keyword = input('请输入你想下载的图片类型:')
key_word = parse.urlencode({'q': keyword})
num=int(input('请输入你想下载的图片数量:'))//100
headers = {
"Referer": "https://www.quanjing.com/search.aspx?%s" % (key_word),
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400"}
url='https://www.quanjing.com/Handler/SearchUrl.ashx?t=%s&callback=searchresult&%s&stype=1&pagesize=100&pagenum=%s&imageType=2&imageColor=&brand=&imageSType=&fr=1&sortFlag=1&imageUType=&btype=&authid=&_=%s'
list_url=[]
for i in range(1,num+1):
str_1 = str(random.random())
random_1 = str_1[str_1.find('.') + 1:str_1.find('.') + 5]
time_1=get_time()
url_1=url%(random_1,key_word,i,time_1)
list_url.append(url_1)
return list_url,headers,keyword
tuple_1=get_url()
list_url,headers,keyword=tuple_1[0],tuple_1[1],tuple_1[2]
queue_url = Queue(len(list_url)*100+5)
queue_img = Queue(len(list_url)*100+5)
try: # 防止因为没有该图片类型而报错
num=1
for i in range(len(list_url)):
request_1=request.Request(url=list_url[i],headers=headers)
content=request.urlopen(request_1)
str_1 = content.read().decode('utf-8') # 得到的数据字符串类型
str_1 = str_1[str_1.find('(') + 1:str_1.rfind(')')]
dict_1 = json.loads(str_1)
images_list = dict_1['imglist']
for j in range(len(images_list)):
print('【{}】-{}'.format(num, images_list[j]['caption']))
queue_url.put(images_list[j]['imgurl'])
queue_img.put(images_list[j]['caption'])
num+=1
def Downlad(queue_url: Queue, queue_img: Queue):
path_1 = './' + keyword
try:
os.mkdir(path_1)
except:
pass
finally:
while True:
if queue_url.empty():
break
image_name = queue_img.get()
request.urlretrieve(url=queue_url.get(), filename=path_1 + '/【{}】-{}.png'.format(random.random()*1000,image_name)) # 下载图片
# 为了防止出现图片名相同的情况,对于图片命名添加一个随机数
print('线程{}正在下载【{}】'.format(threading.current_thread().getName(), image_name))
time.sleep(0.25) # 每下载一张图片,休眠0.25秒
threading_list = []
print('开始下载!')
time.sleep(5)
for i in range(len(list_url)*5): # 根据用户的输入创建相应多的线程
threading_1 = threading.Thread(target=Downlad, args=(queue_url, queue_img,))
threading_1.start()
threading_list.append(threading_1)
for i in threading_list:
i.join()
print('------------------------下载完毕!当前线程为', threading.current_thread().getName())
except Exception as e:
print(e,'没有搜到该图片或者今日访问次数过多!')
你应该使用多线程下载才符合你的要求。
在 Python 中,你可以使用多线程来下载图片,来加快图片的下载速度。
首先,你需要安装 Python 的多线程库 threading。你可以使用 pip 命令来安装:
pip install threading
然后,你可以使用 Python 的 requests 库来下载图片。requests 库是一个简单易用的 HTTP 库,可以帮助你发送 HTTP 请求并获取响应。你可以使用 pip 命令来安装:
pip install requests
接下来,你可以使用以下代码来实现多线程下载图片:
import threading
import requests
def download_image(image_url, image_name):
response = requests.get(image_url)
with open(image_name, 'wb') as f:
f.write(response.content)
# 创建多个线程
threads = []
for i in range(10):
image_url = "http://example.com/image" + str(i) + ".jpg"
image_name = "image" + str(i) + ".jpg"
t = threading.Thread(target=download_image, args=(image_url, image_name))
threads.append(t)
# 启动多个线程
for t in threads:
t.start()
# 等待所有线程完成
for t in threads:
t.join
望采纳
1、可以使用 Queue.Queue() 来替换 Queue() ,因为 Queue() 已经不被推荐使用了。
2、在使用多进程下载时,为了更好地利用 CPU,可以考虑使用进程池(process pool)。进程池可以让预先启动若干个进程,然后将任务分发给这些进程。这样可以减少进程创建的时间开销。
from multiprocessing import Pool
def download_image(pic_url, pic_name, id, device_name):
# 判断目录是否存在,不存在建立
down_pic = f"{down_path}/{id}/{device_name}/{pic_name}"
res = get(pic_url)
with open(f'{down_pic}.jpg', 'wb') as f:
f.write(res.content)
f.close()
if __name__ == "__main__":
with Pool(4) as p:
for row_i in range(row_num):
for line_i in range(line_num):
pic_url = get(origin_pic_url, headers=req_header)
if pic_url.status_code == 200:
pic_url = get(origin_pic_url, headers=req_header).json()['result']
pic_name = pic_url
p.apply_async(download_image, (pic_url, pic_name, id, device_name))
elif pic_url.status_code == 400:
print('token过期,重新操作')
get_token()
pic_url = get(origin_pic_url, headers=req_header).json()['result']
p.apply_async(download_image, (pic_url, pic_name, id, device_name))
else:
print('获取下载链失败')
p.close()
p.join()
仅供参考,望采纳,谢谢。
参考下该实例【利用Python多线程实现图片下载器】,链接:https://www.jb51.net/article/242296.htm
要将图片链接使用多进程下载可以使用 Python 的 multiprocessing 模块。这个模块提供了多种方法来创建和管理子进程,可以方便地实现多进程编程。
下面是一个简单的例子,展示了如何使用 multiprocessing 模块将图片链接下载到本地:
import multiprocessing
import requests
def download_image(url, filename):
response = requests.get(url)
if response.status_code == 200:
with open(filename, 'wb') as f:
f.write(response.content)
if __name__ == '__main__':
# 定义要下载的图片链接列表
urls = [
'https://example.com/image1.jpg',
'https://example.com/image2.jpg',
'https://example.com/image3.jpg',
'https://example.com/image4.jpg',
'https://example.com/image5.jpg',
]
# 创建进程池,并使用 map 方法将下载任务提交到进程池中执行
with multiprocessing.Pool() as pool:
pool.starmap(download_image, [(url, f'image_{i}.jpg') for i, url in enumerate(urls)])
使用 multiprocessing.Pool 类创建了一个进程池,并使用 map 方法将下载任务提交到进程池中执行。每个进程将调用 download_image 函数来下载一个图片链接。
在使用多进程下载图片时,还可以使用 multiprocessing.Queue 类来创建一个任务队列,并使用多个进程从队列中取出任务来执行。这样可以使程序更加灵活,可以动态地添加和移除任务。
import multiprocessing
import requests
def download_image(url, filename, queue):
response = requests.get(url)
if response.status_code == 200:
with open(filename, 'wb') as f:
f.write(response.content)
queue.put((url, filename))
if __name__ == '__main__':
# 创建任务队
题主应该是没有注意到Queue调用的安全
首先当get_url调用后立即进入save_pic若get_url种还未来得及put那么save_pic显然是不能运行的直接跳出了
而假设get_url中神速put了,save_pic没有跳出,那么第二个问题又来了,六个save_pic同时抢资源那么前后4个数据就会被六马分尸当然无法正常下载了
解决方法也很简单,添加进程锁,修改好的代码稍后,望采纳
一、页面抓取
#coding=utf-8
import urllib
def getHtml(url):
page = urllib.urlopen(url)
html = page.read()
return html
html = getHtml("https://tieba.baidu.com/p/5582243679")
print html
页面数据抓取过程定义了getHtml()函数,其作用是给getHtml()传递一个网址,最终进行整个页面的下载。
二、页面数据筛选
import re
import urllib
def getHtml(url):
page = urllib.urlopen(url)
html = page.read()
return html
def getImg(html):
reg = r'src="(.+?\.jpg)" pic_ext'
imgre = re.compile(reg)
imglist = re.findall(imgre,html)
return imglist
html = getHtml("https://tieba.baidu.com/p/5582243679")
print getImg(html)
页面数据筛选中,定义了一个新的函数getImg(),该函数的功能是筛选出.jpg格式的图片地址。
三、图片下载
#coding=utf-8
import urllib
import re
def getHtml(url):
page = urllib.urlopen(url)
html = page.read()
return html
def getImg(html):
reg = r'src="(.+?\.jpg)" pic_ext'
imgre = re.compile(reg)
imglist = re.findall(imgre,html)
x = 0
for imgurl in imglist:
urllib.urlretrieve(imgurl,'%s.jpg' % x)
x+=1
html = getHtml("https://tieba.baidu.com/p/5582243679")
print getImg(html)
你可以使用 Python 的多进程库 concurrent.futures 来实现图片的多进程下载。这个库提供了一个简单的 ProcessPoolExecutor 类,可以使用它来提交多个图片下载任务。
这里是一个示例代码,你可以用它来参考:
import concurrent.futures
import requests
def download_image(url, path):
response = requests.get(url)
with open(path, 'wb') as f:
f.write(response.content)
def main():
urls = [
'https://www.example.com/image1.jpg',
'https://www.example.com/image2.jpg',
'https://www.example.com/image3.jpg',
# ...
]
with concurrent.futures.ProcessPoolExecutor() as executor:
for url, future in zip(urls, executor.map(download_image, urls)):
print(f'{url} was downloaded')
if __name__ == '__main__':
main()
这里,我们首先定义了一个 download_image(url, path) 函数,它可以用来下载指定的图片并将其保存到磁盘上。在主程序中,我们创建了一个 ProcessPoolExecutor 对象并使用它来提交多个下载任务。每个下载任务都由 download_image() 函数执行,并且参数是一个要下载的图片的 URL。
这个程序会在多个进程中并行下载图片,因此它可能比单进程下载图片快得多。
对于下载图片并保存到文件夹的部分,可以考虑在 download_image() 函数中,通过 os.path 模块获取文件夹路径,比如你要下载的图片在 '/images/' 下,然后利用 os.path.exists 和 os.makedirs 来判断文件夹是否存在,如果不存在就新建文件夹并下载图片。
import os
def download_image(url, filename):
folder = '/images/'
if not os.path.exists(folder):
os.makedirs(folder)
path = os.path.join(folder, filename)
response = requests.get(url)
with open(path, 'wb') as f:
f.write(response.content)
同时因为下载图片是IO密集型,因此可以考虑使用 Python asyncio 或 gevent 进行异步下载,这样也能提升下载的速度。如果使用 asyncio 库,可以使用 asyncio.gather 来并发下载多张图片。可以将多个 download_image() 任务放入一个列表中,然后使用 asyncio.gather 并发执行这些任务。
import asyncio
async def download_image(url, filename):
folder = '/images/'
if not os.path.exists(folder):
os.makedirs(folder)
path = os.path.join(folder, filename)
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
with open(path, 'wb') as f:
while True:
chunk = await resp.content.read(1024)
if not chunk:
break
f.write(chunk)
async def main():
urls = [
'https://www.example.com/image1.jpg',
'https://www.example.com/image2.jpg',
'https://www.example.com/image3.jpg',
# ...
]
tasks = []
for url in urls:
task = download_image(url, f'{url.split("/")[-1]}')
tasks.append(task)
await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
或者使用gevent 库
import gevent
from gevent import monkey
monkey.patch_all()
def download_image(url, filename):
folder = '/images/'
if not os.path.exists(folder):
os.makedirs(folder)
path = os.path.join(folder, filename)
response = requests.get(url)
with open(path, 'wb') as f:
f.write(response.content)
def main():
urls = [
'https://www.example.com/image1.jpg',
'https://www.example.com/image2.jpg',
'https://www.example.com/image3.jpg',
# ...
]
tasks = [gevent.spawn(download_image, url, f'{url.split("/")[-1]}') for url in urls]
gevent.joinall(tasks)
if __name__ == '__main__':
main()
使用上述两种库中的一种来实现异步下载,应该可以大大提升下载图片的速度。
需要注意的是,使用 asyncio 与 gevent 来实现异步编程,还需要满足如下条件:
你需要在运行程序之前安装 aiohttp (如果是asyncio) 以及 gevent
你需要在程序中导入对应的库
你需要在 main 或 main() 函数运行asyncio.run(main())或 gevent.joinall(tasks)
如果你不确定哪种方式更适合你的项目,可以尝试多种方法并对比它们的性能。如果你遇到任何问题,请随时给我留言。望采纳。
提供一个多进程的demo,可以参考一下:
from multiprocessing import Process
from threading import Thread
def func():
for i in range(1000):
print("子进程", i)
if __name__ == '__main__':
p = Process(target=func)
p.start()
for i in range(10000):
print("主进程", i)
也可以用进程池,因为看到你代码中有多达6个进程:
# 线程池: 一次性开辟一些线程. 我们用户直接给线程池子提交任务. 线程任务的调度交给线程池来完成
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def fn(name):
for i in range(1000):
print(name, i)
if __name__ == '__main__':
# 创建进程池
with ProcessPoolExecutor(50) as t:
for i in range(100):
t.submit(fn, name=f"进程{i}")
# 等待进程池中的任务全部执行完毕. 才继续执行
print("123")
如果有补充,可以留言继续讨论。
不知道你解决了没?
如果没有解决的话,我们可以聊聊。
前面的回答,估计你有点懵,没有回答到你的问题核心点上。