前面基本上實現了一個很是簡陋的爬蟲框架模型,不少關鍵鏈路都沒有日誌,在分析問題時,就比較麻煩了,所以就有了這一篇博文html
其次就是解決前幾篇遺留的容易解決的問題java
實際上,日誌的輸出應該貫穿在實際的開發過程當中的,因爲以前寫得比較隨意,直接System.out
了, 因此如今就來填坑了git
採用 logback 左右日誌輸出, 這裏有一篇博文可供參考 《Logback 簡明使用手冊》github
埋點的關鍵鏈路編程
實現比較簡單,在pom中添加依賴api
<!--日誌--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.7</version> </dependency>
添加配置文件微信
logback-test.xmlapp
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern> </encoder> </appender> <logger name="com.quick.hui.crawler" level="DEBUG"/> <root level="INFO"> <appender-ref ref="STDOUT"/> </root> </configuration>
代碼中埋點框架
.... (直接參考源碼便可)工具
不少網站會對訪問的頻率進行限制,這是一個最基礎的防爬手段了,因此咱們的爬取須要一個能夠設置爬取任務的頻率控制
目的
方案
採用配置項來解決這個,(爲了後續的拓展,讀取配置搞成面向接口的編程方式),咱們先提供一個基礎的,根據本地配置文件來讀取頻率控制參數
實現
由於採用配置文件的方式,因此一個用於讀取配置文件的輔助工具類是必須的
FileConfRead
@Slf4j public class FileConfRead implements IConfRead { public Config initConf(String path) { try { Properties properties = read(path); Config config = new Config(); config.setSleep(properties.getProperty("sleep"), 0); config.setEmptyQueueWaitTime(properties.getProperty("emptyQueueWaitTime"), 200); return config; } catch (Exception e) { log.error("init config from file: {} error! e: {}", path, e); return new Config(); } } private Properties read(String fileName) throws IOException { try (InputStream inputStream = FileReadUtil.getStreamByFileName(fileName)) { Properties pro = new Properties(); pro.load(inputStream); return pro; } } private File file; private long lastTime; public void registerCheckTask(final String path) { try { file = FileReadUtil.getFile(path); lastTime = file.lastModified(); ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); scheduledExecutorService.scheduleAtFixedRate(() -> { if (file.lastModified() > lastTime) { lastTime = file.lastModified(); ConfigWrapper.getInstance().post(new ConfigWrapper.UpdateConfEvent()); } }, 1, 1, TimeUnit.MINUTES); } catch (Exception e) { throw new RuntimeException(e); } } }
實現類主要繼承接口 IConfRead
, 接口中定義了兩個方法,一個用於獲取配置信息,一個用於註冊配置信息的變更監聽事件
public interface IConfRead { /** * 初始化配置信息 * * @param var * @return */ Config initConf(String var); /** * 註冊配置信息更新檢測任務 * * @param path */ void registerCheckTask(final String path); }
回到具體的實現,讀取配置文件信息比較簡單,直接使用jdk的Properties文件的讀寫方式,接下來則是註冊監聽事件的實現上,咱們的設計思路以下:
Config
這裏定義全部的配置信息,方便後續的維護和查閱
@Getter @Setter @ToString public class Config { /** * 爬取任務的間隔時間 */ private long sleep; /** * 從隊列中獲取任務,返回空時,等待時間以後再進行重試 */ private long emptyQueueWaitTime; public void setSleep(String str, long sleep) { this.sleep = NumUtils.str2long(str, sleep); } public void setEmptyQueueWaitTime(String str, long emptyQueueWaitTime) { this.emptyQueueWaitTime = NumUtils.str2long(str, emptyQueueWaitTime); } }
ConfigWrapper
這裏封裝了獲取配置信息的接口,內部維護配置信息的變動事件,咱們採用EventBus來實現事件的監聽
@Slf4j public class ConfigWrapper { private static final String CONFIG_PATH = "conf/crawler.properties"; private EventBus eventBus; private IConfRead confRead; private Config config; private static volatile ConfigWrapper instance; private ConfigWrapper() { confRead = new FileConfRead(); confRead.registerCheckTask(CONFIG_PATH); config = confRead.initConf(CONFIG_PATH); // 註冊監聽器 eventBus = new EventBus(); eventBus.register(this); } public static ConfigWrapper getInstance() { if (instance == null) { synchronized (ConfigWrapper.class) { if (instance == null) { instance = new ConfigWrapper(); } } } return instance; } @Subscribe public void init(UpdateConfEvent event) { config = confRead.initConf(event.conf); if (log.isDebugEnabled()) { log.debug("time:{} processor:{} update config! new config is: {}", event.now, event.operator, config); } } public Config getConfig() { return config; } public void post(Object event) { eventBus.post(event); } @Getter @Setter public static class UpdateConfEvent { private long now = System.currentTimeMillis(); private String operator = "System"; private String conf = CONFIG_PATH; } }
項目地址: https://github.com/liuyueyi/quick-crawler
日誌埋點對應的tag: v0.006
動態配置對應的tag: v0.007