【Selenium+Webmagic】基于JAVA语言实现爬取js渲染后的页面,附有代码

事先声明
笔者最近需要查看一些数据,自己挨个找太麻烦了,于是简单的学了一下爬虫。笔者在这里声明,爬的数据只为学术用,没有其他用途,希望来这篇文章学习的同学能抱有同样的目的。

枪本身不坏,坏的是使用枪的人

效果
在这里插入图片描述

基于JAVA语言实现爬取js渲染后的页面,详细教程

  • 下载ChromeDriver
    • 下载ChromeDrive以及相对应的Chrome
    • 禁止Chrome自动升级
      • 第一步:禁用任务计划
      • 第二步:禁用更新服务
      • 第三步:重命名更新程序
  • 使用IDEA实现爬取js渲染后的页面
    • 所需依赖
    • 修改maven的镜像地址
    • 具体实现
      • 建议
      • WebMagic
      • 一个简单的demo
      • 实现思路
      • 使用Selenium解析js渲染后的页面信息
      • 重写自定义pageProcessor的process方法
      • 项目代码

下载ChromeDriver

查看自己的Chrome版本,过高需要卸载再下载
在地址栏键入

chrome://version/

查看版本
在这里插入图片描述

下载ChromeDrive以及相对应的Chrome

ChromeDriver的版本需要仔细考究,一个ChromeDriver版本对应一个Chrome版本,由于Chrome版本更新太快,最近已经到119.xx了,ChromeDriver最高支持版本才115.xx, 因此我们要先把本地的Chrome卸载,然后下载相应的历史版本
Chrome历史版本1
Chrome历史版本2 版本更多更全面
ChromeDriver历史版本

笔者以114为例子
在这里插入图片描述
点击后会进入下载页,里面有windows版本以及note.txt,在txt文件中会写有支持哪个Chrome版本
在这里插入图片描述
在这里插入图片描述
我上面给出的Chrome历史版本1中没有114版本,在历史版本2中有,可以自行去下载

禁止Chrome自动升级

由于Chrome更新太快,ChromeDriver跟不上,并且Chrome总是自动升级,这里给出禁止Chrome自动升级的解决办法1

第一步:禁用任务计划

首先是【右键计算机->管理】,在【计算机管理(本地)->系统工具->任务计划程序->任务计划程序库】中找到两个和Google自动更新相关的任务计划【GoogleUpdateTaskMachineCore】与【GoogleUpdateTaskMachineUA】,并把它俩禁用掉。
在这里插入图片描述

第二步:禁用更新服务

然后在下方的【服务和应用程序->服务】中,找到两个和Google更新相关的服务【Google更新服务(gupdate)】、【Google更新服务(gupdatem)】,并右键,选择属性,把启动类型改为禁用。如果没有找到的可以略过。
在这里插入图片描述

第三步:重命名更新程序

完成上面两步后理论上就可以停止Chrome的自动更新了,不过有网友说这么做之后,不要在Chrome中点击【帮助->关于Google Chrome】
这里笔者尝试过,确实有这种情况,为了避免,我们可以修改他的update.exe的名字:
笔者给出自己电脑上update的地址:(没有修改Chrome默认安装地址)

C:\Program Files (x86)\Google\Update

修改这个名字,如果你在这个位置没有找到,可以参考资料1的位置
在这里插入图片描述
到这里就结束了,在地址栏键入

chrome://version/

查看当前版本

不过笔者没有再尝试在Chrome中点击【帮助->关于Google Chrome】是否会更新,大胆的小伙伴可以试试

使用IDEA实现爬取js渲染后的页面

爬取的页面: 国家统计局发布的数据
在这里插入图片描述

相应的版本

SpringBoot 2.6.13
Webmagic: 0.8.0
Selenium-java 3.141.59

现在SpringInitializer已经不支持SpringBoot2.x了,你可以升级使用SpringBoot3,再使用下面代码或者参考我另一篇文章使用SpringBoot2:Spring Initializer 已经不支持Java8,也就是SpringBoot2.x项目初始化

所需依赖

下面依赖有些你可能不需要 比如thymeleaf,不过都加上也不会报错

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/us.codecraft/webmagic-extension -->
        <dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic-extension</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
            <version>0.8.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>32.1.3-jre</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--模拟浏览器行为-->
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
        </dependency>

    </dependencies>

修改maven的镜像地址

下载semenium的依赖需要的时间会比较长,而且下载webmagic依赖的时候有些包在阿里云Central镜像下找不到, 需要修改为all
打开配置文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
修改完保存即可

具体实现

建议

再看下面代码之前,还是要有一定的webmagic基础的,推荐BiliBili上一个教程,只需要两个多小时就能理解webmagic的工作流程Java爬虫案例实战-webmagic(第二话) 2021最新

WebMagic

WebMagic中文文档

从图中可以看到Spider是爬虫启动的关键入口。

我们要做的就是自定义一个xxPageProcessor,实现PageProcessor接口,重写两个方法
Site, process
在process方法中将抓取到的url地址添加到scheduler队列中,图中一个request其实是一个url地址,并不是http的请求;
其中resultItems保存的是向pipeline中写入的数据,是一个linkedhash结构

pipeline是输出的关键,可以向控制台中输出,也可以自定义一个pipeline,向数据库中写入信息

Scheduler默认是内存队列,可以修改为redis队列(成本高)

Download我这里没有自定义,不过官网给出了自定义的方法,感兴趣的可以看看

一个简单的demo

/**
 * @Author:sichenyong
 * @Email: sichenyongwork@163.com
 * @Package:com.scy
 * @Project:crawer
 * @Date:2023/12/2 19:45
 * @description:使用css选择器解析
 */
@Slf4j
public class MyPageProcessor2 implements PageProcessor {
    public void process(Page page) {
        Html html = page.getHtml();
        String title = html.css("title", "text").get();
        log.info("title is {}", title);
        page.putField("title", title);

        String s = html.css("a", "href").get();
        // 向resultItems中写入数据
        page.putField("a", s);
        List<String> all = html.css("a", "href").all();
        page.putField("allLinks", all);

        page.putField("html",html);

    }

    public Site getSite() {
        return Site.me();
    }

    public static void main(String[] args) {
        MyPageProcessor2 myPageProcessor2 = new MyPageProcessor2();
        Spider.create(myPageProcessor2).addUrl("https://www.stats.gov.cn/sj/sjjd/202311/t20231115_1944598.html")
                .start();
    }
}

实现思路

在这里插入图片描述
相较于webmagic的架构,我们只需要在process方法中使用selenium的解析方法获取js加载后的数据就可以

使用Selenium解析js渲染后的页面信息

  1. 首先定义初始化chromedriver的函数

    private String devicePath = "D:\\SoftWare\\environemnt\\chromeDriver\\chromedriver.exe";
    private ChromeDriver webDriver;
    
    
    void setUp(){
       System.getProperties().setProperty("webdriver.chrome.driver",devicePath);
       ChromeOptions options = new ChromeOptions();
       options.addArguments("--headless");
       webDriver = new ChromeDriver(options);
       webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
    }
    
  2. 实现解析函数

    /**
        * @description:解析js加载后的页面,获取相关信息
        * @author: sichenyong
        * @email: sichenyongwork@163.com
        * @date: 2023/12/4 16:43
        * @param: [page]
        * @return: com.example.entity.UsefulMessage
        **/
       UsefulMessage parseJS(Page page) {
    
           UsefulMessage usefulMessage = new UsefulMessage();
           String url = page.getUrl().get();
           webDriver.get(url);
           // 获取所有的a标签地址
           List<WebElement> aElements = webDriver.findElements(By.cssSelector("div.list-content > ul > li > a.fl.mhide.pc1200"));
           if (aElements.size() > 0) {
               List<String> hrefValue = new ArrayList<>();
    
               for (WebElement aElement : aElements) {
                   hrefValue.add(aElement.getAttribute("href"));
               }
               // 设置列表地址
               usefulMessage.setHrefs(hrefValue);
               // 设置是否是列表页
               usefulMessage.setListPage(true);
               // 获取下一页的地址
               WebElement element = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.wrapper-list-right > div.list-pager.mhide > a.next"));
               String nextUrl = element.getAttribute("href");
               //设置下一页的url地址
               usefulMessage.setNextPageUrl(nextUrl);
               log.info("===下一页地址===" + nextUrl);
    
               String column = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.wrapper-list-left.mhide > div > ul > li.active")).getText();
               // 设置栏目
               usefulMessage.setColumn(column);
           }
           webDriver.quit();
           return usefulMessage;
       }
    
  3. 完整代码

    /**
    * @Author:sichenyong
    * @Email: sichenyongwork@163.com
    * @Package:com.example.component
    * @Project:selenium
    * @Date:2023/12/3 22:02
    * @description:使用selenium解析js加载之后的页面信息
    * @Version:1.0 由于笔者没有学过设计模式,因此写的代码有些冗余,见谅。
    */
    @Slf4j
    public class SeleniumProcessor {
    	//下载的ChromeDriver地址
       private String devicePath = "D:\\SoftWare\\environemnt\\chromeDriver\\chromedriver.exe";
       private ChromeDriver webDriver;
    
    
       void setUp(){
           System.getProperties().setProperty("webdriver.chrome.driver",devicePath);
           ChromeOptions options = new ChromeOptions();
           options.addArguments("--headless");
           webDriver = new ChromeDriver(options);
           webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
       }
    
       /**
        * @description:解析js加载后的页面,获取相关信息
        * @author: sichenyong
        * @email: sichenyongwork@163.com
        * @date: 2023/12/4 16:43
        * @param: [page]
        * @return: com.example.entity.UsefulMessage
        **/
       UsefulMessage parseJS(Page page) {
    		// 自定义的实体类,保存自己向要的js生成的信息
           UsefulMessage usefulMessage = new UsefulMessage();
           String url = page.getUrl().get();
           webDriver.get(url);
           // 获取所有的a标签地址
           List<WebElement> aElements = webDriver.findElements(By.cssSelector("div.list-content > ul > li > a.fl.mhide.pc1200"));
           if (aElements.size() > 0) {
               List<String> hrefValue = new ArrayList<>();
    
               for (WebElement aElement : aElements) {
                   hrefValue.add(aElement.getAttribute("href"));
               }
               // 设置列表地址
               usefulMessage.setHrefs(hrefValue);
               // 设置是否是列表页
               usefulMessage.setListPage(true);
               // 获取下一页的地址
               WebElement element = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.wrapper-list-right > div.list-pager.mhide > a.next"));
               String nextUrl = element.getAttribute("href");
               //设置下一页的url地址
               usefulMessage.setNextPageUrl(nextUrl);
               log.info("===下一页地址===" + nextUrl);
    
               String column = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.wrapper-list-left.mhide > div > ul > li.active")).getText();
               // 设置栏目
               usefulMessage.setColumn(column);
           }
           webDriver.quit();
           return usefulMessage;
       }
    
       /**
        * @description: 解析网页的数据
        *              parse可以根据需要进行修改,爬取你想要的
        * @author: sichenyong
        * @email: sichenyongwork@163.com
        * @date: 2023/12/4 14:20
        * @param: [page, filterTitle]
        * @return: void
        **/
       void parse(Page page, String filterTitle, String column) {
           try {
               // 获取url
               String url = page.getUrl().get();
               webDriver.get(url);
               // 获取标题
               String title = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.detail-title > h1")).getText();
               if (title.contains(filterTitle)) {
                   // 创建数据库实体
                   Stats stats = new Stats();
                   // 读入当前页的url
                   stats.setPubUrl(url);
                   // 读入title
                   stats.setWebTitle(title);
                   // 读入栏目
                   stats.setPubColumn(column);
                   // 获取数据来源
                   WebElement source = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.detail-title > div > h2:nth-child(1) > span"));
                   String pubSources = source.getText();
                   String regex = ":";
                   if (pubSources.contains(":")) {
                       regex = ":";
                   }
                   String[] strings = pubSources.split(regex);
                   String pubSource = strings[strings.length-1];
                   stats.setPubSource(pubSource);
                   // 获取发布时间
                   String pubTime = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.detail-title > div > h2:nth-child(1) > p")).getText();
                   pubTime = pubTime.replaceAll("/","-");
                   stats.setPubTime(pubTime);
    
                   // 存入数据库
                   page.putField("stats",stats);
               }
               else {
                   log.error("文章\"" + title + "\"中不包含关键字:{}", filterTitle);
                   page.getResultItems().setSkip(true);
               }
           } catch (Exception e) {
               e.printStackTrace();
           }
           finally {
               webDriver.quit();
           }
       }
    
       /**
        * @description: 需要过滤的数据有多个
        * @author: sichenyong
        * @email: sichenyongwork@163.com
        * @date: 2023/12/4 14:21
        * @param: [page, filterTitles]
        * @return: void
        **/
       void parse(Page page, List<String> filterTitles,String column) {
           try {
               // 获取url
               String url = page.getUrl().get();
               webDriver.get(url);
               // 获取标题
               String title = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.detail-title > h1")).getText();
               if (support(title, filterTitles)) {
                   // 创建数据库实体
                   Stats stats = new Stats();
                   // 读入当前页的url
                   stats.setPubUrl(url);
                   // 读入title
                   stats.setWebTitle(title);
                   // 读入栏目
                   stats.setPubColumn(column);
                   // 获取数据来源
                   WebElement source = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.detail-title > div > h2:nth-child(1) > span"));
                   String pubSources = source.getText();
                   String regex = ":";
                   if (pubSources.contains(":")) {
                       regex = ":";
                   }
                   String[] strings = pubSources.split(regex);
                   String pubSource = strings[strings.length-1];
                   stats.setPubSource(pubSource);
                   // 获取发布时间
                   String pubTime = webDriver.findElement(By.cssSelector("body > div > div.wrapper-content > div > div.detail-title > div > h2:nth-child(1) > p")).getText();
                   pubTime = pubTime.replaceAll("/","-");
                   stats.setPubTime(pubTime);
    
                   // 存入数据库
                   page.putField("stats",stats);
               }
               else {
                   log.error("文章\"" + title + "\"中不包含关键字:{}", filterTitles);
                   page.getResultItems().setSkip(true);
               }
           } catch (Exception e) {
               e.printStackTrace();
           }
           finally {
               webDriver.quit();
           }
       }
    
       /**
        * @description:判断title是否在想要的列表中
        * @author: sichenyong
        * @email: sichenyongwork@163.com
        * @date: 2023/12/4 14:28
        * @param: [title, filterTitles]
        * @return: boolean
        **/
       boolean support(String title, @NotNull List<String> filterTitles) {
           for (String filterTitle : filterTitles) {
               if (title.contains(filterTitle)) {
                   return true;
               }
           }
           return false;
       }
    }
    
    

重写自定义pageProcessor的process方法

/**
 * @Author:sichenyong
 * @Email: sichenyongwork@163.com
 * @Package:com.scy.component
 * @Project:stats
 * @Date:2023/12/3 13:25
 * @description:
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Slf4j
public class StatsPageProcessor implements PageProcessor {
    /**
     * @description: 过滤标题文章,保存含有filterTitle的文章
     * demo: filterTitle = "Java"
     *          函数会自动保存所有含有Java的文章,将不含有java的文章过滤掉
     * @author: sichenyong
     * @email: sichenyongwork@163.com
     * @date: 2023/12/3 14:03
     **/
    protected String filterTitle="";
    protected List<String> filterTitles;
    private String column;

    @Override
    public void process(Page page) {

        SeleniumProcessor seleniumProcessor1 = new SeleniumProcessor();
        seleniumProcessor1.setUp();
        // 获取解析js后的网页信息
        UsefulMessage usefulMessage = seleniumProcessor1.parseJS(page);

        // 是列表页
        if (usefulMessage.isListPage()) {
            // 获取所有的链接
            List<String> links = usefulMessage.getHrefs();
            // 传给Scheduler
            page.addTargetRequests(links);
            // 解析下一页
            String nextPage = usefulMessage.getNextPageUrl();
            page.addTargetRequest(nextPage);

            column = usefulMessage.getColumn();
            // 列表页面的数据不写入数据库
            page.getResultItems().setSkip(true);
        }
        else {
            // 详情页面写入数据库
//            parseStats(page);
            SeleniumProcessor seleniumProcessor = new SeleniumProcessor();
            seleniumProcessor.setUp();
            if (filterTitles == null) {
                seleniumProcessor.parse(page, filterTitle, column);
            }
            else {
                seleniumProcessor.parse(page, filterTitles, column);
            }
        }
    }


    /**
     * @description: 解析详情页面 - 无法解析js加载的页面
     * @Deprecated
     * @param: page
     * @return: void
     * @author: sichenyong
     * @email: sichenyongwork@163.com
     * @date: 2023/12/3 14:04
     **/
    @Deprecated
    private void parseStats(Page page) {
        Html html = page.getHtml();
        // 获取页面的标题
        String title = html.css("body > div > div.wrapper-content > div > div.detail-title > h1","text").get();
        // 如果文章中包含filterTitle,则保存文章
        if (title.contains(filterTitle)) {
            Stats stats = new Stats();
            //获取当前页面的url
            String currentUrl = page.getUrl().get();
            // 获取当前页面的pubtime
            String pubTime = html.css("body > div > div.wrapper-content > div > div.detail-title > div > h2:nth-child(1) > p", "text").get();
            // 获取页面的来源
            String pubSources = html.xpath("/html/body/div/div[3]/div/div[1]/div/h2[1]/span/text()").get();
            String regex = ":";
            if (pubSources.contains(":")) {
                regex = ":";
            }
            String[] strings = pubSources.split(regex);
            String pubSource = strings[strings.length-1];

            stats.setWebTitle(title);
            stats.setPubUrl(currentUrl);
            stats.setPubSource(pubSource);
            stats.setPubTime(pubTime);

            // 写入数据库
            page.putField("stats",stats);
        }
    }

    @Override
    public Site getSite() {
        Site site = new Site();
        // 设置重试间隔时间
        site.setRetryTimes(3);
        site.setRetrySleepTime(3000);
        site.setSleepTime(3000);
        return site;
    }
}

项目代码

这里笔者使用的是阿里云云效Code代码托管平台,项目地址


  1. 三步彻底关闭chrome谷歌浏览
    器自动更新; ↩︎ ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EOCR-CT电流互感器与SR-CT区别简介

电流互感器CT是&#xff08;Current Transformers&#xff09;的缩写&#xff0c;是将一次测的大电流&#xff0c;按比列变为适合通过测量仪表或保护装置的变换设备。 EOCR外部电流互感器3CT和SR-CT是专为保护大负载的组合使用&#xff0c;电流变比100&#xff1a;5&#xff0…

如何部署自己的服务渲染页面为Pdf文档

前言 相信大家都觉得官方发布的文档生成模块https://docs.mendix.com/appstore/modules/document-generation/很有用&#xff0c;它能把Mendix页面像素级导出到Pdf文件中&#xff0c;这对于归档等业务非常有价值。但部署依赖公有云提供的渲染服务&#xff0c;而中国本土用户对…

常用API(一)

API(全称 Application Programming Interface&#xff1a;应用程序编程接口) 就是别人写好的一些程序&#xff0c;给我们直接拿去调用即可解决问题的。 包 什么是包&#xff1f; 包是用来分门别类的管理各种不同程序的&#xff0c;类似于文件夹&#xff0c;建包有利于程序的管…

python数据分析总结(pandas)

目录 前言 df导入数据 df基本增删改查 数据清洗 ​编辑 索引操作 数据统计 行列操作 ​编辑 df->types 数据格式化 ​编辑 日期数据处理 前言 此篇文章为个人python数据分析学习总结&#xff0c;总结内容大都为表格和结构图方式&#xff0c;仅供参考。 df导入数…

在线教育小程序正在成为教育行业的新生力量

教育数字化转型是目前教育领域的一个热门话题&#xff0c;那么到底什么是教育数字化转型&#xff1f;如何做好教育数字化转型&#xff1f; 教育数字化转型是利用信息技术和数字工具改变和优化教育的过程。主要特征包括技术整合、在线学习、个性化学习、大数据分析、云计算、虚拟…

视频封面提取:精准截图,如何从指定时长中提取某一帧图片

在视频制作和分享过程中&#xff0c;一个有吸引力的封面或截图往往能吸引更多的观众点击观看。有时候要在特定的时间段内从视频中提取一帧作为封面或截图。如果每个视频都手动提取的话就会耗费很长时间&#xff0c;那么如何智化能批量提取呢&#xff1f;现在一起来看下云炫AI智…

VUE2+THREE.JS 按照行动轨迹移动人物模型并相机视角跟随人物

按照行动轨迹移动人物模型并相机视角跟随人物 1. 初始化加载模型2. 开始移动模型3. 人物模型启动4. 暂停模型移动5. 重置模型位置6. 切换区域动画7. 摄像机追踪模型8. 移动模型位置9.动画执行 人物按照上一篇博客所设定的关键点位置&#xff0c;匀速移动 1. 初始化加载模型 //…

选择护眼台灯的标准,符合国家最高标准的护眼台灯推荐

据中国国家卫生健康委员会发布的报告&#xff0c;2020年全国青少年近视率为53.6%&#xff0c;其中&#xff0c;小学生近视率为38.1%&#xff0c;初中生近视率为71.6%&#xff0c;高中生近视率为81.0%。这意味着中国青少年中&#xff0c;大多数人都存在不同程度的近视问题&#…

【Java用法】Lombok中@SneakyThrows注解的使用方法和作用

Lombok中SneakyThrows注解的使用方法和作用 一、SneakyThrows的作用二、SneakyThrows注解原理 一、SneakyThrows的作用 普通Exception类,也就是我们常说的受检异常或者Checked Exception会强制要求抛出它的方法声明throws&#xff0c;调用者必须显示的去处理这个异常。设计的目…

如何使用eXtplorer+cpolar内网穿透搭建个人云存储实现公网访问

文章目录 1. 前言2. eXtplorer网站搭建2.1 eXtplorer下载和安装2.2 eXtplorer网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1. 前言 通过互联网传输文件&#xff0c;是互联网最重要的应用之一&#xff0c;无论是…

Mybatis源码解析2:全局配置

Mybatis源码解析2&#xff1a;全局配置 1.项目结构2. 源码分析2.1.SqlSessionFactoryBuilder#build(java.io.InputStream)2.2 XMLConfigBuilder构造器2.3 解析XMLConfigBuilder#parse2.4 解析配置 XMLConfigBuilder#parseConfiguration 1.项目结构 源码地址&#xff1a; 项目结…

MySQL-日期时间函数详解及练习

目录 3.1 返回当前日期 3.2 提取日期部分 3.3 增加或减去时间 3.4 格式化时期或时间 3.5 牛客练习题 3.1 返回当前日期 1. CURDATE() 或 CURRENT_DATE() | 返回当前日期 select curdate();select current_date(); 结果&#xff1a; 2. CURTIME() 或 CURRENT_TIME() | 返…

【PyTorch】 暂退法(dropout)

文章目录 1. 理论介绍2. 实例解析2.1. 实例描述2.2. 代码实现2.2.1. 主要代码2.2.2. 完整代码2.2.3. 输出结果 1. 理论介绍 线性模型泛化的可靠性是有代价的&#xff0c;因为线性模型没有考虑到特征之间的交互作用&#xff0c;由此模型灵活性受限。泛化性和灵活性之间的基本权…

STM32-EXTI外部中断

一、中断系统 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继续运行 中断优先级&#xff…

2021年第十届数学建模国际赛小美赛B题疾病传播的风险解题全过程文档及程序

2021年第十届数学建模国际赛小美赛 B题 疾病传播的风险 原题再现&#xff1a; 空气传播疾病可以通过咳嗽或打喷嚏、喷洒液体或灰尘传播。另一方面&#xff0c;一些常见的传染病只能通过飞沫传播。请建立一个模型&#xff0c;以评估密闭空间内空气传播和液滴传播疾病的可能性。…

查看电脑cuda版本

1.找到NVODIA控制面板 输入NVIDIA搜索即可 出现NVIDIA控制面板 点击系统信息 2.WINR 输入nvidia-smi 检查了一下&#xff0c;电脑没用过GPU&#xff0c;连驱动都没有 所以&#xff0c;装驱动…… 选版本&#xff0c;下载 下载后双击打开安装 重新输入nvidia-smi 显示如下…

喜讯:加速度商城系统全系列产品品牌全新升级为Shopfa

2月1日讯&#xff1a;经过1年多的品牌文化塑造&#xff0c;深圳市加速度软件开发有限公司经过研究决定&#xff0c;将旗下的多商户商城系列、小程序商城系列、B2B商城系列、供应商集采系列、电子元器件商城系列、跨境独立站商城系列、MRO工业品商城系列、外卖商城系列、智慧零售…

C++笔记:动态内存管理

文章目录 语言层面的内存划分C语言动态内存管理的缺陷new 和 delete 的使用了解语法new 和 delete 操作内置类型new 和 delete 操作自定义类型 new 和 delete 的细节探究new 和 delete 的底层探究operator new 和 operator new[]operator delete 和 operator delete[] 显式调用…

体验官分享 | 用户眼中的OK3588-C开发板究竟有多优秀?

编者荐语&#xff1a;飞凌嵌入式今年共发起了5期【产品体验官】活动&#xff0c;让更多热爱嵌入式的朋友免费体验到了自己感兴趣的产品&#xff0c;飞凌嵌入式也收获了很多宝贵的建议。活动期间体验官们创作了许多优质的体验报告&#xff0c;今天小编就与大家分享一篇来自体验官…

Django讲课笔记01:初探Django框架

文章目录 一、学习目标二、课程导入&#xff08;一&#xff09;课程简介&#xff08;二&#xff09;课程目标&#xff08;三&#xff09;适用人群&#xff08;四&#xff09;教学方式&#xff08;五&#xff09;评估方式&#xff08;六&#xff09;参考教材 三、新课讲授&#…