如何实现英雄联盟全皮肤?
话接上回,虽然我们能获得全皮肤,但是呢,速度确实是有点慢,但是没关系,这次小编就带着大家给爬虫提提速!!!
首先:
我们要明白怎么给爬虫加速?这就要提到多进程和多线程了!!
多进程:
# 1. 多进程
"""
一个应用程序默认有一个进程(主进程),一个进程中默认有一个线程(主线程)。
一个应用程序可以有多个进程,每个进程中也可以有多个线程。
同一个进程中的多个线程之间数据可以直接共享;不同进程中的数据无法直接共享
"""
# 2.多进程的使用
"""
一个程序默认只有一个进程,如果需要多个进程,需要程序员手动创建进程对象:
进程对象 = Process(target=函数, args=元组)
进程对象.start()
进程对象.join()
"""
多线程:
# 1.线程
"""
线程是进程执行任务的基本单元。
进程中的任务都是在线程中执行的(如果一个进程中没有线程,那么这个进程对应的程序什么事都做不了)
进程 - 车间(工厂),提供厂房以及厂房中保存资源
线程 - 车间工人
默认情况下,一个进程中有一个线程。
""
# 2.多线程 --一个进程中有多个线程
"""
单线程特点:一个线程执行多个任务,只能串行(一个一个按顺序)执行
多线程特点:多个线程执行多个任务,可以并行(同时进行)执行
"""
# 3.多线程的本质
"""
一个cpu同一时间只能处理一个线程,同一时间只有一个线程可以工作。
多线程原理:多线程技术其实就是利用cpu空闲时间做其他事情。
"""
线程池:
# 举例:
def download(name):
print(f'======{name}开始下载:{datetime.now()}========')
print(current_thread())
time.sleep(randint(2, 7))
print(f'======={name}下载结束:{datetime.now()}=================')
# 1)创建线程池对象
pool = ThreadPoolExecutor(5)
# 2)添加任务
# a.一次添加一个任务: 线程池对象.submit(函数,实参1,实参2,...)
pool.submit(download, '肖申克的救赎')
for x in range(10):
pool.submit(download, f'电影{x}')
# b.一次添加多个任务: 线程池对象.map(函数, [数据1, 数据2, 数据3,...])
# 注意:这个地方任务对应的函数必须是有且只有一个参数的函数
pool.map(download, ['霸王别姬', '阿甘正传', '触不可及'])
# 注意:只要线程池没有关闭,我们可以在任何你需要位置添加任务。
# 3)关闭线程池(同时具备关闭线程池和等待线程池任务都完成的功能)
pool.shutdown()
# pool.submit(download, '电影10') # 报错!
print('---------------------全部任务都完成!--------------------------')
那么,然后
运用线程池的方法,修改一下上次的代码,就能快速获取lol全皮肤了
import requests
import os
from queue import Queue
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
def down_load(hero_name, skin_name, skin_url):
resp = requests.get(skin_url)
file_type = os.path.splitext(skin_url)[-1]
with open(f'./lol极速版/{hero_name}/{skin_name}{file_type}', 'wb') as f:
f.write(resp.content)
# print(f'下载{skin_name}完成')
# 1.获取所有英雄的id
def get_all_hero_id_list():
Url = 'https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js?ts=2759918'
resp = requests.get(url=Url)
result = resp.json()
all_hero_id = [x['heroId'] for x in result['hero']]
# print(all_hero_id)
return all_hero_id
# 使用线程池获取英雄皮肤所在链接:
def get_all_hero_messqge(hero_id):
one_page = []
resp = requests.get(f'https://game.gtimg.cn/images/lol/act/img/js/hero/{hero_id}.js')
result = resp.json()
# 获取英雄名称
hero_name = result['hero']['name']
# 创建英雄名对应的文件夹
path = './lol极速版/'
if not os.path.exists(path + str(hero_name)):
os.makedirs(path + str(hero_name))
# 解析所有皮肤数据
for skin in result['skins']:
one_url = []
skin_name = skin['name'].replace('/', '-')
skin_url = skin['mainImg']
if not skin_url:
skin_url = skin['chromaImg']
one_url.append([hero_name, skin_name, skin_url])
url_q.put(one_url) # 一个的数据
one_page.append(one_url)
page_q.put(one_page) # 一页的数据
if __name__ == '__main__':
print(f'======开始下载:{datetime.now()}========')
all_page = []
# 2.使用线程池去获取所有英雄的详情json文件:
# a.创建线程池
# 获取下载链接的线程池
# 创建id的队列:
# .创建队列去获取英雄池中所产生的链接信息:
url_q = Queue()
page_q = Queue()
url_pool = ThreadPoolExecutor(100)
# 下载皮肤的线程池
down_pool = ThreadPoolExecutor(100)
hero_id = get_all_hero_id_list()
# b.线程池中添加,寻找皮肤链接的任务,创建文件夹的任务,
for id1 in hero_id:
url_pool.submit(get_all_hero_messqge, id1)
# 4.从队列中取出链接信息,然后在添加到下载的任务池中
for x in range(len(hero_id)): # 通过英雄个数控制外层循环
for y in page_q.get(): # 通过每一个英雄有多少个皮肤控制内层循环
name = url_q.get()[0]
down_pool.submit(down_load, name[0], name[1], name[2])
# 3)关闭线程池(同时具备关闭线程池和等待线程池任务都完成的功能)
down_pool.shutdown()
print(f'======下载结束:{datetime.now()}========')
```# 最后希望大家能给小编一点动力,比方说点点赞0.0