【Java项目】讲讲我用Java爬虫获取LOL英雄数据与图片(附源码)

news2025/7/13 20:38:18

🚀用Java爬一下英雄联盟数据

📓推荐网站(不断完善中):个人博客

📌个人主页:个人主页

👉相关专栏:CSDN专栏

🏝立志赚钱,干活想躺,瞎分享的摸鱼工程师一枚

🏖前言

本章内容为一个实战项目,主要的实战方向为使用Javad的WebMagic爬虫框架来爬取LOL的英雄资料和一些图片。

本章节需要学习的小伙伴们具备一些初步的JavaSE知识,以及最好能对Maven进行使用。

如果你还不知道Maven是什么,以及不知道如何创建一个Maven项目的话,请移步:Maven教程传送门

那么我们就开始吧!

文章目录

  • 🚀用Java爬一下英雄联盟数据
    • 🏖前言
    • 1.什么是爬虫?
      • 1.1爬虫亦有善恶
      • 1.2.爬虫的本质
      • 1.3.爬虫的基本流程
    • 2.WebMagic
      • 2.1.框架概述
      • 2.2.设计架构
    • 3.项目实战(初窥篇)
      • 3.1.准备工作
      • 3.2.工具介绍(hutool)
        • 🎁Hutool名称的由来
      • 3.3.初窥门径
      • 3.4.利用WebMagic处理请求
    • 4.项目实战(提升篇)
      • 4.1.请求分析
      • 4.2.代码部分
      • 4.3.项目源码
    • 🏜写在最后


1.什么是爬虫?

爬虫是指使用代码模拟用户批量发送网络请求,批量获取数据的行为。

通俗点来来讲,爬虫就是一个探测机器,它的基本操作就是模拟人的行为去各个网站溜达,点点按钮,查查数据,或者把看到的信息背回来。就像一只虫子在一幢楼里不知疲倦地爬来爬去。

我们见到的最常见的爬虫就是比如百度、谷歌..之类的搜索引擎

1.1爬虫亦有善恶

我们知道互联网也是一个江湖,在这个大江湖之中,爬虫也是区分善恶的(当然这只是一个概念)。

其实说白了呢就是看使用者如何去使用它。

  • 像谷歌这样的搜索引擎爬虫,每隔几天对全网的网页扫一遍,供大家查阅,各个被扫的网站大都很开心。这种就被定义为「善意爬虫」。
  • 但是,像抢票软件这样的爬虫,对着 12306 每秒钟恨不得撸几万次。铁总并不觉得很开心。这种就被定义为「恶意爬虫」。(注意,抢票的你觉得开心没用,被扫描的网站觉得不开心,它就是恶意的。)
    • 为什么说12306不开心呢,因为在20年前的一份数据表明12306最高峰时 1 天内页面浏览量达 813.4 亿次,1 小时最高点击量 59.3 亿次,平均每秒 164.8 万次。相信如果被这样捕捉的服务器是你的服务器,你也不会开心的。

1.2.爬虫的本质

实质上爬虫的本质就是模拟人为打开浏览器,然后去获取页面上的信息。

只不过这种人为的动作被我们的代码所代替。

1.3.爬虫的基本流程

对于初学者入门来说,其实爬虫的基本流程主要在四步

1.请求目标链接 -> 2.获取响应内容 -> 3.解析内容 -> 4.存储数据

  • 请求目标链接:发起一个带有header、请求参数等信息的Request,等待服务器响应
  • 获取服务器响应内容:服务器正常响应后,Response的内容即包含所有页面内容(可以是HTML、JSON字符串、二进制数据(图片、视频)等等)
  • 解析内容:将得到的内容进行解析,HTML解析、JSON解析、二进制流解析等等
  • 存储数据:存储形式多样,可以存为文本,也可以存储到数据库,或者存为特定格式的文件

2.WebMagic

一般来说爬虫只是一种技术,其实任何语言都是可以实现爬虫的,区分为简单与复杂。

我们所知道的市面上比较常见的爬虫就是Python或者Go比较多

但是实际上在Java中也是可以完成爬虫这一操作,并且有一个相对而言比较成熟的框架就是WebMagic

今天我们就用这个框架来实战一下如何爬取英雄联盟的英雄信息与图片。

logo

2.1.框架概述

WebMagic的设计参考了业界最优秀的爬虫Scrapy,而实现则应用了HttpClient、Jsoup等Java世界最成熟的工具,目标就是做一个Java语言Web爬虫的教科书般的实现

2.2.设计架构

WebMagic的结构分为DownloaderPageProcessorSchedulerPipeline四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。

image

可以依据架构图我们看到整个执行流程大概为

1.发起一个HTTP请求

2.将这个HTTP内容下载下来(Downloader)

3.将内容交给PageProcesser进行处理(框架的处理核心)

4.1.处理内容后,可以再次发起请求

4.2.处理的结果可以交给Pipeline来进行最后的收尾工作(比如存到数据库、或者保存为文件等等)

更详细的内容可以直接查看官方的文档说明,这里就不一一赘述了。🚪 官方传送门

3.项目实战(初窥篇)

3.1.准备工作

直接添加WebMagic相关的框架依赖。

直接复制进pom.xml文件中即可

<dependencies>
    <dependency>
      <groupId>us.codecraft</groupId>
      <artifactId>webmagic-core</artifactId>
      <version>0.7.3</version>
    </dependency>
    <dependency>
      <groupId>us.codecraft</groupId>
      <artifactId>webmagic-extension</artifactId>
      <version>0.7.3</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
      <scope>provided</scope>
    </dependency>
    <!-- hutool工具jar包-->
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.9</version>
    </dependency>
  </dependencies>

3.2.工具介绍(hutool)

这是一个包含各大常用工具方法的Java工具包。

里面具有丰富的工具资源,可以让你省下不少写一些通用方法的时间。

Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug

官方传送门:Hutool官方地址

可以在官方地址中查看对应的文档信息。

这次主要我们要用到Hutool工具中对文件、请求的处理的工具!

🎁Hutool名称的由来

Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,tool表示工具。Hutool谐音“糊涂”,一方面简洁易懂,一方面寓意“难得糊涂”。

3.3.初窥门径

我们进行爬虫的第一步就是先明确的我们的需求。

首先我们应当想办法找到LOL英雄资料的页面(URL),然后我们才开始解析我们的页面。

🚪 LOL官方英雄资料地址

学会解析页面

首先我们要鼠标右键查看网页源代码

image-20221114224920149

由此我们可以发现我们的页面数据不过是寥寥几十行,并没有我们所需要的英雄数据信息,说明当前网站的页面信息并不是静态的。而是动态的(这里需要大家对HTTP请求有一定的基础知识)

因为数据是动态的所以我们需要去查看当前页面的请求链接去分析和寻找(这里需要耐心一点)

打开官网地址我们需要按下F12然后选择Network

刷新一下来查看当前网页的数据源是怎么展示在页面上的请求链接,我们可以发现一个比较可疑的链接hero_list.js

从名字来看是英雄列表的意思,只要你点进去查看返回结果可以发现这个就是我们想要的信息。

image-20221114225457022

由此分析我们就得到了当前英雄信息的数据源,我们接下来要做的就是去处理这个数据。

我们得到了我们要请求的路径为:https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js?ts=2780729

3.4.利用WebMagic处理请求

得到我们的需要的数据源之后,我们就要学会利用我们的爬虫来往数据源里面进行爬取数据。

对于数据的处理我们是通过自定义PageProcessor来完成的,所以我们需要创建一个类来实现这个接口。

并且重写我们的process()核心函数,改为我们要做的事情。

简单梳理一下我们要做的事情

  1. 判断请求路径是否与我们的目标路径一致
  2. 路径如果一致则获取文件中的json数据转换成Java对象
  3. 将处理好变成Java对象的数据存到page对象中等待Pipeline的处理
  4. Pipeline对象在接收到处理好传递过来的数据的时候,进行收尾工作,可以选择保存文件、输出在控制台等等

博主在代码中也对内容步骤进行了注释,可以进行参考查看。

核心处理代码

import cn.dengsz.common.Constants;
import cn.dengsz.common.model.HeroInfo;
import cn.dengsz.common.model.HeroSkin;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Deng's
 * 去获取页面的进程
 */

public class HerosListPageProcessor implements PageProcessor {


    /**
     * 核心程序部分
     */
    @Override
    public void process(Page page) {
        // 处理英雄列表信息
        if (page.getUrl().get().equals(Constants.HERO_URL)) {
            // 获取页面内容
            String jsonResult = page.getJson().toString();
            // 利用fastjson解析json内容(根据返回内容决定获取key:hero的内容)
            JSONObject jsonObject = JSONObject.parseObject(jsonResult);
            // 将内容转换成数组
            JSONArray heros = jsonObject.getJSONArray(Constants.HERO_KEY);
            // 版本信息、更新时间
            String version = jsonObject.getString(Constants.VERSION);
            String updateFileTime = jsonObject.getString(Constants.UPDATE_TIME);
            // 获取到数据数组 判断数组内容是否为null
            if (heros.size() == 0) {
                return;
            }
            // 将处理好的信息存入Pipeline中
            List<HeroInfo> heroInfoList = heros.toJavaList(HeroInfo.class);
            page.putField(Constants.HERO_KEY, heroInfoList);
            page.putField(Constants.VERSION, version);
            page.putField(Constants.UPDATE_TIME, updateFileTime);
            
        }
    }

    @Override
    public Site getSite() {
        // 设置相关的请求头信息,防止反爬虫或者无效访问被拒绝
        return Site.me().setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/" +
                        "537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
                .addHeader("accept-encoding", "gzip, deflate, br")
                .addHeader("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
                .addHeader("origin", "https://101.qq.com")
                .setCharset("utf-8")
                .setRetryTimes(3).setSleepTime(1000);
    }
}

英雄信息的对象模型

import lombok.Data;
/**
 * @author Deng's
 * 仅仅获取一些有用的相关数据 保存下来。
 */
@Data
public class HeroInfo {

    /**
     * 英雄id
     */
    private String heroId;

    /**
     * 中文名
     */
    private String name;

    /**
     * 别名
     */
    private String alias;

    /**
     * 信息标题
     */
    private String title;

    /**
     * 金币售价
     */
    private String goldPrice;

    /**
     * 点券售价
     */
    private String couponPrice;

    /**
     * 一些关键信息
     */
    private String keywords;


}

一些固定的常量

写一些常量方便之后需要改动的时候进行全局直接生效。

比如文件存储位置、初始访问链接、固定常量名等等

/**
 * @author Deng's
 * 一些解析数据的常量
 */

public class Constants {
    public static final String HERO_KEY = "hero";
    public static final String VERSION = "version";
    public static final String UPDATE_TIME = "fileTime";
    public static final String PIC_URL = "https://game.gtimg.cn/images/lol/act/img/js/hero/";
    public static final String HERO_URL = "https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js?ts=2780565";

    /**
     * 预设一些文件存储地址
     * 英雄信息文件、英雄图片文件存储路径(默认桌面)
     */
    public static final String HERO_INFO_FILE = "/Users/dengs/Desktop/lol-skins/hero.json";
    public static final String HERO_PIC_FILE = "/Users/dengs/Desktop/lol-skins/";
}

核心的自定义Pipeline类

本教程将英雄数据存储为本地的json文件,存储地址可以去改动Constants类中的HERO_INFO_FILE常量值来改变。

import cn.dengsz.common.Constants;
import cn.dengsz.common.model.HeroInfo;
import cn.dengsz.common.model.HeroSkin;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

/**
 * @author Deng's
 * 处理由pageProcessor处理好后 塞过来的英雄数据(当然你可以在这里改造成存入数据库)
 */
@Slf4j
public class LolHeroPipeline implements Pipeline {

    @Override
    public void process(ResultItems resultItems, Task task) {
        // 判断当前请求路径是什么 再决定做什么事情
        if (resultItems.getRequest().getUrl().equals(Constants.HERO_URL)) {
            // 根据Processor传递过来参数做下一步处理
            List<HeroInfo> heroInfoList = resultItems.get(Constants.HERO_KEY);
            // 利用hutool可以将内容快速输出成文件
            try {
                //Constants.HERO_INFO_FILE 为文件输出的地址
                FileWriter fileWriter = new FileWriter(Constants.HERO_INFO_FILE);
                fileWriter.write(JSONObject.toJSONString(heroInfoList));
                fileWriter.close();
            } catch (IOException e) {
                log.error("写出英雄信息出现问题,请查看:{}", e.getMessage());
                throw new RuntimeException(e);
            }
        }
    }
}

最后放上这个项目的启动类

import cn.dengsz.common.Constants;
import cn.dengsz.core.HerosListPageProcessor;
import cn.dengsz.core.LolHeroPipeline;
import us.codecraft.webmagic.Spider;

/**
 * @author Deng's
 */
public class App
{

    public static void main( String[] args ) {
        // 调用数据爬虫进程
        // 可以增加线程来提高运行效率(thread)
        long beginTime = System.currentTimeMillis();
        Spider.create(new HerosListPageProcessor())
                .addUrl(Constants.HERO_URL)
                .addPipeline(new LolHeroPipeline())
                .thread(5)
                .run();
        System.out.printf("用时 %d ms",System.currentTimeMillis()-beginTime);
    }
}

总结

通过以上代码我们可以初步完成对于LOL英雄数据信息的爬取与保存,也算是为大家对爬虫有了初步了解。

4.项目实战(提升篇)

有了上面的案例以后,其实获取英雄图片也是同理分析和完成的。

首先第一步,仍然是对于网页请求的分析。思考一下我们英雄的图片从何而来。

4.1.请求分析

我们可以随机点击一个英雄信息后,对英雄的信息进行查看与分析。

🚪 英雄详情页传送门

我们同样通过F12在请求列表中找到了一个比较可疑的请求1.js

为什么会找到这个请求呢?

只要仔细观察会发现我们解析的英雄详情路径是这样的:

https://101.qq.com/#/hero-detail?heroid=1&datatype=5v5

可以看到其中有一个关键信息是heroid=1

不用多说基本就代表了当前英雄的id编号了

所以由此才会去找到一个1.js的这个请求,与heroId相对应

image-20221114232335572

不出所料我们找到了有用的皮肤信息

点开皮肤skins查看每个skin的数据结构大概如下

{
  "skinId": "1000",
  "heroId": "1",
  "heroName": "黑暗之女",
  "heroTitle": "安妮",
  "name": "黑暗之女",
  "chromas": "0",
  "chromasBelongId": "0",
  "isBase": "1",
  "emblemsName": "base",
  "description": "",
  "mainImg": "https://game.gtimg.cn/images/lol/act/img/skin/big1000.jpg",
  "iconImg": "https://game.gtimg.cn/images/lol/act/img/skin/small1000.jpg",
  "loadingImg": "https://game.gtimg.cn/images/lol/act/img/skinloading/1000.jpg",
  "videoImg": "https://game.gtimg.cn/images/lol/act/img/skinvideo/sp1000.jpg",
  "sourceImg": "https://game.gtimg.cn/images/lol/act/img/sourceImg/guide1000.jpg",
  "vedioPath": "",
  "suitType": "",
  "publishTime": "",
  "chromaImg": ""
}

我们可以看到这里面就包含了图片的请求地址mainImg

当然如果我们继续仔细查看我们就会发现一些炫彩皮肤是没有mainImg这个属性值的。

所以我们可以在代码处理的时候通过mainImg是否有值来判断是不是皮肤,还是炫彩皮肤。

所以爬虫的时候 分析是很重要的一件事情,请大家铭记。

并且获取到了当前内容的请求地址为:https://game.gtimg.cn/images/lol/act/img/js/hero/1.js?ts=2780731

综合上面所有的分析内容,我们就可以知道请求英雄详情的地址是固定的,唯一的变数是结尾的{heroId}.js

所以我们只要一一对每个英雄所对应的heroId进行拼接访问,再依次获取对应皮肤图片的地址下载下来即可!

4.2.代码部分

信息对象模型

同样的这样的内容我们需要建立一个对象模型来方便我们接受处理数据

package cn.dengsz.common.model;

import lombok.Data;

/**
 * @author Deng's
 * 英雄的皮肤信息实体类(这里的内容可以根据返回的json信息自己进行需要的属性定义)
 */
@Data
public class HeroSkin {

    /**
     * 皮肤id
     */
    private String skinId;

    /**
     * 英雄id
     */
    private String heroId;

    /**
     * 英雄名
     */
    private String heroName;

    /**
     * 皮肤名
     */
    private String name;

    /**
     * 主图
     */
    private String mainImg;

    /**
     * 图标
     */
    private String iconImg;

    /**
     * 炫彩皮肤
     */
    private String chromaImg;
}

核心处理类HerosListPageProcessor

因为增加了对于英雄id的记录,以及对每次链接请求的判断(如果是列表就保存英雄数据,如果是英雄详情则下载皮肤图片)

因此改造后的核心HerosListPageProcessorprocess()函数应该如下

/**
     * 核心程序部分
     */
    @Override
    public void process(Page page) {
        // 处理英雄列表信息
        if (page.getUrl().get().equals(Constants.HERO_URL)) {
            // 获取页面内容
            String jsonResult = page.getJson().toString();
            // 利用fastjson解析json内容(根据返回内容决定获取key:hero的内容)
            JSONObject jsonObject = JSONObject.parseObject(jsonResult);
            // 将内容转换成数组
            JSONArray heros = jsonObject.getJSONArray(Constants.HERO_KEY);
            // 版本信息、更新时间
            String version = jsonObject.getString(Constants.VERSION);
            String updateFileTime = jsonObject.getString(Constants.UPDATE_TIME);
            // 获取到数据数组 判断数组内容是否为null
            if (heros.size() == 0) {
                return;
            }
            // 将处理好的信息存入Pipeline中
            List<HeroInfo> heroInfoList = heros.toJavaList(HeroInfo.class);
            page.putField(Constants.HERO_KEY, heroInfoList);
            page.putField(Constants.VERSION, version);
            page.putField(Constants.UPDATE_TIME, updateFileTime);
            // 下载英雄图片信息,经过分析得到英雄信息详情的json信息路径(写在Constants中)
            // 需要根据每个heroId来查询对应的信息 最终返回每张图片的下载地址
            this.getImgReqList(page, heroInfoList);
        }
        // 判断当前url路径是否是英雄信息详情
        if (page.getUrl().get().contains(Constants.PIC_URL)) {
            // 处理单只英雄详情(先获取json数据对象)
            JSONObject heroDetail = JSONObject.parseObject(page.getJson().toString());
            // 从英雄详情中获取到skins这个属性
            JSONArray skins = heroDetail.getJSONArray("skins");
            List<HeroSkin> heroSkins = skins.toJavaList(HeroSkin.class);
            // 不要炫彩皮肤,我们筛选出有主皮肤图的数据即可
            List<HeroSkin> screenSkins = heroSkins.stream().filter(item -> !item.getMainImg().isEmpty()).collect(Collectors.toList());
            // 存入页面空间中待pipeLine处理
            page.putField("skins", screenSkins);
        }

    }

    /**
     * 批量去添加所有英雄的详细信息的请求路径
     */
    private void getImgReqList(Page page, List<HeroInfo> heroInfoList) {
        // 根据heroId去请求不同的英雄信息
        for (HeroInfo heroInfo : heroInfoList) {
            // 拼接图片请求路径(添加目标链接)
            page.addTargetRequest(Constants.PIC_URL+heroInfo.getHeroId()+".js");
            System.out.println(page.getJson().toString());
        }
    }

最后结果处理类LolHeroPipeline

同样的我们的最终处理类的process()函数也要添加一个额外操作

要对进来的路径进行判断,如果是英雄详情的路径则需要下载图片

// 判断路径如果是英雄详情路径则开始下载图片文件
        if (resultItems.getRequest().getUrl().contains(Constants.PIC_URL)) {
            // 根据捕获到的信息下载图片
            List<HeroSkin> skins = resultItems.get("skins");
            // 创建文件夹存储皮肤(采用默认路径+英雄名 来作为文件夹路径)
            String saveFilePath = Constants.HERO_PIC_FILE + skins.get(0).getHeroName();
            FileUtil.mkdir(saveFilePath);
            for (HeroSkin skin : skins) {
                // 利用hutool工具下载文件  参数一:下载地址 参数二:保存路径
                long size = HttpUtil.downloadFile(skin.getMainImg(), FileUtil.file(saveFilePath));
                log.info("下载 {} 图片成功,大小为 {}, 存储地址为{}",skin.getName(),size,saveFilePath);
            }
        }

4.3.项目源码

完整的项目案例博主已经上传到Github中,如有需要可以直接访问下载

如果对你有参考价值的话,希望能获取你的一个start

🚪 代码仓库:lol-spider源码

🏜写在最后

本文通过实战案例的方式来讲解和应用WebMagic这个Java爬虫框架。

在爬虫的过程中,其实对于页面内容的解析是很重要的。所以在这一步的时候提醒大家需要用心一点哦。

如果本文章对你有用,请不要忘记一键三连!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/8671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Asesprite】快速自制Tileset瓦片地图集(俯视角)

使用Aseprite软件完成一个Tileset素材的制作&#xff0c;用于2D游戏开发。 目录 一、基础配置 二、草地和泥土 三、导出为TileSet素材 一、基础配置 1.创建一个96x48的画布。 2.在菜单中选择View-》GridSettings。 3.设置网格宽高为16x16。 4.点击View-》Show-》Grid显…

IOS手机和车机互联自动化测试

在酷热的夏天&#xff0c;提前打开空调&#xff1b;在寒冷的冬天&#xff0c;提前加热座椅和方向盘。这些贴心的功能都是通过手机远程控制汽车实现的。随着汽车新四化的进程推进&#xff0c;类似手机和车机连接的功能必然越来越多。 作为汽车行业的工程师&#xff0c;我们都知道…

Jenkins 忘记登录密码解决办法

今天给大家分享下 jenkins 登录密码忘记的解决办法&#xff0c;方法不唯一&#xff0c;都能解决问题&#xff0c;按照自己的习惯来做更好。 1、先停止 jenkins 服务 systemctl stop jenkins 此步骤可以结合 ps -ef | grep jenkins 和 kill -9 jenkins进程号 一起解决2、找到…

简单实用的Python图像处理库Pillow

Pillow图像处理Pillow 库的安装图象处理基本知识图像的RGB 色彩模式像素阵列Image 模块打开和新建混合透明度混合处理遮罩混合处理复制和缩放复制图像缩放像素缩放图像粘贴和裁剪粘贴裁剪图像图像旋转格式转换covert()transpose()分离和合并分离合并滤镜其他内置函数ImageFilte…

A Blockchain-Driven IIoT Traffic Classification Service for Edge Computing 论文学习

A Blockchain-Driven IIoT Traffic Classification Service for Edge Computing IEEE INTERNET OF THINGS JOURNAL&#xff0c;2021 文章目录A Blockchain-Driven IIoT Traffic Classification Service for Edge ComputingSummaryResearch Objective(s)Background / Problem S…

用Canvas绘制一个数字键盘

Hello啊老铁们&#xff0c;这篇文章还是阐述自定义View相关的内容&#xff0c;用Canvas轻轻松松搞一个数字键盘&#xff0c;本身没什么难度&#xff0c;这种效果实现的方式也是多种多样&#xff0c;这篇只是其中的一种&#xff0c;要说本篇有什么特别之处&#xff0c;可能就是纯…

OpenGL 灰度图

目录 一.OpenGL 灰度图 1.IOS Object-C 版本1.Windows OpenGL ES 版本2.Windows OpenGL 版本 二.OpenGL 灰度图 GLSL Shader三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 &…

振弦采集模块AABB 通讯协议

振弦采集模块AABB 通讯协议 AABB 通讯协议是一种非标准自定义协议&#xff0c; 相较于 MODBUS 通讯协议&#xff0c;结构更简单&#xff0c;指令生成方法更容易&#xff0c;便于进行快速测试。 AABB 通讯协议支持单寄存器读写两种指令。 &#xff08; 1&#xff09; 读取单个寄…

《Care Bears 爱心熊》人物化身来到 The Sandbox 元宇宙!

无论你想要快乐、和谐、幸运还是温暖&#xff0c;都会有一个适合你的爱心熊人物化身&#xff01;&#x1f43b; 想成为一只爱心熊吗&#xff1f; 《爱心熊》作品集是由 3060 个独特的 The Sandbox 人物化身组成的作品集&#xff0c;可在欢快而多彩的元宇宙世界中玩耍。每个人物…

【Linux】软件包管理器yum和编辑器vim(内附动图)

大家好我是沐曦希&#x1f495; 文章目录1.Linux 软件包管理器 yum1.1 什么是软件包1.2 第一个软件rzsz2.Linux编辑器-vim使用2.1 vim的基本概念2.2 vim的基本操作2.3 命令模式2.3.1 光标定位2.3.2 文本复制2.4 插入模式2.5 底行模式2.5.1 调用和取消行号2.5.2 底行&#xff01…

Node.js | 详解 Cookie-Session登录验证 的工作原理

&#x1f9d1;‍&#x1f4bc; 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f5a5;️ 本系列专栏&#xff1a;Node.js从入门到精通 &#x1f449; 你的一键三连是我更新的最大动力❤️&#xff01; &#x1f4e2; 欢迎私信博主加入前端交流群&#x1f339; …

Maven版本3.6.1环境配置安装

官网下载安装包配置maven环境变量配置本地仓库以及阿里云镜像官网下载安装包 下载maven安装包官网地址&#xff0c;解压即可使用&#xff0c;推荐下载apache-maven-3.6.1-bin.zip 配置maven环境变量 找到此电脑右键-->点击属性-->选择高级系统设置-->点击环境变量--&g…

EPICS记录参考--计算输出记录(calcout)

计算输出或"Calcout"记录类似于Calc记录&#xff0c;其增加了能够输出的特性(一个"output link"和一个"output event")&#xff0c;根据计算结果条件地执行它们。这种特性允许在一个EPICS数据库内实现了条件分支(例如&#xff1a;只在Record_B有…

BERT预训练模型学习笔记

1.Transforme 1.1 要做一件什么事 基本组成依旧是机器翻译模型中常见的Seq2Seq网络输入输出都很直观&#xff0c;其核心架构就是中间的网络设计了MxN&#xff0c;输入M&#xff0c;输出N 1.2 传统的RNN网络有什么问题 传统RNN是一个时序模型&#xff0c;下一个RNN的输入依靠…

野火FPGA入门(4):时序逻辑电路

文章目录第11讲&#xff1a;寄存器第12讲&#xff1a;阻塞赋值与非阻塞赋值第13讲&#xff1a;计数器第14讲&#xff1a;分频器&#xff1a;偶分频第15讲&#xff1a;分频器&#xff1a;奇分频第16讲&#xff1a;按键消抖组合逻辑存在竞争冒险 第11讲&#xff1a;寄存器 寄存…

【Debug】关于 nginx 上传文件时出现 413 及 500 错误码解决方法

先简单介绍一下 Nginx…   Nginx 作为一个高性能的 HTTP 和 反向代理 web 服务器具有占用内存少, 并发能力强等特点,可以说 Nginx 专为性能和效率而生, 如 tomcat 的并发量大约在 100 多, 而 Nginx 的并发量可以达到 5 万之多;   Nginx 的主要作用还是反向代理, 实现负载均衡…

什么是扩散模型(Diffusion Model)?

扩散模型是什么&#xff1f;如何工作以及他如何解决实际的问题 在计算机视觉中&#xff0c;生成模型是一类能够生成合成图像的模型&#xff08;文本生成图像【DALL2、Stable Diffusion】、图像生成图像【Diffusion-GAN】&#xff09;。例如&#xff0c;一个被训练来生成人脸的…

2023年天津市大学软件学院高职升本科联合招生专业考试大纲

天津市大学软件学院 2023年“高职升本科”联合招生专业考试大纲一、考试性质 天津市大学软件学院“高职升本科”联合招生专业考试是由合格的高职高专毕业生参加的选拔性考试。高等院校根据考生的成绩&#xff0c;按照已确定的招生计划&#xff0c;德、智、体全面衡量&#xff0…

MATLAB if...else...end 语句

在MATLAB的 if...else...end 语句中&#xff0c;if 语句后面可以跟一个可选择的 else 语句&#xff0c;当执行的表达式为假的时候&#xff0c;执行 else 语句。 if...else...end 语句语法&#xff1a; MATLAB 中一个 if ... else 语句的语法示例&#xff1a; if <expressio…

【python】一篇玩转正则表达式

目录 前言 正则表达式 行定位符 1.^ 2.$ 元字符 常见的元字符 限定符 常用的限定符 字符类 排除字符 选择字符 转义字符 &#xff08;&#xff09; python使用正则表达式 匹配字符串 match() search() findall() sub() 替换敏感字符 split() 前言 正则表…