自制脚本,统计个人csdn博客总字数

前言

在csdn写博客也已经一年多了,经常忍不住想知道自己总共写了多少字。可是目前官方只能统计单篇文章的总字数,却没有提供所有文章的字数统计数据(希望官方以后增加这个统计数据)。

一篇一篇地点开统计虽说数据量也不是很大,但是作为一个前端,能用脚本搞定的事干嘛要自己去数呢?于是我就抽空自己写了一段简单的脚本,对自己目前的67篇文章进行了一次字数统计,最后统计的总字数约为50万字,跟预期还是非常接近的。下面我们就一起来看代码的实现吧(脚本可以复制下来用于统计自己的博客数据)。

注意,由于文章的列表页(https://mp.csdn.net)与文章详情页(https://blog.csdn.net)位于不同的域,为了避免处理跨域问题,我们的脚本分为两部分:第一段脚本在列表页控制台执行,可获取所有文章详情页的链接地址;第二部分可任意打开一个详情页在控制台执行,即可得到最终的统计结果。如果想要一次性统计出所有的字数,可能需要使用nginx进行较为复杂的代理,本文暂不涉及这种方案。

整个过程分为两步:第一步是爬取所有文章详情页的链接地址,第二步就是进行字数统计。

一、自动爬取所有文章的链接地址

首先第一步,当然是打开个人博客的文章详情页,也就是下面的页面(可在登录后,从首页头像的下拉列表中点击个人中心 > 我的博客进入该页面):
在这里插入图片描述
第一步,我们先来定义一个数组,用于存储所有文章的url:

let urls = [];

第二步,定义一个获取当前页面所有文章链接地址的函数。

csdn的文章列表是分页的,每次最多只能加载20篇文章,我们的这个函数只是用于获取当前页的链接。后面我们会介绍如何通过脚本自动加载其他页的文章。代码如下:

function getUrls () {
    let items = document.querySelectorAll('.item-info-oper');
    urls = urls.concat(Array.from(items).map(item => {
        return item.querySelectorAll('a[target]')[0].href;
    }));
}

函数第一行获取的是列表每篇文章的这个部分,我们暂且称之为工具栏
在这里插入图片描述
工具栏内的'查看'按钮的href属性里带了文章详情页的地址:
在这里插入图片描述
于是我们遍历这20个工具栏,找出图中对应的a标签,取出其href属性的值,拼接到urls数组中。这个函数执行一次,当前页内的20篇文章的链接地址就会自动被统计出来。

第三步,定义一个自动翻页的函数。

其实自动翻页非常简单,页面的底部有一个翻页按钮,点击即可翻页。我们所要做的,只是用js自动模拟点击:

// 获取下一页的文章数据
function fetchNextPage () {
    let next = document.querySelector('.btn-next');
    if (next.disabled !== 'disabled') {
        next.click();
    }
}

只有当翻页按钮没有disabled属性的时候,我们才自动进行下一次翻页,否则说明已经是最后一页了。

第四步,设置DOM MutationObserver监听,检测页面翻动。

我们知道,点击了翻页按钮后,列表数据没有马上变化,页面需要向后端发请求,获取下一页的数据后再渲染到页面上。那么我们怎么知道新一页的数据已经渲染到页面上了呢?

一个可以想到的办法是给对应的ajax请求注册回调函数,但是由于请求下一页数据的代码不是我们实现的,这个方案不便于实施。不过我们还有一个更加直接了当的办法:监听DOM变动事件

首先我们获取到列表项的根节点:

let rootDiv = document.querySelectorAll('.article_manage_list > div')[1];

在这里插入图片描述
图中的.article-list-item-mp就是每一个文章列表项,我们现在获取到的就是这些列表项的根节点,即图中的那个div

下面我们要定义一个对该节点的观察者对象,检测该节点的变动:

// 只观测它的子元素变化
const config = { childList: true };
const observer = new MutationObserver(function () {
    // 一旦发生变化就获取当前页文章的url,
    // 随后继续获取下一页的数据
    getUrls();
    fetchNextPage();
});
// 启动观测
observer.observe(rootDiv, config);

config的配置表示我们要监听某个DOM节点子元素的变化,当文章列表变化时,它们的父节点就会触发这个事件。接着我们创建一个观察者,它会在发生DOM变动时调用getUrls()统计当前页的文章链接地址,然后继续调用fetchNextPage()进行自动翻页。最后就是用这个观察者去观察列表项的根节点。

第五步,爬取当前页的链接地址。

我们需要先调用getUrls获取当前页的链接地址:

getUrls();

统计完当前页的数据,就进行翻页:

fetchNextPage();

由于DOM变动的监听事件会在监听到列表发生变动时自动进行下一次翻页,所以我们只需手动触发第一次翻页,列表页就会自动翻页,直到最后一页为止,并在这个过程中统计出每一页文章的链接地址。

第六步,输出所有链接地址。

当在控制台执行完上述代码,我们可以手动在控制台输入变量urls,它应该已经保存了所有文章的链接地址(这里共67篇文章,因此数组有67项):

> urls
< [
  "https://blog.csdn.net/qq_41694291/article/details/107877447",
  ...
]

上述的整个过程就是如下代码,直接复制粘贴到列表页的控制台,回车执行即可:

// 存储所有的url
let urls = [];
// 提取当前页的所有文章的url
function getUrls () {
    // 
    let items = document.querySelectorAll('.item-info-oper');
    urls = urls.concat(Array.from(items).map(item => {
        return item.querySelectorAll('a[target]')[0].href;
    }));
}
// 获取下一页的文章数据
function fetchNextPage () {
    let next = document.querySelector('.btn-next');
    if (next.disabled !== 'disabled') {
        next.click();
    }
}
let rootDiv = document.querySelectorAll('.article_manage_list > div')[1];
const config = { childList: true };
const observer = new MutationObserver(function () {
    getUrls();
    fetchNextPage();
});
observer.observe(rootDiv, config);

// 获取当前页所有文章的链接地址
getUrls();
fetchNextPage();

执行完毕,在控制台输入:

> urls
< [
  "https://blog.csdn.net/qq_41694291/article/details/107877447"
  ......
]

这就是我们要的url数组,我们将其拷贝下来,以备后续使用。为了方便拷贝,我们可以将其转化为json:

// 格式化为JSON字符串,并在每个元素前插入2个空格
JSON.stringify(urls, null, 2);

二、字数统计

由于列表页和详情页存在跨域问题,因此我们得到上述url数组后并未直接继续爬取页面,而是把得到的url暂时保存起来了。现在我们可以任意进入一个文章的详情页,打开其控制台:
在这里插入图片描述
第一步,将url数组拷贝过来。

我们刚才已经得到了所有文章的详情页的链接地址,现在我们将其保存在一个变量中:

let urls = [
  "https://blog.csdn.net/qq_41694291/article/details/107877447",
  ...
];

第二步,设置变量total和time,total用于记录已统计的总字数,time是一个延迟时间:

let time = 0;
let total = 0;

total就不用多说了,这里之所以要设置一个计时器,是因为实际测试发现,当同时向服务器使用fetch发送67个请求,大约有60个请求都报了如下的错误:
在这里插入图片描述
而以200毫秒的延迟逐个发送请求时则没有报错(根据网速的不同,这个延迟可能需要设置得更长)。

第三步,请求文章详情页数据,解析文本并统计字数。

为了简便,我们直接使用浏览器原生的fetch接口来发送请求,然后使用原生的DOMParser来解析返回的HTML页面:

// 在列表页得到的url数组
let urls = [ ... ]

let time = 0;
let total = 0;

urls.forEach(url => {
  time += 200;
  setTimeout(() => {
    fetch(url).then(res => {
      // 获取返回的页面字符串
      res.text().then(data => {
        let parser = new DOMParser();
        // 将字符串以html格式解析,得到document对象
        let result = parser.parseFromString(data, 'text/html');
        // 使用原生DOM获取页面内的文章标签
        let article = result.querySelector('article');
        // 替换掉所有的空白字符
        let length = article.textContent.replace(/\s+/g, '').length;
        // 统计字数
        total += length;
        console.log(total);
      })
    })
  }, time);
})

可以看到在浏览器控制台依次输出67个数据,最后一个就是我们要统计的总字数:
在这里插入图片描述
注意,本代码较为消耗内存(特别是文章非常多的时候),所以多次输出可能造成页面卡顿,如果发生卡顿可以关闭页面重新执行。

总结

想要使用本文的脚本统计字数,可以先把第一部分的代码粘贴到列表页控制台,回车执行。执行完毕后继续输入:urls,获取所有文章的url数组。接着把这个数组保存起来,粘贴到第二部分的代码的变量urls中。然后任意打开一个文章详情页(在别人的文章详情页也可以,因为访问详情页不存在权限问题),执行第二部分的代码,等待输出完毕,就可以统计出自己所有csdn文章的总字数了。

有三个注意事项:

  1. 必须在列表页的第一页执行第一部分脚本,因为脚本是从当前页开始统计的。
  2. 执行完第一部分脚本后翻页功能会失效(因为DOM监听事件一直存在,每次点击翻页按钮后它都会检测到,并自动翻到最后一页),关闭重新打开即可恢复翻页功能。
  3. 脚本在一个页面内只能执行一次,想要再次执行请关闭页面重新打开。

本脚本涉及到的主要知识点有三个:

  1. DOM MutationObserver的使用
  2. fetch的使用
  3. DOMParser的使用

希望读完本文的同学也可以简单地了解一下这几个知识点。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JSP(JavaServer Pages)是一种用于开发动态Web应用程序的Java技术,它能够和Java语言无缝集成,在CSDN上实现个人博客系统可以采用JSP来构建。 首先,我们可以定义一个数据库来存储博客系统所需的数据。可以使用MySQL等关系型数据库管理系统进行设计和管理。在数据库中创建博客表,包含博客标题、内容、创建时间等字段。 接下来,我们可以使用JSP来创建博客的前端界面。可以使用HTML和CSS技术来构建页面布局和样式。可以创建一个主页面,包含博客列表的展示区域和博客详情的展示区域。使用JSP的脚本标签来插入Java代码,获取数据库中的博客数据,并动态显示在页面上。 在主页面的博客列表区域,我们可以使用JSP的循环结构,遍历数据库中的博客数据,将每篇博客的标题和创建时间等信息展示出来。可以为每篇博客添加点击事件,跳转到对应的博客详情页面。 在博客详情页面,我们可以通过JSP从数据库中获取指定博客的内容,并动态显示在页面上。可以在页面上添加评论区域,用户可以在该区域发表评论,评论内容也可以存储在数据库中。 最后,我们可以使用JSP来处理用户的操作和交互。例如,当用户点击某篇博客的标题时,JSP可以将对应的博客ID传递到服务器端,然后根据博客ID从数据库中获取博客的内容,并展示在页面上。当用户发表评论时,JSP可以将评论内容插入数据库中。 之,通过使用JSP来构建个人博客系统可以实现CSDN最新上的功能。JSP可以与Java语言无缝集成,可以方便地处理数据库操作和用户交互。通过合理设计数据库、创建前端页面和处理用户操作,可以实现具备基本功能的个人博客系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值