本系列文章生成的镜像站已上传到 Gitee Pages 托管平台,可通过如下地址查看完成后的效果:https://jhlxge.gitee.io/coolshell-mirror/
2024年6月5日更新 :Gitee Pages服务已停止提供服务,可通过本机托管的如下地址访问:https://coolshell-mirror.work.zhuzhilong.com/
在上篇文章中我们把需要的html的内容爬取并存储到 crawler_article 表了,不少系统都是边爬取边分析,然后一步得到所需的内容,我们这边为什么要分这么多步骤来实现呢?我自己感觉这样的设计的好处是:
这个过程比较长,我们很难一次性把所有的流程都实现完,并且保证不出错,一步一步来的话,在某一步出了问题,我们可以仅调整这一步的代码,这样也能将一个大任务解耦。解耦后也更便于我们做代码维护。
好了,闲话少说,所需要的内容我们已经爬取完毕了,接下来我们开展下一步工作:解析获取文章元数据,这个过程的完整代码如下:
import cn.hutool.core.util.NumberUtil
import cn.hutool.core.util.ObjectUtil
import cn.hutool.core.util.StrUtil
import org.jsoup.Jsoup
import cn.hutool.core.date.DateUtil
import cn.hutool.json.JSONUtil
import cn.hutool.core.util.URLUtil
import log
var timer = DateUtil.timer(); // 定义计时器,用于记录时间
var pageList = db['MDC'].select('select id,page_html from crawler_article where page_html is not null')
log.info("待处理记录数据:" + pageList.size())
for (item in pageList) {
var pageHtml = item.pageHtml
// 1、获取内容元数据
// 1.1 获取发布时间、作者、评论数、阅读数
var doc = Jsoup.parse(pageHtml)
var entryDateEle = doc.select('time.entry-date')
var publishDate = ''
if (ObjectUtil.isNotEmpty(entryDateEle)) {
publishDate = DateUtil.parse(entryDateEle.attr('datetime'))
publishDate = DateUtil.formatDateTime(publishDate)
}
var authorEle = doc.select('.author.vcard a')
var author = ''
if (ObjectUtil.isNotEmpty(authorEle)) {
author = authorEle.text()
}
var commentEle = doc.select('a.comments-link')
var commentCount = 0
if (ObjectUtil.isNotEmpty(commentEle)) {
var commentCountText = StrUtil.replace(commentEle.text(),' 条评论', '')
commentCountText = StrUtil.replace(commentCountText,',','')
if (NumberUtil.isNumber(commentCountText)) {
commentCount = Integer.parseInt(commentCountText)
}
}
var appNodes = doc.select('.entry-date').textNodes()
var viewEle = appNodes.get(appNodes.size() - 2)
var viewCount = 0
if (ObjectUtil.isNotEmpty(viewEle)) {
var viewText = viewEle.text().replace(' 人阅读', '')
viewText = StrUtil.replace(viewText,',','')
viewText = StrUtil.replace(viewText,' ','')
viewCount = Integer.parseInt(viewText)
}
// 1.2 获取tag
var tagsEle = doc.select('.tags-links')
var tags = ''
if (ObjectUtil.isNotEmpty(tagsEle)) {
tags = tagsEle.text()
}
// 1.3 获取分类数据
var categoriesEle = doc.select('.cattegories .cat-links')
var categories = []
if (ObjectUtil.isNotEmpty(categoriesEle)) {
var cates = categoriesEle.select('a')
categories = cates.map(cate => {
var link = cate.attr('href')
link = link.substring(link.lastIndexOf('/') + 1)
link = URLUtil.decode(link)
var text = cate.text()
return {
code: link,
name: text
}
})
}
// 2、获取正文
var contentEle = doc.select('.entry-content').first()
// 清理不需要的数据
contentEle.select('script[crossorigin="anonymous"]').first().remove()
contentEle.select('.wp_rp_wrap').first().remove()
contentEle.select('.post-ratings').first().remove()
contentEle.select('.post-ratings-loading').first().remove()
contentEle.select("div[style='margin-top: 15px; font-size: 16px;color: #cc0000;']").first().remove()
var articleHtml = contentEle.html()
articleHtml = StrUtil.replace(articleHtml,'<p>(全文完)</p>','')
articleHtml = StrUtil.replace(articleHtml,'<p>(全文完)</p>','')
if(StrUtil.isNotBlank(articleHtml)) {
var articleText = StrUtil.replace(contentEle.text(),'(全文完)','')
articleText = StrUtil.replace(articleText,'(全文完)','')
var updateMap = {
id: item.id,
articleHtml,
articleText,
author,
publishDate,
categories: JSONUtil.toJsonStr(categories),
tags: tags,
clickCount:viewCount,
voteCount:commentCount,
analysisTime:DateUtil.now()
}
db['MDC'].table('crawler_article').primary('id').update(updateMap)
}
}
log.info(`Cost Time: ${timer.intervalPretty()}.`);
这个过程主要是分析文章 html,得到文章如下元数据:正文内容、作者、发布时间、分类列表、Tag词列表、浏览次数、评论次数,并将相关元数据存储到 crawler_article 表的对应字段里。
评论 (0)