功能
通过Gecco来抓取网站,并存储到elasticsearch中。
可以通过网址搜索elasticsearch中存储的文章列表,可以查看文章内容。
环境
配置
安装elasticsearch
可配
elasticsearch安装ik分词器
elasticsearch.yml
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
indices.fielddata.cache.size: 20%
indices.breaker.total.use_real_memory: false
indices.breaker.fielddata.limit: 40%
indices.breaker.request.limit: 40%
indices.breaker.total.limit: 95%
预览
使用说明
选择一个站点提取文章
通过css选择器选择文章对应的标签
以 https://news.qq.com/ 为例,文章的标题为h1标签,内容为标签类名为content-article的标签,文章地址为任意包含超链接的a标签
新建一个Bean继承HtmlBean,添加注解 @Gecco(matchUrl = {"*"}, pipelines = "articlePipeline", downloader = "htmlUnitDownloder")
matchUrl代表匹配的url地址,pipelines指定获取到内容后的处理管道,downloader指定网址的下载方式
@HtmlField(cssPath = "h1")
private String title;
@HtmlField(cssPath = ".content-article")
private String content;
@Href
@HtmlField(cssPath = "a[href]")
private List<String> urls;
新建类public class ArticlePipeline extends BasePipeline<ArticlePipeline.Bean> ,在public void onCapture(Bean bean)可以获得提取到的文章数据,这里可以对文章进行存储。
@Override
public void onCapture(Bean bean) {
bean.getUrls().forEach(url -> {
Pattern pattern = Pattern.compile("https://new.qq.com/omn/.*");//匹配的文章地址
Matcher matcher = pattern.matcher(url);
if (!matcher.find()) {
return;
}
synchronized (fetchedSet) {
if (!fetchedSet.contains(url) && fetchedSet.size() < 15) {//最多抓取15篇文章
log.info(url);
fetchedSet.add(url);
DeriveSchedulerContext.into(new HttpGetRequest(url));//添加到抓取队列
}
}
});
// 保存文章
String id = MD5.create().digestHex(bean.getContent());
Article article = new Article();
article.setId(id);
article.setTitle(bean.getTitle());
article.setContent(bean.getContent());
if (articleRepository.findById(id).isPresent()) {
article.setCreateAt(new Date());
} else {
article.setUpdateAt(new Date());
}
articleRepository.save(article);
}
因为抓取的内容是html标签,所有文章的样式需要在article.html中加入才能更好地展现文章内容。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="zh">
<head>
<meta charset="UTF-8">
<title>文章列表</title>
<link rel="stylesheet" href="/css/tx.css">
</head>
<body>
<div class="content">
<div th:each="item : ${articles} " style="width: 100%;">
<a th:href="@{'/article/' + ${item.id}}" th:text="${item.title}"></a>
</div>
</div>
</body>
</html>