SpringBoot项目通过WebCollector + @Scheduled实现定时爬取网站任务

SpringBoot项目通过WebCollector + @Scheduled实现定时爬取网站任务

一、编写网站爬取程序

1、继承BreadthCrawler类

继承BreadthCrawler类

2、根据自己的需求写构造方法

如:我写的这个无参构造方法,其中super的第一个参数是爬取过程中产生的文件夹路径(文件夹中的文件主要是维护爬取过程中的URL等信息),第二个参数是指是否根据设置的正则表达式自动探取新的URL。添加正则表达式的方法addRegex(String urlRegex),参数为一个 url 正则表达式,可以用于过滤不必抓取的链接,如 .js .jpg .css … 等,也可用于抓取指定某些规则的链接,如:

addRegex("https://www.bilibili.com/video/BV1Kt411g7Sq?p=/[0-9]{2}[^/]");
	public ProcurementCrawler() {
        super("./crawPath", false);
        /**设置爬取的网站,其中后面的参数指定该URL的类型
        *如:爬取一个网站的所有公告,最开始爬取的便是公告列表的第一页
        *第一页中有公告详情URL,就需要将详情URL添加到爬取任务中
        *就可以通过后面的那个字符串参数来分辨爬取的URL是公告列表还是公告详情页
        */
        addSeed(send + noticePage,"noticeList");

        //设置线程数
        setThreads(2);
    }

3、覆写visit方法

visit中有两个参数(Page,CrawlDatums)
Page是爬取过程中,内存中保存网页爬取信息的一个容器,Page只在内存中存 放,用于保存一些网页信息,方便用户进行自定义网页解析之类的操作
CrawlDatums是存放爬取任务的集合,底层实现是LinkedList

	@Override
    public void visit(Page page, CrawlDatums crawlDatums) {
		//区分爬取的URL是公告列表还是公告详情页
        if(page.matchType("noticeList")){
        	/**
        	*获取公告列表中的公告详情页的URL,其中select方法中的字符串代表的是
        	*代码所示的意思是抓取class为info的div下的ul的li的a标签
        	*/
            Elements elements = page.select("div.info>ul>li>a");
            if(elements != null){
                for(Element element : elements){
                    String href = element.attributes().get("href");
                    	//将详情页URL添加到crawlDatums中
                        crawlDatums.add(href,"noticeDetails");
                }
                //当本页还有数据就将下一页列表的URL添加进去
                crawlDatums.add(send + ++noticePage,"noticeList");
            }
        }else if(page.matchType("noticeDetails")) {
        	//如果是详情页就将数据存入数据库中
            try {
                Notice notice = new Notice();
                notice.setId(UUID.randomUUID().toString());
                
                //获取公告发布时间,若公告时间比上次爬取的时间早,return结束该URL爬取
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                String uploadDate = page.select("div.cont-info>p").first().text().split(":")[1];
                if(lastDate != null) {
                    if (sdf.parse(uploadDate).before(lastDate)) {
                        return;
                    }
                }
                notice.setUploadDate(sdf.parse(uploadDate));

                String title = page.select("div.cont-info>h1").first().text();
                notice.setTitle(title);

                String url = page.url();
                notice.setUrl(url);

                String content = page.select("div.cont-info>div.tableBox").first().text();
                notice.setContent(content);
                noticeCrawlerDao.insert(notice);
            } catch (ParseException e) {
                log.error("", e);
            }
        }
    }

4、写main方法测试爬取程序

//这里的异常其实需要处理,我是为了省事
	public static void main(String[] args) throws Exception {
        ProcurementCrawler crawler = new ProcurementCrawler();
        /**
        *lastDate是我在爬取程序中定义的一个属性并写了set方法
        *protected static Date lastDate = null;
        */
        crawler.setLastDate(null);
        /**
        *20代表爬取深度
        *1爬取深度代表爬取完第一个爬取URL本身和你添加在CrawlDatums的爬取任务
        *下一个爬取深度就是爬取你上一深度中添加在CrawlDatums中的URL
        *类似树的层次遍历
        */
        crawler.start(20);
    }

二、编写定时任务

可以写在@Service或@Component注解的类中

1、在类上添加@EnableScheduling注解

这个注解主要作用是向SchedulingConfiguration注册

2、定时任务启动爬取程序

//在每天凌晨两点钟定时爬取公告数据
	@Scheduled(cron = "0 0 2 * * ?")
    public void noticeCrawler() throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //从数据库中查上次爬取的时间
        String timeStr = dao.getLastDate();
        Date lastDate = dateFormat.parse(timeStr.substring(0,18) + "1");
        crawler.setLastDate(lastDate);
        try {
            crawler.start(30);
        } catch (Exception e) {
            log.error("",e);
        }
    }

3、@Scheduled定时任务时间设置

主要讲述3种常用的时间设置方式

(1)cron

一个cron表达式有至少6个(也可能7个)由空格分隔的时间元素,项目中大多写在配置文件中,通过@Scheduled(cron="${key}")来获取
依次是:[秒] [分] [小时] [日] [月] [周] [年](可省略年)
cron表达式
*表示所有值
?表示不指定值
,表示多值,如在秒上1,30表示1秒和30秒的时候都触发
-表示区间,如在时上10-12表示10、11、12都会触发
/表示递增,如在时上0/12表示晚上零点和中午十二点触发

(2)fixedDelay

例:@Scheduled(fixedDelay = 5000)
表示上一次执行完成后多久再次执行,单位是毫秒
每个两小时执行一次
@Scheduled(fixedDelay = 2 * 60 * 60 * 1000)

(3)fixedDelayString

与fixedDelay意思相同,只是使用字符串的形式,唯一不同的是支持占位符
如:@Scheduled(fixedDelayString="${time.cron}")

所以大多数使用(1)、(3)两种设置方式

总结

内容并不难主要是再visit方法的覆写上难
更多WebCollector教程链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要 Caffeine 和 `@Cacheable` 注解实现定时刷新缓存,可以按照以下步骤进行操作: 1. 添加 Caffeine 依赖:在项目的 `pom.xml` 文件中添加 Caffeine 依赖。 ```xml <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.9.0</version> </dependency> ``` 2. 创建缓存配置:在 Spring Boot 的配置类中创建一个缓存配置类,配置 Caffeine 缓存。 ```java import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.caffeine.CaffeineCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.TimeUnit; @Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager("myCache"); cacheManager.setCaffeine(caffeineCacheBuilder()); return cacheManager; } Caffeine<Object, Object> caffeineCacheBuilder() { return Caffeine.newBuilder() .expireAfterWrite(1, TimeUnit.HOURS) // 缓存项写入后过期时间 .refreshAfterWrite(30, TimeUnit.MINUTES) // 缓存项刷新时间 .maximumSize(100) // 缓存最大大小 .weakKeys() // 弱引用键 .recordStats(); // 记录统计信息 } } ``` 3. 使用 `@Cacheable` 注解:在需要进行缓存的方法上使用 `@Cacheable` 注解,并指定缓存的名称。 ```java import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service public class MyService { @Cacheable(cacheNames = "myCache") public String getData(String key) { // 从数据库或其他数据源获取数据 return "data"; } } ``` 4. 定时刷新缓存:使用 Spring 的定时任务功能,定时调用需要刷新缓存的方法。 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class CacheScheduler { private final CacheManager cacheManager; private final MyService myService; @Autowired public CacheScheduler(CacheManager cacheManager, MyService myService) { this.cacheManager = cacheManager; this.myService = myService; } @Scheduled(fixedRate = 30 * 60 * 1000) // 每30分钟执行一次 public void refreshCache() { cacheManager.getCache("myCache").clear(); myService.getData("key"); // 触发缓存的重新加载 } } ``` 以上步骤将使用 Caffeine 缓存和 `@Cacheable` 注解实现缓存的定时刷新。在每次定时任务执行时,会清空缓存并重新加载数据。请根据自己的需求进行适当调整和配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值