Python 多进程、协程异步抓取英雄联盟皮肤并保存在本地

news/2024/11/29 6:25:23/

00f6b5d4e1ba625a925ff32e20855687.gif

作者 | 俊欣

来源 | 关于数据分析与可视化

就在11月7日晚间,《英雄联盟》S11赛季全球总决赛决斗,在冰岛拉开“帷幕”,同时面向全球直播。在经过了5个小时的鏖战,EDG战队最终以3:2战胜来自韩国LCK赛区的DK战队,获得俱乐部队史上首座全球总决赛冠军。

cd59834884963309de7cc35471d0d6bd.png

夺冠的消息瞬间引爆全网,包括小编的朋友圈也被刷屏了,今天小编就写一篇与之相关的文章,通过单线程多进程以及异步协程等方法来抓取英雄联盟的皮肤并下载。

传统数据抓取 VS 高性能数据抓取

传统的数据抓取都是运行在单线程上的,先用获取到目标页面中最大的页数,然后循环抓取每个单页数据并进行解析,按照这样的思路,会有大量的时间都浪费在等待请求传回的数据上面,如果在等待第一个页面返回的数据时去请求第二个页面,就能有效地提高效率,下面我们就通过单线程多进程以及异步协程的方式分别来简单的实践一下。

页面分析

目标网站:https://lol.qq.com/data/info-heros.shtml

c462e08553509f520a5dd7fc8befb56a.png

官网的界面如图所示,上面的每一张小图代表每一个英雄,我们知道每一个英雄有多个皮肤,我们的目标就是爬取每一个英雄的所有皮肤,并且保存在本地

打开一个英雄显示他所有的皮肤,如下图所示,

41b748fb3face29f5f371da5ec035c49.png

我们打开浏览器里面的开发者工具,查看皮肤数据的接口,

1bee4abb6853bb89398acc087327ef4f.png

可以看到皮肤的信息是通过json的数据格式来进行传输的,并且存放皮肤的url也是有一定规律的,和英雄的ID相挂钩

url1 = 'https://game.gtimg.cn/images/lol/act/img/js/hero/1.js' 
url2 = 'https://game.gtimg.cn/images/lol/act/img/js/hero/2.js' 
url3 = 'https://game.gtimg.cn/images/lol/act/img/js/hero/3.js'
url4 = 'https://game.gtimg.cn/images/lol/act/img/js/hero/4.js'

因此我们也可以自己来构造这个url格式

'https://game.gtimg.cn/images/lol/act/img/js/hero/{}.js'.format(i)

单线程方案

我们先来看一下单线程的方案

def get_page():page_urls = []for i in range(1, 10):url = 'https://game.gtimg.cn/images/lol/act/img/js/hero/{}.js'.format(i)page_urls.append(url)return page_urls# 获取各英雄皮肤的链接
def get_img_urls():results_list = []page_urls = get_page()for page_url in page_urls:res = requests.get(page_url, headers=headers)result = res.content.decode('utf-8')result_dict = json.loads(result)skins_list = result_dict["skins"]for skin in skins_list:hero_dict = {}hero_dict['name'] = skin["heroName"]hero_dict['skin_name'] = skin["name"]if skin["mainImg"] == '':continuehero_dict['imgUrl'] = skin["mainImg"]results_list.append(hero_dict)time.sleep(2)return results_list# 将各种皮肤保存到本地
def save_image(index, img_url):path = "skin/" + img_url["name"]if not os.path.exists(path):os.makedirs(path)response = requests.get(img_url['imgUrl'], headers = headers).contentwith open('./skin/' + img_url['name'] + '/' + img_url['skin_name'] + str(index) + '.jpg', 'wb') as f:f.write(response)

上面的代码分别代表的获取各英雄每个皮肤的链接,然后再将各英雄的皮肤图片保存到本地,通过一个主函数将上面的步骤都串联到一起

def main():img_urls = get_img_urls()print("总共有{}个网页".format(len(img_urls)))for index, img_url in enumerate(img_urls):print("目前正处于第{}个".format(img_urls.index(img_url)))save_image(index, img_url)print("Done")

爬取这几个网页然后保存到本地的时间总共是需要43秒的时间,接下来我们来看一下多进程的爬取所需要的时间。

多进程的抓取方案

首先来简单的介绍一下进程,进程是系统进行资源分配和调度的最小单位,每一个进程都有自己独立的地址空间,不同进程之间的内存空间不共享,进程与进程之间的通信是由操作系统来传递的,因此通讯效率低,切换开销大。

这里我们简单的用多进程来抓取一下各个英雄的皮肤

def main():img_urls = get_img_urls()print("总共有{}个网页".format(len(img_urls)))pools = multiprocessing.Pool(len(img_urls))for index_1, img_url in enumerate(img_urls):print("目前正处于第{}个".format(img_urls.index(img_url)))pools.apply_async(save_image, args=(index_1, img_url, ))pools.close() # 关闭进程池(pool),使其不在接受新的任务。pools.join() # 主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用print("Done")

整体下来需要的时间是29秒,比上面的单线程要快出许多。

异步协程的抓取方案

与异步相对立的则是同步,顾名思义,同步具体指的各个任务并不是独立进行的,而是按照顺序交替进行下去的,在一个任务进行完之后得到结果才进行下一个的任务。

而异步则是各个任务可以独立的运行,一个任务的运行不受另外一个任务的影响。而这里提到的协程,英文叫做Coroutine,也称为是微线程,是一种用户态的轻量级线程,拥有自己的寄存器上下文和栈,在进行调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候恢复先前保存的寄存器上下文和栈。

4cd1911494f5446e6032900fd116fec2.png

我们可以利用协程来实现异步操作,比如在发出请求的时候,需要等一段时间才能得到返回的结果,但其实这个等待的时候程序完全可以干其他许多的事情,在响应返回之后再切换回来继续处理,这样可以充分利用 CPU 和其他资源。

我们这里用协程来抓取一下各个英雄的皮肤

async def save_image(index, img_url):path = "skin/" + img_url["name"]if not os.path.exists(path):os.makedirs(path)response = requests.get(img_url['imgUrl'], headers = headers).contentwith open('./skin/' + img_url['name'] + '/' + img_url['skin_name'] + str(index) + '.jpg', 'wb') as f:f.write(response)def main():loop = asyncio.get_event_loop()img_urls = get_img_urls()print("总共有{}个网页".format(len(img_urls)))tasks_list = [save_image(index, img_url) for index, img_url in enumerate(img_urls)]try:loop.run_until_complete(asyncio.wait(tasks_list))finally:loop.close()print("Done")

一整个跑下来,大概是需要33秒的时间,也是比单线程的43秒要快出很多

以上便是用单线程、多进程以及异步协程的方式来优化爬虫脚本的性能,感兴趣的读者可以自己照着上面的教程与步骤自己去敲一遍代码,感谢阅读。

a7328bb03f7ead5ae8ce808e306bde2a.png

资讯

GPT-3与小学生的做题之战……

技术

如何利用python爬取高清精美壁纸

技术

Pandas生成炫酷的动态交互时图表

福利

赠书|深度学习视频理解之图像分类

94bda5d554464f87751463594c2eaa80.png

分享

9c825ce481791ef63a91e5da368d6740.png

点收藏

526c966b8d6b705cc8f43bc39b10f8e1.png

点点赞

4f8075f538e40671377b2d6664e7a1ad.png

点在看


http://www.ppmy.cn/news/444566.html

相关文章

python爬虫脚本 初级入门爬虫英雄联盟所有皮肤_Python爬虫实战,60行代码爬取英雄联盟全英雄全皮肤,找寻曾今那些被删除的绝版皮肤...

学了一周多的爬虫课后终于按捺不住了,小编决定自己手动编写爬虫程序,刚好LJ在鼓励学员分享成果,优秀作品有奖励,就把自己用Python编程爬取各大游戏高清壁纸的过程整理了出来进行投稿,与大家一起分享。 爬取了当前比较…

android抖抖壁纸,抖抖动态壁纸安卓版 v1.2.3下载 - 艾薇下载站

抖抖动态壁纸APP为用户提供了许多的游戏动态壁纸、动漫人物动态壁纸,帮助用户将网上热门的短视频作为动态壁纸,这样就可以让您的手机桌面变得更加生动;这里提供的游戏动态壁纸非常的多,包含了英雄联盟、绝地求生、王者荣耀、守望先…

深度学习:探索人工智能的新前沿

第一章:引言 人工智能(Artificial Intelligence,AI)作为一项前沿技术,在近年来取得了巨大的进展。其中,深度学习(Deep Learning)作为人工智能领域的一个重要分支,更是引…

【Vue3+Ts project】vant4 实现触发指定表单 rules校验、setTimeout和 setInterval 区别

一.使用vant组件 validate属性 实现触发指定输入框rules校验&#xff0c;满足校验通过否则失败 1.给form表单绑定 ref并定义值名称 &#xff0c;然后为你想校验的表单绑定 name值 <van-form ref"form"><van-field name"mobilenNmber" v-model&…

爬虫 | 王者荣耀高清壁纸-多线程

# CY3761 | 2021-11-04 18:23 import json import os import queue import time import urllibimport requestsfrom urllib import parse import threading from queue import Queue# 王者荣耀-官网 https://pvp.qq.com # 王者荣耀-高清壁纸 https://pvp.qq.com/web201605/wall…

华为鸿蒙系统能继承王者荣耀吗,华为鸿蒙玩王者荣耀账号互通吗?华为鸿蒙玩王者荣耀会不会影响?...

大家朝思暮想的华为鸿蒙系统终于发布了&#xff0c;很多用户都升级了&#xff0c;但是有些网友难免会担心华为鸿蒙系统玩王者荣耀会有所影响&#xff0c;最直接的影响便是账号不互通了&#xff0c;毕竟鸿蒙和安卓是两个系统。那么华为鸿蒙玩王者荣耀会不会影响呢&#xff1f;以…

Baumer工业相机堡盟工业相机如何通过BGAPISDK使用AutoFocusHelper自动对焦补充功能(C++)

Baumer工业相机堡盟工业相机如何通过BGAPISDK使用AutoFocusHelper自动对焦补充功能&#xff08;C&#xff09; Baumer工业相机Baumer工业相机BGAPISDK和AutoFocus功能的技术背景Baumer工业相机通过BGAPISDK使用AutoFocus功能1.引用合适的类文件2.通过BGAPISDK声明AutoFocusHelp…

多线程下载王者荣耀高清壁纸(过程超详细)

文章分为单线程和多线程两个部分&#xff0c;选择单线程一个一个下载速度会很慢&#xff0c;多线程下载可以明显提升速度。但先用单线程写出代码&#xff0c;再在此基础上改动成多线程&#xff0c;思路会更加清晰&#xff0c;对初学者也更加友好&#xff01; 单线程下载王者荣…