目录

  • 前言
  • 一、自动爬取所有文章的链接地址
  • 二、字数统计
  • 总结

前言

在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的使用

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

自制脚本,统计个人csdn博客总字数相关推荐

  1. 【Blog】CSDN博客总排行榜

    CSDN博客总排行榜 https://blog.csdn.net/rank/writing_rank_total

  2. 30行代码统计自己 CSDN 博客相关数据

    1. 编写目的 爬虫本身是一个非常简单的事情,都是由于业务需要才变得越来越复杂的.为了方便广大开发者,也有很多简单好用的爬虫框架,但这里不使用那些已经实现了的专用框架,也不能起到任何商业化的目的,只是 ...

  3. 用 selenium 统计博客总字数

    有一天 突然想知道博客写了多少字 ⛵️​ - 1. 打开主页 利用 selemium 打开博客主页: import time from selenium import webdriverbrowser ...

  4. 2019年度CSDN博客之星TOP10榜单揭晓,你上榜了吗?

    培根说,『读书造成充实的人,会议造成未能觉悟的人,写作造成正确的人』. 在短信短视频快速迭代的快时代,更深度的思考.更正确的实践,更成体系的写作与分享,尤显可贵.这里,每一篇博文都是开发者实战的经验解 ...

  5. 大屏监控系统实战(6)-爬虫初探:爬取CSDN博客之星年度总评选投票统计数据

    一.介绍 我们先来做个简单的,我们的目标是爬取CSDN博客之星年度总评选的首页信息. 首页的地址:http://m234140.nofollow.ax.mvote.cn/wxvote/43ced329 ...

  6. 大屏实时监控-2019年CSDN博客之星年度总评选(2019-02-07 13:47)

    监控地址:http://anymk.com:8888/ 2019-02-07 13:47 2019-02-01 20:09 2019-01-28 15:17 2019-01-25 15:01 大屏实时 ...

  7. 大屏实时监控-2019年CSDN博客之星年度总评选(2019-01-20 23:30)

    近期的2019年CSDN博客之星年度总评选战况空前激烈,前面看了第一名天元浪子每日发布的投票统计博客,觉得很有意思,于是我就换个角度来分析一下.目前大屏监控比较流行,我也就跟风制作了一个供大家鉴赏. ...

  8. python+selenium统计CSDN博客(上):统计阅读量

    由于CSDN改版,本文有些过时,请移步Python玩转CSDN,用selenium统计博客的阅读量 这个功能是比较容易实现的,按理说一个人的所有文章都在博客主页,每篇文章的标题大致如下 <div ...

  9. 为你的CSDN博客添加CNZZ流量统计功能

    一.流量统计介绍 流量统计是指通过各种科学的方式,准确的纪录来访某一页面的访问者的流量信息,目前而言,必须具备可以统计. 1.简介 统计独立的访问者数量(独立用户.独立访客): 可以统计独立的IP地址 ...

最新文章

  1. 帝国cms让当前栏目显示不同样式(图文)
  2. 超大规模数据中心vs微型数据中心
  3. C语言从青铜到王者——基础知识总结
  4. 五层架构(MVC+biz+lib)
  5. spring boot集成mybatis+事务控制
  6. 使用CDN加速后网站不能使用HttpWebRequest提交数据
  7. 植物病害鉴定真的需要深度CNN吗?
  8. 【毕业设计】基于情感分析的网络舆情热点评估系统 - 大数据 python可视化 数据分析
  9. 【文献阅读】CCNet: Criss-Cross Attention for Semantic Segmentation
  10. printf用法之打印二进制,八进制,十进制,十六进制
  11. 把手机自带计算机软件,怎样删除手机自带软件
  12. Eclipse使用Log4j2的详细教程
  13. 2021极术通讯-CSL-YOLO | 超越Tiny-YOLO V4,全新设计轻量化YOLO模型实现边缘实时检测
  14. java实现mysql自动更新创建时间与更新时间的两种方式
  15. 第一章 Hadoop
  16. 信贷风控指南丨人工智能专家直播解析信贷评分卡模型
  17. UI设计界面设计培训班
  18. 《浪潮之巅》——当年摩托罗拉系统输在Java慢,Android赢在C++
  19. 基于ACCESS数据库写成的挂机游戏更新日志
  20. WIN 7 MSN 80040154 登录问题

热门文章

  1. jquery创建css_如何使用jQuery和CSS创建万花筒
  2. 【快应用】小程序转快应用如何退出整个快应用
  3. linux 内核 风扇,Linux CPU温度,风扇监测lm-sensors
  4. pandas学习笔记(四)
  5. C语言慈善募捐程序(在全院10000学生中,征集慈善募捐,当总数达到10万元时就结束,统计此时捐款的人数,以及平均每人捐款的数目。)
  6. 太阳直射点纬度计算公式_正午太阳高度角计算公式
  7. iOS emoji应用(一)
  8. Crisis Dents Putin's Popularity
  9. 使用MFC画线(初学)
  10. android 浏览器 遥控器 光标,Unified Remote!让手机变身电视遥控器