WebCollector

news2024/11/18 14:03:00

1.WebCollector简介

WebCollector也是一个基于Java的开源网络爬虫框架,其支持多线程、深度采集、URL维护及结构化数据抽取等。WebCollector项目的源码可以在GitHub上进行下载。相比于Crawler4j,WebCollector的可扩展性和适用性更强,如可以实现多代理的切换、断点采集和大规模数据采集。

WebCollector的依赖jar包有OkHttp(网页请求开源库)、Jsoup(HTML/XML类型的网页解析)、Gson(JSON数据解析)、slf4j/log4j(配置日志)、rocksdbjni(RocksDB数据存储)等。

2.依赖

GitHub - CrawlScript/WebCollector:WebCollector是一个基于 Java.It 的开源Web爬虫框架,它提供了一些简单的Web抓取接口,您可以在不到5分钟的时间内设置一个多线程Web爬虫。

<dependency>
    <groupId>cn.edu.hfut.dmic.webcollector</groupId>
    <artifactId>WebCollector</artifactId>
    <version>2.73-alpha</version>
</dependency>

3.入门案列

package com.example.jsoup;


import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler;

import java.io.*;

public class RediffCrawler extends BreadthCrawler {

    private static StringBuilder sb = new StringBuilder();
    private static String fileName;
    private static String code;

    public RediffCrawler(String crawlPath, boolean autoParse, String filenName, String cod) {
        super(crawlPath, autoParse);
        //添加种子URL
        this.addSeed("https://www.*****.com");
        this.addSeed("https://www.*****.com/business");
        /**
         * URL访问规则添加
         * 以“https://www.xxxxxx.com/为前缀 ,以tml为后缀
         */
        this.addRegex("^(https://www.*****.com/).*(\\.tml)$");
        this.addSeed("-.*\\.(jpg|png|gif|css|js|mid|mp4|wav|mpeg|ram|m4v|pdf)$");
        /**
         * 输出文件配置
         * 文件名及文件编码
         */
        fileName = filenName;
        code = cod;

    }
    @Override
    public void visit(Page page, CrawlDatums next) {
         String url = page.url();
         //种子URL不符合条件 这里过滤掉
        if(page.matchUrl("^(https://www.*****.com/).*(\\.tml)$")){
            /**
             * 使用jsoup解析数据
             */
            String title =page.select("#leftcontainer>h1").text();
            String content=page.select("#arti_cintent_n").text();
            sb.append("URL:\t"+url+"\n"+"title:\t"+title+"\ncontent:\t"+content+"\n\n");
        }
        try {
            writeFile(fileName, sb.toString(), code);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *  数据写人指定文档
     * @param file 文件名
     * @param content (需要写入的内容)
     * @param code  (文件编码)
     */
    private void writeFile(String file, String content, String code) throws IOException {
        final File result = new File(file);
        final FileOutputStream out = new FileOutputStream(result, false);
        final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out, code));
        bw.write(content);
        bw.close();
        out.close();

    }

    public static void main(String[] args) throws Exception {
        final RediffCrawler crawler = new RediffCrawler("rediffNewCrawler",
                true, "data/rediffNews.txt", "uft-8");
        //设置线程数目
        crawler.setThreads(5);
        //设置每一层最多采集的页面数
        crawler.getConf().setTopN(300);
        //开始采集数据,设置采集的深度
        crawler.start(3);
    }
}

 

 在控制台会输出一系列日志信息。整个程序的执行时间为28秒,共采集271条新闻,采集到数据写入了项目“data/”目录下的文件“rediffNews.txt”,其内容如图9-9所示。相比Crawler4j,WebCollector采集数据的速度更快、效率更高。在执行的过程中,在项目的根目录下会自动创建文件夹“rediffNewsCrawler”,同时在该文件夹下还包含三个文件,分别是“crawldb”、“fetch”和“link”。这三个文件夹下存放的都是RocksDB数据库对应的文件,如图9.10所示。RocksDB是一种嵌入式的支持持久化的key-value存储系统,可以在控制台输出每个数据库中存储的key-value数据。其中,key为访问的URL;value为包含5个字段的JSON数据,即URL、状态status(三种取值为0、1、5,默认为0)、执行时间executeTime(UNIX时间戳-毫秒)、执行次数executeCount(默认值为0)、HTTP状态码(默认值为-1,表示未获取到状态码)和重定向地址(默认值为null,如果有重定向则保存重定向地址)。WebCollector的数据去重,依据的是RocksDB数据库中的key,如果没有设置key,程序会将URL当成key。

 

package com.example.jsoup;


import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksIterator;

public class RocksDBOpen {
    static {
        RocksDB.loadLibrary();
    }
    static RocksDB rocksDB;
    static String path="rediffNewsCrawler/crawldb";

    public static void main(String[] args) throws Exception {
        final Options options = new Options();
        options.setCreateIfMissing(true);
        //打开RocksDB
        rocksDB=RocksDB.open(options,path);
        RocksIterator iter = rocksDB.newIterator();
        for( iter.seekToFirst();iter.isValid();iter.next()){
            System.out.println("key:"+new String(iter.key())+",value:"+new String(iter.value()));
        }
        


    }
}

4.相关配置 

1.User-Agent

在cn.edu.hfut.dmic.webcollector.util包的Config类中,给出了User-Agent的默认值,即:

String user_agent = "\"Mozilla/5.0 (Windows NT 10.0; Win64; x64\" + \"AppleWebKit/537.36(KHTML, like chrome/\" +\n" +
                "                \"63.0.3239.108 Safari/537.36\"";
        crawler.getConf().setDefaultUserAgent(user_agent);

2. 请求时间间隔

为了礼貌地采集网站数据,Configuration类提供了setExecuteInterval ()方法来设置任意线程URL请求之间的时间间隔(默认值为0)。以下为配置程序。

crawler.getConf().setExecuteInterval(1000);

 3.超时时间

WebCollector提供了连接超时时间和获取数据超时时间的配置。在Config类中,连接超时时间的默认值为3秒,获取数据超时时间的默认值为10秒。配置这两种超时时间,可以使用Configuration类中的setConnectTimeout()和setReadTimeout()方法。

crawler.getConf().setConnectTimeout(10000);//连接超时
        crawler.getConf().setReadTimeout(200000);//获取数据超时

 4.最大重定向次数

在WebCollector中,最大重定向次数默认设置为2次。但使用者可以使用Configuration类中的setMaxRedirect()重新配置。

 crawler.getConf().setMaxRedirect(5);

 5.最大执行次数

使用Crawler类中setMaxExecuteCount()可以设置爬虫任务的最大执行次数。在数据采集任务中,请求URL和解析数据出错都有可能导致任务失败。当某个任务执行失败时,如果设置的最大执行次数超过1,那么该任务还会重新执行,直到达到最大执行次数。setMaxExecuteCount()方法的默认设置为-1,即任务失败不会重新执行,以下为该方法的使用方式。

  crawler.setMaxExecuteCount(2);

 6.断点爬取

WebCollector的一个重要特性便是支持断点采集。针对耗时较长和大规模数据采集的任务,经常会遇到一些意外情况(如断网、死机和断电等),导致程序中断。为了保证数据采集任务不受这些因素的影响,WebCollector框架中提供了断点配置方法——setResumable()方法,该方法的参数类型为boolean类型。默认情况下,setResumable()方法输入参数设置为false,即每次采集清空历史数据,不执行断点爬取。没有设置断点爬取,则每次启动任务“crawldb”、“fetch”和“link”三个数据库中的数据都会被清空。但如果程序的start()方法之前进行如下配置:

 crawler.setResumable(true);

再次执行程序后,同时使用后面的程序打开“crawldb”数据库,则会发现其原有的key-value数据依旧还在,并且添加了新的key-value数据。 

 5 .HTTP请求扩展

WebCollector 2.7版本默认使用cn.edu.hfut.dmic.webcollector.plugin.net包中的OkHttpRequester作为HTTP请求插件,但其提供的功能有限,为进一步扩展HTTP请求的功能(如设置HTTP请求头信息、设置代理、设置请求方法等),可继承OkHttpRequester类,复写其中的createRequestBuilder()方法。采集的数据仍是rediff.com中的新闻。相比入门案例,这里自定义了请求插件,即MyRequester,其继承了OkHttpRequester。并且,在复写的createRequestBuilder()方法中使用了addHeader()方法添加请求头信息。在构造方法HeaderAdd ()中,只要使用setRequester()方法配置自定义的MyRequester,便可以利用自定义的请求插件请求URL。

package com.example.jsoup.crawler;


import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.net.OkHttpRequester;
import cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler;
import okhttp3.Request;

import java.io.*;

public class HeaderAdd extends BreadthCrawler {

    private static StringBuilder sb = new StringBuilder();
    private static String fileName;
    private static String code;
    //自定义请求头
    public static class MyRequester extends OkHttpRequester{
        //每次发送请求前都会使用这个方法来构建请求
        @Override
        public Request.Builder createRequestBuilder(CrawlDatum crawlDatum) {
            //使用的是OkHttp中的Request.Builder
            return super.createRequestBuilder(crawlDatum)
                    .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64" + "AppleWebKit/537.36(KHTML, like chrome/" +
                            "63.0.3239.108 Safari/537.36");
        }
    }
    public HeaderAdd(String crawlPath, boolean autoParse,String filename,String cod) {
        super(crawlPath, autoParse);
        setRequester(new MyRequester());
        //添加种子URL
        this.addSeed("https://www.*****.com");
        this.addSeed("https://www.*****.com/business");
        /**
         * URL访问规则添加
         * 以“https://www.xxxxxx.com/为前缀 ,以tml为后缀
         */
        this.addRegex("^(https://www.*****.com/).*(\\.tml)$");
        this.addSeed("-.*\\.(jpg|png|gif|css|js|mid|mp4|wav|mpeg|ram|m4v|pdf)$");
        /**
         * 输出文件配置
         * 文件名及文件编码
         */
        fileName = filename;
        code = cod;

    }

    @Override
    public void visit(Page page, CrawlDatums crawlDatums) {
        String url = page.url();
        //种子URL不符合条件 这里过滤掉
        if (page.matchUrl("^(https://www.*****.com/).*(\\.tml)$")) {
            /**
             * 使用jsoup解析数据
             */
            String title = page.select("#leftcontainer>h1").text();
            String content = page.select("#arti_cintent_n").text();
            sb.append("URL:\t" + url + "\n" + "title:\t" + title + "\ncontent:\t" + content + "\n\n");
        }
        try {
            writeFile(fileName, sb.toString(), code);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 数据写人指定文档
     *
     * @param file    文件名
     * @param content (需要写入的内容)
     * @param code    (文件编码)
     */
    private void writeFile(String file, String content, String code) throws IOException {
        final File result = new File(file);
        final FileOutputStream out = new FileOutputStream(result, false);
        final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out, code));
        bw.write(content);
        bw.close();
        out.close();

    }

    public static void main(String[] args) throws Exception {
        final HeaderAdd crawler = new HeaderAdd("rediffNewCrawler_head",
                true, "data/rediffNews.txt", "uft-8");
        //设置线程数目
        crawler.setThreads(10);
        //设置每一层最多采集的页面数
        crawler.getConf().setTopN(300);
        crawler.getConf().setExecuteInterval(1000);
        //开始采集数据,设置采集的深度
        crawler.start(3);



    }
}

 另外,通过复写createRequestBuilder()方法,也可以实现表单数据的提交。

package com.example.jsoup.crawler;

import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.net.OkHttpRequester;
import cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;

/**
 *  提交表单数据
 */
public class PostRequestTest extends BreadthCrawler {

    /**
     * 构造一个基于RocksDB的爬虫
     * RocksDB文件夹为crawlPath,crawlPath中维护了历史URL等信息
     * 不同任务不要使用相同的crawlPath
     * 两个使用相同crawlPath的爬虫并行爬取会产生错误
     *
     * @param crawlPath RocksDB使用的文件夹
     * @param autoParse 是否根据设置的正则自动探测新URL
     */
    public PostRequestTest(String crawlPath, boolean autoParse) {
        super(crawlPath, autoParse);
        addSeed(new CrawlDatum("https://www.xxxx.com")
        .meta("username","张三")
        .meta("password","123456"));

        setRequester(new OkHttpRequester(){
            @Override
            public Request.Builder createRequestBuilder(CrawlDatum crawlDatum) {
               Request.Builder requestBuilder= super.createRequestBuilder(crawlDatum);
                RequestBody requestBody;
                String username = crawlDatum.meta("username");
                //如果没有表单数据
                if(username==null){
                    requestBody=RequestBody.create(null,new byte[]{});
                }else {
                    //根据meta创建请求体
                    requestBody=new MultipartBody.Builder()
                            .setType(MultipartBody.FORM)
                            .addFormDataPart("username",username)
                            .addFormDataPart("password",crawlDatum.meta("password")).build();
                }
                return requestBuilder.post(requestBody).header("Connection", "keep-alive");
            }
        });
    }

    @Override
    public void visit(Page page, CrawlDatums next) {
        String html= page.html();
        System.out.println("快递信息"+html);

    }

    public static void main(String[] args) throws Exception {
        final PostRequestTest crawler = new PostRequestTest("post_crawler", true);
        crawler.start(1);

    }
}

 构建HTTP请求插件使用的是OkHttp jar包中的Request类的内部类Builder。但这个Builder类只能用于配置请求方法(GET/POST)、请求头(添加/删除)和请求体等。如果要配置代理和超时时间等内容,则需要使用OkHttpClient类中的内部类Builder。下面简绍实现了HTTP请求的多代理随机切换模式。MyRequester类继承了OkHttpRequester类,但复写的是createOkHttpClientBuilder()方法。在该方法中,使用了OkHttpClient.Builder类中的proxySelector()添加代理。在采集的过程中,一些代理可能失效,导致URL请求失败,为此,在主方法中,设置了断点采集。

package com.example.jsoup.crawler;

import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.net.Proxies;
import cn.edu.hfut.dmic.webcollector.plugin.net.OkHttpRequester;
import cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler;
import okhttp3.OkHttpClient;


import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

//设置代理
public class ProxyUseTest extends BreadthCrawler {
    public static class MyRequester extends OkHttpRequester {
        Proxies proxies;

        public MyRequester() {
            proxies = new Proxies();
            proxies.addSocksProxy("127.0.0.1", 1080); //本机
            proxies.addSocksProxy("183.161.29.127", 8071);
            proxies.addSocksProxy("183.161.29.125", 8071);
            //直接连接,不使用代理
            proxies.add(null);
        }

        @Override
        public OkHttpClient.Builder createOkHttpClientBuilder() {
            return super.createOkHttpClientBuilder()
                    //设置一个代理选择器
                    .proxySelector(new ProxySelector() {
                        @Override
                        public List<Proxy> select(URI uri) {
                            //随机选择一个代理
                            Proxy randomProxy = proxies.randomProxy();
                            //放回值类型 需要为List
                            List<Proxy> randomProxies = new ArrayList<>();
                            //如果随机到Null ,即不要代理 返回空的list 即可
                            if (randomProxy != null) {
                                randomProxies.add(randomProxy);
                            }
                            System.out.println("使用的代理为:" + randomProxies);
                            return randomProxies;
                        }

                        @Override
                        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {

                        }
                    });
        }

    }


    /**
     * 构造一个基于RocksDB的爬虫
     * RocksDB文件夹为crawlPath,crawlPath中维护了历史URL等信息
     * 不同任务不要使用相同的crawlPath
     * 两个使用相同crawlPath的爬虫并行爬取会产生错误
     *
     * @param crawlPath RocksDB使用的文件夹
     *
     */
    public ProxyUseTest(String crawlPath) {
        super(crawlPath, true);
        //设置请求插件
        setRequester(new HeaderAdd.MyRequester());
        this.addSeed("https://www.xxxx.com");
        this.addRegex("^(https://www.*****.com/).*(\\.tml)$");

    }
    /**
     * @param page 当前访问页面的信息
     
     */
    @Override
    public void visit(Page page, CrawlDatums crawlDatums) {
        if(page.matchUrl("^(https://www.xxxx.com/).*(\\.htm)$")){
            String title = page.select("#leftcontainer>h1").text();
        }
    }

    public static void main(String[] args) throws Exception {
        final ProxyUseTest crawler = new ProxyUseTest("crawl_proxy_rediff");
        //设置线程数
        crawler.setThreads(3);
        //防止有些代理不可用,下次启动可以使用其他代理继续请求
        crawler.setResumable(false);
        //请求间隔时间
        crawler.getConf().setExecuteInterval(10000);
        //设置每一层最多采集的页面数
        crawler.getConf().setTopN(100);
        crawler.start(3);
        
    }
}

6.翻页数据采集

在对有分页的网页,进行操作

 

package com.example.jsoup.crawler;


import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.ram.RamCrawler;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;

/**
 * 基于内存的Crawler插件,适合一次性爬取,并不具有断点爬取功能
 * 长期任务请使用BreadthCrawler
 * 你也可以继续使用前面的BreadthCrawler爬虫
 *
 * @author hu
 */
public class HFUTNewsCrawler extends RamCrawler {
    String fileFirstLayerOutPut = "data/hfut_newUrl.txt";
    String contentOutPut = "data/hfut_newsContent.txt";
    String code = "utf-8";
    StringBuilder sb_first = new StringBuilder();
    StringBuilder sb_content = new StringBuilder();

    public HFUTNewsCrawler(int pageNum) throws Exception {
        //添加多页
        for (int pageIndex=1; pageIndex<=pageNum;pageIndex++){
            String url = "www.adffsafa.com";
            final CrawlDatum datums = new CrawlDatum(url)
                    .type("firstLayer")      //第一层
                    .meta("pageIndex", pageIndex)     //页面保护
                    .meta("depth", 1);        //深度为第一层

            this.addSeed(datums);

        }
    }

    @Override
    public void visit(Page page, CrawlDatums next) {
        int pageIndex = page.metaAsInt("pageIndex");
        int depth = page.metaAsInt("depth");
        if(page.matchType("firstLayer")){
            //解析新闻标题页
          Elements results=  page.select("div.col-lg-8 >u1").select("li");
          for (int rank=0;rank<results.size();rank++){
              final Element result = results.get(rank);
              String href = "https://www.xxxx.com" + result.select("a").attr("href");
              String title=result.select("span[class=rt]").text();
              if(title.length()!=0){
                  //输出第一层信息
                  sb_first.append("url:"+href);
                  try {
                      writeFile(fileFirstLayerOutPut, sb_first.toString(), code);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                  /**
                   * 添加需要访问的新闻连接 ,类型为content
                   * 用于爬取新闻的详细内容
                   */
                  //将该URL添加到CrawlDatum做为要采集的URL
                  next.addAndReturn(href)
                          .type("content")     //页面内容
                          .meta("pageIndex",pageIndex)          //第几页的新闻
                          .meta("rank",rank);     //这条新闻的序号
              }
              
          }
        }
        //新闻详情页
        if(page.matchType("content")){
            //输出结果
            String url= page.url();
            int index = page.metaAsInt("pageIndex");//新闻在第几页
            int rank = page.metaAsInt("rank");  //新闻在页面的序号
            String content=page.select("div[id=artibody]").text();
            //输出第二层信息
            sb_content.append("url:" + url);
            try {
                writeFile(contentOutPut,sb_content.toString(),code);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * 页面的深度 +1
         * 新闻的详情页
         */
        next.meta("depth",depth+1);


    }

    /**
     * 数据写人指定文档
     *
     * @param file    文件名
     * @param content (需要写入的内容)
     * @param code    (文件编码)
     */
    private void writeFile(String file, String content, String code) throws IOException {
        final File result = new File(file);
        final FileOutputStream out = new FileOutputStream(result, false);
        final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out, code));
        bw.write(content);
        bw.close();
        out.close();

    }

    public static void main(String[] args) throws Exception {
        final HFUTNewsCrawler crawler = new HFUTNewsCrawler(3);
        crawler.setThreads(10);
        crawler.start(); //启动程序
    }
}

 

 

 

 

 

 

 

 

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

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

相关文章

Labelme分割标注的使用(非常好)

博客转自于: Labelme分割标注软件使用 1. Labelme的使用 这里建议大家按照我提供的目录格式事先准备好数据&#xff0c;然后在该根目录下启动labelme&#xff08;注意启动目录位子&#xff0c;因为标注json文件中存储的图片路径都是以该目录作为相对路径的&#xff09; ├─…

Live800:降低客服成本,你必须了解的事

无论是售前咨询还是售后服务&#xff0c;咨询客服都是客户的“必经之路”&#xff0c;因此客服又被称为企业形象的“代言”、品牌美誉的“前台”、企业文化的一面“镜子”。 然而网友关于客服的吐槽&#xff0c;我们不时可以见到&#xff0c;有的客服答非所问&#xff0c;对产品…

一次明白 JDBC,ORM,JPA,SpringDataJPA 之间的关系

java持久层框架访问数据库一般有两种方式&#xff1a; 以SQL为核心&#xff0c;封装JDBC操作&#xff0c;如&#xff1a;MyBatis以java实体类为核心&#xff0c;将实体类和数据库表之间映射的ORM框架&#xff0c;比如&#xff1a;Spring Data JPA和Hibernate 接下来就是详细的…

blender指定地图影像数据作为背景

qgis导出一个层刚好温和 然后 切换到shading 默认只有表面化 bsdf 点击添加 图片纹理 选择图片&#xff0c;然后把那个颜色拦截到基础色就ok了&#xff0c;操作方法和ue类似 image.pnguv editing必须进入编辑模式 方可操作&#xff0c;如果要刚好铺满整个框&#xff0c;要开启那…

Django 学习 Day10

1.聚合查询 聚合查询是指对一个数据表中的一个字段的数据进行部分或全部的统计查询。差Book数据表中的全部书的平均价格、查询所有书的总数等都需要使用聚合查询。 聚合查询分为&#xff1a; &#xff08;1&#xff09;整表聚合 聚合函数的导入&#xff1a; from django.db.…

Qt QFileSystemModel类详解

文章目录一.QFileSystemModel类属性信号函数二.使用说明一.QFileSystemModel类 属性 nameFilterDisables : bool 此属性保存未通过名称筛选器的文件是隐藏还是禁用&#xff0c;默认值为trueoptions : Options 此属性包含影响模型的各种选项&#xff0c;默认情况下&#xff0c…

索引排序内部流程

select 查询字段是不是索引覆盖&#xff0c;覆盖到了就直接内存中排序&#xff0c;输出结果&#xff0c; 如果索引没有覆盖查询字段&#xff0c;计算select的字段释放超过单行所有字段总和限制&#xff0c;超过限制就进行双路排序&#xff0c;否则就使用单路排序 双路排序&…

裂缝波导天线

1. 裂缝波导天线波导裂缝天线属于阵列天线&#xff0c;如图1-1所示&#xff0c;在一根波导上开一系列裂缝可构成线阵天线&#xff0c;三种波导裂缝线阵&#xff08;两种在宽边&#xff0c;一种在窄边&#xff09;通过控制裂缝的偏置或倾角实现所要求的口径幅度分布。图1-1 波导…

钉钉的想象力,向企业服务第一平台进阶

作者 | 曾响铃 文 | 响铃说 时近年末&#xff0c;钉钉7.0版本在杭州重磅发布。 两年一个大版本&#xff0c;这一次钉钉正试图向更高的维度进化&#xff1a; 第一&#xff0c;在完成一家企业的组织数字化和业务数字化后&#xff0c;钉钉开始将重点突破到企业间&#xff0c;突…

如何获取完整、准确的用户需求?

1、成立专业且全面的综合项目组 想要获取完整且准确的用户需求&#xff0c;首先需要成立由技术人员、业务人员、测试人员等组成的项目组&#xff0c;项目组成员最好既懂技术又懂业务。这样的综合项目组有助于全面获取用户需求。 如何获取完整、准确的用户需求&#xff1a;专业全…

模拟前端的开关器件隔离度分析与优化

1、模拟开关的隔离程度 下图为一个模拟开关在 SiPM接收切换中的应用电路。 V1点的波形输入的信号下降沿为500ps&#xff0c;上升沿为10ns&#xff0c;波形如下图所示。 V2点的波形如下图所示&#xff0c;此时IN为低&#xff0c;应该是S1导通&#xff0c;S2断开的&#xff0c;此…

Unity 3D 导入资源包 || Unity 3D 导出资源包

项目中的一些资源具有复用性&#xff0c;只需要将资源导出&#xff0c;就能够重复使用。 导出资源包 执行 Assets → Select Dependencies 菜单命令&#xff0c;选中与导出资源相关的内容。接着执行 Assets→ Export Package 菜单命令。弹出的 Exporting Package 导出资源对话框…

大数据NiFi(一):什么是NiFi

文章目录 什么是NiFi 一、NiFi背景介绍

第5章 函数

&#x1f31e;欢迎来到机器学习的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f320;本阶段属于练气阶段&#xff0c;希望各位仙友顺利完…

软件测试复习

软件测试定义 什么是软件测试 使用人工或自动手段运行或测定某个系统的过程&#xff0c;其目的在于检验它是否满足规定的需求或是弄清预期结果与实际结果之间的差别。软件测试就是“验证”和“确认”活动构成的整体。 软件测试的作用 验证软件需求和功能是否得到完整实现验证软…

花房集团成功上市,构建互联互通的在线社交娱乐生态

近日&#xff0c;花房集团正式在香港联合交易所主板上市。对于花房集团而言&#xff0c;登陆港股市场是新的征程、新的起点。 可以看到&#xff0c;花房集团在稳固“直播社交”业务基本盘的同时&#xff0c;持续探索元宇宙领域&#xff0c;上市当日首次发布了最新的战略方向“娱…

Apriori算法的python实现

文章目录函数介绍实例Step1:整理数据Step2:挖掘频繁项集Step3:挖掘关联规则Step4:进一步筛选规则作者&#xff1a;李雪茸函数介绍 实现Apriori关联规则挖掘是借助mlxtend第三方包&#xff0c;使用步骤如下&#xff1a; 1、调用apriori算法挖掘频繁项集&#xff0c;apriori()中…

十一、通过程序向闪存文件系统写入信息

1、闪存 (1)每一个esp8266都配有一个闪存&#xff0c;闪存就类似于一个小硬盘。 (2)我们编译上传的程序就存储在闪存中。 (3)闪存的全称是Serial Peripheral Interface Flash File System&#xff08;SPIFFS&#xff09;&#xff0c;串行外设接口Flash文件系统。 (4)闪存除…

docker高级篇-docker-compose容器编排介绍及实战

Docker-compose是什么?能干嘛?解决了哪些痛点? 是什么? Docker-compose是Docker官方推出 的一个工具软件,可以管理多个Docker容器组成的一个应用。你需要编写一个一个YAML格式的配置文件:docker-compose.yml。写好多个容器之间的调用关系。然后,只需要一个命令,就能…

嵌入式:ARM汇编语言程序设计基础教程

文章目录汇编语言程序设计的步骤顺序程序设计分支程序设计循环程序设计子程序设计寄存器传递参数方式存储区域传递参数方式堆栈传递参数方式汇编语言程序设计的步骤 ① 合理地分配存储器资源&#xff0c;将前述的目标系统‘数据结构模型’表示到各存储器单元。 ② CPU寄存器数…