酷壳(coolshell.cn)镜像站建设经验分享之三——分析爬取的文章html得到正文及相关的元数据

酷壳(coolshell.cn)镜像站建设经验分享之三——分析爬取的文章html得到正文及相关的元数据

朱治龙
2024-02-28 / 0 评论 / 32 阅读 / 正在检测是否收录...

本系列文章生成的镜像站已上传到 Gitee Pages 托管平台,可通过如下地址查看完成后的效果:https://jhlxge.gitee.io/coolshell-mirror/
2024年6月5日更新 :Gitee Pages服务已停止提供服务,可通过本机托管的如下地址访问:https://coolshell-mirror.work.zhuzhilong.com/
Gitee Pages 停服

在上篇文章中我们把需要的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

评论 (0)

取消