43 changed files with 694 additions and 0 deletions
@ -0,0 +1,43 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<groupId>com.example</groupId> |
|||
<artifactId>datacollect</artifactId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>11</maven.compiler.source> |
|||
<maven.compiler.target>11</maven.compiler.target> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>org.jsoup</groupId> |
|||
<artifactId>jsoup</artifactId> |
|||
<version>1.15.3</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-classic</artifactId> |
|||
<version>1.4.8</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<version>3.8.1</version> |
|||
<configuration> |
|||
<source>11</source> |
|||
<target>11</target> |
|||
</configuration> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
</project> |
|||
@ -0,0 +1,23 @@ |
|||
package com.example.datacollect; |
|||
|
|||
import com.example.datacollect.controller.CrawlerController; |
|||
import com.example.datacollect.repository.ArticleRepository; |
|||
import com.example.datacollect.service.CrawlerService; |
|||
import com.example.datacollect.strategy.StrategyFactory; |
|||
import com.example.datacollect.view.ConsoleView; |
|||
|
|||
public class Main { |
|||
|
|||
public static void main(String[] args) { |
|||
ConsoleView view = new ConsoleView(); |
|||
ArticleRepository repository = new ArticleRepository(); |
|||
StrategyFactory strategyFactory = new StrategyFactory(); |
|||
CrawlerService service = new CrawlerService(repository, strategyFactory); |
|||
CrawlerController controller = new CrawlerController(view, service); |
|||
|
|||
view.printSuccess("Welcome to CLI Crawler (w11)! Type help for commands."); |
|||
while (true) { |
|||
controller.handle(view.readLine()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
package com.example.datacollect.command; |
|||
|
|||
public interface Command { |
|||
String getName(); |
|||
void execute(String[] args); |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
package com.example.datacollect.command; |
|||
|
|||
import com.example.datacollect.model.Article; |
|||
import com.example.datacollect.service.CrawlerService; |
|||
import com.example.datacollect.view.ConsoleView; |
|||
import java.util.List; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class CrawlCommand implements Command { |
|||
private static final Logger logger = LoggerFactory.getLogger(CrawlCommand.class); |
|||
private final ConsoleView view; |
|||
private final CrawlerService service; |
|||
|
|||
public CrawlCommand(ConsoleView view, CrawlerService service) { |
|||
this.view = view; |
|||
this.service = service; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "crawl"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args) { |
|||
if (args.length < 2) { |
|||
view.printError("Usage: crawl <url>"); |
|||
return; |
|||
} |
|||
String url = args[1]; |
|||
|
|||
try { |
|||
view.printInfo("Crawling: " + url); |
|||
List<Article> articles = service.crawl(url); |
|||
view.printSuccess("Crawled " + articles.size() + " articles."); |
|||
} catch (IllegalArgumentException e) { |
|||
view.printError(e.getMessage()); |
|||
} catch (RuntimeException e) { |
|||
view.printError(e.getMessage()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package com.example.datacollect.command; |
|||
|
|||
import com.example.datacollect.view.ConsoleView; |
|||
|
|||
public class ExitCommand implements Command { |
|||
private final ConsoleView view; |
|||
|
|||
public ExitCommand(ConsoleView view) { |
|||
this.view = view; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "exit"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args) { |
|||
view.printSuccess("Bye!"); |
|||
System.exit(0); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package com.example.datacollect.command; |
|||
|
|||
import com.example.datacollect.view.ConsoleView; |
|||
|
|||
public class HelpCommand implements Command { |
|||
private final ConsoleView view; |
|||
|
|||
public HelpCommand(ConsoleView view) { |
|||
this.view = view; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "help"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args) { |
|||
view.printInfo("Commands: crawl <url>, list, help, exit"); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
package com.example.datacollect.command; |
|||
|
|||
import com.example.datacollect.service.CrawlerService; |
|||
import com.example.datacollect.view.ConsoleView; |
|||
|
|||
public class ListCommand implements Command { |
|||
private final ConsoleView view; |
|||
private final CrawlerService service; |
|||
|
|||
public ListCommand(ConsoleView view, CrawlerService service) { |
|||
this.view = view; |
|||
this.service = service; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "list"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args) { |
|||
view.display(service.getAllArticles()); |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
package com.example.datacollect.controller; |
|||
|
|||
import com.example.datacollect.command.Command; |
|||
import com.example.datacollect.command.CrawlCommand; |
|||
import com.example.datacollect.command.ExitCommand; |
|||
import com.example.datacollect.command.HelpCommand; |
|||
import com.example.datacollect.command.ListCommand; |
|||
import com.example.datacollect.service.CrawlerService; |
|||
import com.example.datacollect.view.ConsoleView; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class CrawlerController { |
|||
private static final Logger logger = LoggerFactory.getLogger(CrawlerController.class); |
|||
private final Map<String, Command> commands = new HashMap<>(); |
|||
private final ConsoleView view; |
|||
|
|||
public CrawlerController(ConsoleView view, CrawlerService service) { |
|||
this.view = view; |
|||
register(new HelpCommand(view)); |
|||
register(new ListCommand(view, service)); |
|||
register(new CrawlCommand(view, service)); |
|||
register(new ExitCommand(view)); |
|||
} |
|||
|
|||
private void register(Command command) { |
|||
commands.put(command.getName(), command); |
|||
} |
|||
|
|||
public void handle(String input) { |
|||
String text = input == null ? "" : input.trim(); |
|||
if (text.isEmpty()) { |
|||
return; |
|||
} |
|||
|
|||
String[] args = text.split("\\s+"); |
|||
String cmdName = args[0].toLowerCase(); |
|||
logger.info("Received command: {}", cmdName); |
|||
|
|||
Command command = commands.get(cmdName); |
|||
if (command == null) { |
|||
logger.warn("Unknown command: {}", cmdName); |
|||
view.printError("Unknown command: " + cmdName); |
|||
return; |
|||
} |
|||
command.execute(args); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
package com.example.datacollect.exception; |
|||
|
|||
public class CrawlerException extends RuntimeException { |
|||
public CrawlerException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
public CrawlerException(String message, Throwable cause) { |
|||
super(message, cause); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
package com.example.datacollect.exception; |
|||
|
|||
public class NetworkException extends CrawlerException { |
|||
public NetworkException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
public NetworkException(String message, Throwable cause) { |
|||
super(message, cause); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
package com.example.datacollect.exception; |
|||
|
|||
public class ParseException extends CrawlerException { |
|||
public ParseException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
public ParseException(String message, Throwable cause) { |
|||
super(message, cause); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
package com.example.datacollect.model; |
|||
|
|||
public class Article { |
|||
private final String title; |
|||
private final String url; |
|||
private final String content; |
|||
|
|||
public Article(String title, String url, String content) { |
|||
this.title = title; |
|||
this.url = url; |
|||
this.content = content; |
|||
} |
|||
|
|||
public String getTitle() { |
|||
return title; |
|||
} |
|||
|
|||
public String getUrl() { |
|||
return url; |
|||
} |
|||
|
|||
public String getContent() { |
|||
return content; |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
package com.example.datacollect.repository; |
|||
|
|||
import com.example.datacollect.model.Article; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class ArticleRepository { |
|||
private static final Logger logger = LoggerFactory.getLogger(ArticleRepository.class); |
|||
private final List<Article> articles = new ArrayList<>(); |
|||
|
|||
public void add(Article article) { |
|||
if (article == null) { |
|||
logger.warn("Attempt to add null article"); |
|||
throw new IllegalArgumentException("Article cannot be null"); |
|||
} |
|||
if (article.getTitle() == null || article.getTitle().trim().isEmpty()) { |
|||
logger.warn("Attempt to add article with empty title"); |
|||
throw new IllegalArgumentException("Article title cannot be empty"); |
|||
} |
|||
articles.add(article); |
|||
logger.debug("Added article: {}", article.getTitle()); |
|||
} |
|||
|
|||
public List<Article> getAll() { |
|||
return new ArrayList<>(articles); |
|||
} |
|||
|
|||
public void clear() { |
|||
int count = articles.size(); |
|||
articles.clear(); |
|||
logger.info("Cleared {} articles", count); |
|||
} |
|||
|
|||
public int size() { |
|||
return articles.size(); |
|||
} |
|||
|
|||
public Article get(int index) { |
|||
if (index < 0 || index >= articles.size()) { |
|||
logger.warn("Invalid index: {} (size: {})", index, articles.size()); |
|||
throw new IndexOutOfBoundsException("Index out of bounds: " + index); |
|||
} |
|||
return articles.get(index); |
|||
} |
|||
|
|||
public boolean contains(Article article) { |
|||
if (article == null) { |
|||
return false; |
|||
} |
|||
return articles.contains(article); |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
package com.example.datacollect.service; |
|||
|
|||
import com.example.datacollect.exception.CrawlerException; |
|||
import com.example.datacollect.exception.NetworkException; |
|||
import com.example.datacollect.exception.ParseException; |
|||
import com.example.datacollect.model.Article; |
|||
import com.example.datacollect.repository.ArticleRepository; |
|||
import com.example.datacollect.strategy.CrawlStrategy; |
|||
import com.example.datacollect.strategy.StrategyFactory; |
|||
import java.util.List; |
|||
import org.jsoup.Jsoup; |
|||
import org.jsoup.nodes.Document; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class CrawlerService { |
|||
private static final Logger logger = LoggerFactory.getLogger(CrawlerService.class); |
|||
private static final int MAX_RETRY = 3; |
|||
private static final long RETRY_DELAY_MS = 1000; |
|||
|
|||
private final ArticleRepository repository; |
|||
private final StrategyFactory strategyFactory; |
|||
|
|||
public CrawlerService(ArticleRepository repository, StrategyFactory strategyFactory) { |
|||
this.repository = repository; |
|||
this.strategyFactory = strategyFactory; |
|||
} |
|||
|
|||
public List<Article> crawl(String url) { |
|||
CrawlStrategy strategy = strategyFactory.getStrategy(url); |
|||
if (strategy == null) { |
|||
logger.warn("No strategy found for URL: {}", url); |
|||
throw new CrawlerException("No strategy found for: " + url); |
|||
} |
|||
|
|||
int retryCount = 0; |
|||
Exception lastException = null; |
|||
|
|||
while (retryCount < MAX_RETRY) { |
|||
try { |
|||
logger.info("Crawling URL: {} (attempt {}/{})", url, retryCount + 1, MAX_RETRY); |
|||
Document doc = Jsoup.connect(url).get(); |
|||
List<Article> articles = strategy.parse(url, doc); |
|||
articles.forEach(repository::add); |
|||
logger.info("Successfully crawled {} articles from {}", articles.size(), url); |
|||
return articles; |
|||
} catch (ParseException e) { |
|||
logger.error("Parse error: {}", e.getMessage()); |
|||
throw e; |
|||
} catch (Exception e) { |
|||
lastException = e; |
|||
retryCount++; |
|||
logger.warn("Network error (attempt {}): {}, retrying...", retryCount, e.getMessage()); |
|||
if (retryCount < MAX_RETRY) { |
|||
try { |
|||
Thread.sleep(RETRY_DELAY_MS); |
|||
} catch (InterruptedException ie) { |
|||
Thread.currentThread().interrupt(); |
|||
throw new CrawlerException("Crawl interrupted", ie); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
logger.error("Failed to crawl {} after {} attempts", url, MAX_RETRY); |
|||
throw new NetworkException("Failed to crawl after " + MAX_RETRY + " attempts", lastException); |
|||
} |
|||
|
|||
public List<Article> getAllArticles() { |
|||
List<Article> articles = repository.getAll(); |
|||
logger.debug("Retrieved {} articles from repository", articles.size()); |
|||
return articles; |
|||
} |
|||
|
|||
public int getArticleCount() { |
|||
int count = repository.size(); |
|||
logger.debug("Article count: {}", count); |
|||
return count; |
|||
} |
|||
|
|||
public void clearArticles() { |
|||
repository.clear(); |
|||
logger.info("Cleared all articles"); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
package com.example.datacollect.strategy; |
|||
|
|||
import com.example.datacollect.exception.ParseException; |
|||
import com.example.datacollect.model.Article; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import org.jsoup.nodes.Document; |
|||
import org.jsoup.nodes.Element; |
|||
import org.jsoup.select.Elements; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class BlogStrategy implements CrawlStrategy { |
|||
private static final Logger logger = LoggerFactory.getLogger(BlogStrategy.class); |
|||
|
|||
@Override |
|||
public List<Article> parse(String url, Document doc) throws ParseException { |
|||
List<Article> articles = new ArrayList<>(); |
|||
Elements links = doc.select("article a, .post a, .entry a"); |
|||
for (Element link : links) { |
|||
String title = link.text(); |
|||
String href = link.attr("abs:href"); |
|||
if (!title.isEmpty() && !href.isEmpty()) { |
|||
articles.add(new Article(title, href, "")); |
|||
} |
|||
} |
|||
logger.debug("Parsed {} articles from blog", articles.size()); |
|||
return articles; |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
package com.example.datacollect.strategy; |
|||
|
|||
import com.example.datacollect.exception.ParseException; |
|||
import com.example.datacollect.model.Article; |
|||
import java.util.List; |
|||
import org.jsoup.nodes.Document; |
|||
|
|||
public interface CrawlStrategy { |
|||
List<Article> parse(String url, Document doc) throws ParseException; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
package com.example.datacollect.strategy; |
|||
|
|||
import com.example.datacollect.exception.ParseException; |
|||
import com.example.datacollect.model.Article; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import org.jsoup.nodes.Document; |
|||
import org.jsoup.nodes.Element; |
|||
import org.jsoup.select.Elements; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class NewsStrategy implements CrawlStrategy { |
|||
private static final Logger logger = LoggerFactory.getLogger(NewsStrategy.class); |
|||
|
|||
@Override |
|||
public List<Article> parse(String url, Document doc) throws ParseException { |
|||
List<Article> articles = new ArrayList<>(); |
|||
Elements links = doc.select(".news-item a, .headline a, h2 a, h3 a"); |
|||
for (Element link : links) { |
|||
String title = link.text(); |
|||
String href = link.attr("abs:href"); |
|||
if (!title.isEmpty() && !href.isEmpty()) { |
|||
articles.add(new Article(title, href, "")); |
|||
} |
|||
} |
|||
logger.debug("Parsed {} articles from news", articles.size()); |
|||
return articles; |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package com.example.datacollect.strategy; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class StrategyFactory { |
|||
private static final Logger logger = LoggerFactory.getLogger(StrategyFactory.class); |
|||
private final Map<String, CrawlStrategy> strategies = new HashMap<>(); |
|||
|
|||
public StrategyFactory() { |
|||
strategies.put("example.com", new BlogStrategy()); |
|||
strategies.put("news.ycombinator.com", new NewsStrategy()); |
|||
strategies.put("weibo.com", new WeiboStrategy()); |
|||
logger.info("Initialized {} strategies", strategies.size()); |
|||
} |
|||
|
|||
public CrawlStrategy getStrategy(String url) { |
|||
for (Map.Entry<String, CrawlStrategy> entry : strategies.entrySet()) { |
|||
if (url.contains(entry.getKey())) { |
|||
logger.debug("Found strategy for url: {}", url); |
|||
return entry.getValue(); |
|||
} |
|||
} |
|||
logger.debug("No strategy found for url: {}", url); |
|||
return null; |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
package com.example.datacollect.strategy; |
|||
|
|||
import com.example.datacollect.exception.ParseException; |
|||
import com.example.datacollect.model.Article; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import org.jsoup.nodes.Document; |
|||
import org.jsoup.nodes.Element; |
|||
import org.jsoup.select.Elements; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
public class WeiboStrategy implements CrawlStrategy { |
|||
private static final Logger logger = LoggerFactory.getLogger(WeiboStrategy.class); |
|||
|
|||
@Override |
|||
public List<Article> parse(String url, Document doc) throws ParseException { |
|||
List<Article> articles = new ArrayList<>(); |
|||
|
|||
Elements cards = doc.select(".card-wrap, .WB_cardwrap, .feed-item"); |
|||
for (Element card : cards) { |
|||
Element titleElement = card.select(".txt, .WB_text, .content").first(); |
|||
Element linkElement = card.select("a[href*='/status/']").first(); |
|||
|
|||
if (titleElement != null) { |
|||
String title = titleElement.text().trim(); |
|||
String href = linkElement != null ? linkElement.attr("abs:href") : url; |
|||
|
|||
if (!title.isEmpty()) { |
|||
articles.add(new Article(title, href, "")); |
|||
} |
|||
} |
|||
} |
|||
|
|||
logger.debug("Parsed {} articles from weibo", articles.size()); |
|||
return articles; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
package com.example.datacollect.view; |
|||
|
|||
import com.example.datacollect.model.Article; |
|||
import java.util.List; |
|||
import java.util.Scanner; |
|||
|
|||
public class ConsoleView { |
|||
private static final String ANSI_RESET = "\u001B[0m"; |
|||
private static final String ANSI_GREEN = "\u001B[32m"; |
|||
private static final String ANSI_RED = "\u001B[31m"; |
|||
private static final String ANSI_BLUE = "\u001B[34m"; |
|||
|
|||
private final Scanner scanner = new Scanner(System.in); |
|||
|
|||
public String readLine() { |
|||
System.out.print("> "); |
|||
return scanner.nextLine(); |
|||
} |
|||
|
|||
public void printSuccess(String msg) { |
|||
System.out.println(ANSI_GREEN + msg + ANSI_RESET); |
|||
} |
|||
|
|||
public void printError(String msg) { |
|||
System.out.println(ANSI_RED + msg + ANSI_RESET); |
|||
} |
|||
|
|||
public void printInfo(String msg) { |
|||
System.out.println(ANSI_BLUE + msg + ANSI_RESET); |
|||
} |
|||
|
|||
public void display(List<Article> articles) { |
|||
if (articles.isEmpty()) { |
|||
printInfo("暂无文章,请先执行 crawl。"); |
|||
return; |
|||
} |
|||
for (int i = 0; i < articles.size(); i++) { |
|||
Article a = articles.get(i); |
|||
System.out.println((i + 1) + ". " + a.getTitle() + " | " + a.getUrl()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<configuration> |
|||
<property name="LOG_PATH" value="./logs"/> |
|||
|
|||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> |
|||
<file>${LOG_PATH}/crawler.log</file> |
|||
<encoder> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<logger name="com.example.datacollect" level="INFO"/> |
|||
|
|||
<root level="INFO"> |
|||
<appender-ref ref="STDOUT"/> |
|||
<appender-ref ref="FILE"/> |
|||
</root> |
|||
</configuration> |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,24 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<configuration> |
|||
<property name="LOG_PATH" value="./logs"/> |
|||
|
|||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> |
|||
<file>${LOG_PATH}/crawler.log</file> |
|||
<encoder> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<logger name="com.example.datacollect" level="INFO"/> |
|||
|
|||
<root level="INFO"> |
|||
<appender-ref ref="STDOUT"/> |
|||
<appender-ref ref="FILE"/> |
|||
</root> |
|||
</configuration> |
|||
@ -0,0 +1,19 @@ |
|||
com\example\datacollect\command\ListCommand.class |
|||
com\example\datacollect\command\CrawlCommand.class |
|||
com\example\datacollect\strategy\BlogStrategy.class |
|||
com\example\datacollect\repository\ArticleRepository.class |
|||
com\example\datacollect\Main.class |
|||
com\example\datacollect\view\ConsoleView.class |
|||
com\example\datacollect\command\ExitCommand.class |
|||
com\example\datacollect\command\HelpCommand.class |
|||
com\example\datacollect\strategy\WeiboStrategy.class |
|||
com\example\datacollect\strategy\NewsStrategy.class |
|||
com\example\datacollect\command\Command.class |
|||
com\example\datacollect\controller\CrawlerController.class |
|||
com\example\datacollect\exception\CrawlerException.class |
|||
com\example\datacollect\exception\NetworkException.class |
|||
com\example\datacollect\strategy\StrategyFactory.class |
|||
com\example\datacollect\service\CrawlerService.class |
|||
com\example\datacollect\exception\ParseException.class |
|||
com\example\datacollect\strategy\CrawlStrategy.class |
|||
com\example\datacollect\model\Article.class |
|||
@ -0,0 +1,19 @@ |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\command\ExitCommand.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\command\Command.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\strategy\StrategyFactory.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\strategy\WeiboStrategy.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\strategy\NewsStrategy.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\repository\ArticleRepository.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\view\ConsoleView.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\exception\CrawlerException.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\exception\NetworkException.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\strategy\CrawlStrategy.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\command\HelpCommand.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\command\ListCommand.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\command\CrawlCommand.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\model\Article.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\service\CrawlerService.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\Main.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\controller\CrawlerController.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\exception\ParseException.java |
|||
C:\Users\朱彦硕\Java\java\w11\src\main\java\com\example\datacollect\strategy\BlogStrategy.java |
|||
Loading…
Reference in new issue