超实用!CSDN个人数据Chrome插件开发

发布时间:2023年12月30日

插件简介

相信写过博客的都知道,每天会经常打开自己的主页无数次,尤其是写了一篇新文章,就为了看文章浏览量增长了多少,文章获得了多少个赞,有多少人评论(谁不想自己写的文章成为爆款呢~)

因此我特意做了一个Chrome插件,让用户更方便地实时查看自己在CSDN博客上的数据

我们先来看看最后的实现效果:

在这里插入图片描述

这个插件能显示两部分数据,一部分是用户个人数据,包括:总阅读数、文章数、排名、粉丝数,另一部分是个人博客成就数据,包括:点赞数、评论数、收藏数、分享数

插件显示的数据默认每1小时更新一次,用户可以自行修改数据更新时间

插件的UI第一版写的暂时比较简陋,可以后期版本再修改以及增加一些功能

在开发之前,我们需要会一些前置知识,包括:Node.js爬虫、Chrome插件开发

不会的同学也没关系,可以看我之前写过的博客,里面关于爬虫和插件开发写的非常详细:

都 2023 年了还不会 Node.js 爬虫?快学起来!

Node.js 爬虫只会 Cheerio?来试试 Puppeteer!

从零入门 Chrome 插件开发

好的,现在我们就来开动吧!

爬取CSDN个人数据

这里默认大家已经学过puppeteer,具体爬取的操作在上一篇文章中有很详细的解释

这里我们分析完网页结构之后直接来编写爬虫脚本:

// 无头浏览器模块
const puppeteer = require("puppeteer");

// 目标页面
const crawlPage = "https://blog.csdn.net/weixin_46232841?spm=1000.2115.3001.5343";

// 网页爬虫
async function crawler() {
    //创建实例
    const browser = await puppeteer.launch({
        //无浏览器界面启动
        headless: "new",
        //放慢浏览器执行速度,方便测试观察
        slowMo: 100,
        // 设置打开的浏览器窗口尺寸
        defaultViewport: { width: 960, height: 540 },
    });

    // 新开一个tab页面
    const page = await browser.newPage();
    // 加载目标页,在 500ms 内没有任何网络请求才算加载完
    await page.goto(crawlPage, { waitUntil: "networkidle0" });

    // 在无头浏览器页面dom环境,获取页面数据
    const myData = await page.evaluate(() => {
        let data = {};
        let name = "萌萌哒の瑞萌萌";
        let achievement = {};

        // 个人数据
        document.querySelectorAll(".user-profile-head-info-r-c ul").forEach((ele) => {
            const allReadNum = ele.querySelector("li:nth-child(1) .user-profile-statistics-views .user-profile-statistics-num").innerText;
            const articleNum = ele.querySelector("li:nth-child(2) .user-profile-statistics-num").innerText;
            const rank = ele.querySelector("li:nth-child(3) .user-profile-statistics-num").innerText;
            const fans = ele.querySelector("li:nth-child(4) .user-profile-statistics-num").innerText;
            data = {
                allReadNum,articleNum,rank,fans
            }
        });
        
        // 个人成就
        document.querySelectorAll(".aside-common-box-achievement").forEach((ele) => {
            const like = ele.querySelector("li:nth-child(1) div").innerText;
            const comment = ele.querySelector("li:nth-child(2) div").innerText;
            const favorite = ele.querySelector("li:nth-child(3) div").innerText;
            const share = ele.querySelector("li:nth-child(4) div").innerText;
            achievement = {
                like,comment,favorite,share
            }
        });
        return {
            name,data,achievement
        };
    });

    console.log(myData);

    // 关闭tab页
    await page.close();
    // 关闭实例
    await browser.close();
})

运行一下看看有没有获取到我们想要的数据吧:

在这里插入图片描述

完美!现在我们拿到了我们想要的数据,接下来要完成的需求就是:

  1. 将数据存储到json文件里,方便插件目录获取
  2. 定时爬取,每隔一小时爬取一次,及时更新json文件

解决办法:用 fs 模块的fs.writeFile来保存文件,用 node-schedule 模块来实现定时爬取

上代码!

// 无头浏览器模块
const puppeteer = require("puppeteer");
const schedule = require('node-schedule');
const fs = require('fs');

// 目标页面
const crawlPage = "https://blog.csdn.net/weixin_46232841?spm=1000.2115.3001.5343";

// 创建一个定时任务,每隔1小时执行一次
let job = schedule.scheduleJob('0 0 */1 * * *',// 网页爬虫
async function crawler() {
    //创建实例
    const browser = await puppeteer.launch({
        //无浏览器界面启动
        headless: "new",
        //放慢浏览器执行速度,方便测试观察
        slowMo: 100,
        // 设置打开的浏览器窗口尺寸
        defaultViewport: { width: 960, height: 540 },
    });

    // 新开一个tab页面
    const page = await browser.newPage();
    // 加载目标页,在 500ms 内没有任何网络请求才算加载完
    await page.goto(crawlPage, { waitUntil: "networkidle0" });

    // 在无头浏览器页面dom环境,获取页面数据
    const myData = await page.evaluate(() => {
        let data = {};
        let name = "萌萌哒の瑞萌萌";
        let achievement = {};

        // 个人数据
        document.querySelectorAll(".user-profile-head-info-r-c ul").forEach((ele) => {
            const allReadNum = ele.querySelector("li:nth-child(1) .user-profile-statistics-views .user-profile-statistics-num").innerText;
            const articleNum = ele.querySelector("li:nth-child(2) .user-profile-statistics-num").innerText;
            const rank = ele.querySelector("li:nth-child(3) .user-profile-statistics-num").innerText;
            const fans = ele.querySelector("li:nth-child(4) .user-profile-statistics-num").innerText;
            data = {
                allReadNum,articleNum,rank,fans
            }
        });
        
        // 个人成就
        document.querySelectorAll(".aside-common-box-achievement").forEach((ele) => {
            const like = ele.querySelector("li:nth-child(1) div").innerText;
            const comment = ele.querySelector("li:nth-child(2) div").innerText;
            const favorite = ele.querySelector("li:nth-child(3) div").innerText;
            const share = ele.querySelector("li:nth-child(4) div").innerText;
            achievement = {
                like,comment,favorite,share
            }
        });
        return {
            name,data,achievement
        };
    });
    
    // 将数据写入文件中
    fs.writeFile('../chrome/mycsdn.json', JSON.stringify(myData), function (err, data) {
        if (err) {
            throw err
        }
        console.log('文件保存成功,当前时间:' + new Date());
    })

    // 关闭tab页
    await page.close();
    // 关闭实例
    await browser.close();
})

最终实现效果:

在这里插入图片描述

到此我们就实现了定时爬取CSDN个人主页数据的操作,接下来我们一起来完成Chrome插件开发!

Chrome插件开发

先来创建一个 Chrome 插件项目叫 mycsdn:

mkdir mycsdn  # 创建插件项目
cd mycsdn # 进入项目根目录
touch manifest.json # 在项目根目录中创建一个名为 manifest.json 的文件

接下来我们简单编写 manifest.json文件,参数配置如下:

{
    "manifest_version": 2,
    "name": "CSDN个人数据",
    "version": "1.0",
    "description": "CSDN个人数据展示",
    "permissions": [
        "activeTab"
      ],
    "browser_action": {
        "default_title": "CSDN个人数据",
        "default_popup": "popup/popup.html",
        "default_icon": {
            "128": "icon/icon128.png"
        }
    }
}

然后我们在根目录创建popup文件夹,添加一个名为 popup.html 的文件,我们来完成点击弹出的页面结构:

<!DOCTYPE html>
<html>
<head>
	<title>CSDN个人数据展示</title>
  	<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0">
  	<link rel="stylesheet" href="popup.css">
  	<script src="popup.js"></script>
</head>
<body>
	<div class="container">
		<div class="box">
			<div class="card-data content">
				<h2>个人数据</h2>
				<p>总阅读数</p>
				<p>文章数</p>
				<p>排名</p>
				<p>粉丝数</p>
			</div>
		</div>

    <div class="box">
			<div class="card-data card-achievement content">
				<h2>个人成就</h2>
				<p>点赞数</p>
				<p>评论数</p>
				<p>收藏数</p>
				<p>分享数</p>
			</div>
		</div>
	</div>
</body>
</html>

来点CSS装饰一下:

body {
    min-width: 400px;
    min-height: 300px;
    font-family: Arial, Helvetica, sans-serif;
    background-color: #f2f2f2;
    margin: 0;
    padding: 0;
}

.container {
  max-width: 800px;
  margin: 0 auto;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  padding: 10px 20px;
  background: radial-gradient(circle, rgba(238,174,202,1) 0%, rgba(148,187,233,1) 100%);
}

.box {
  position: relative;
  height: 220px;
  align-items: center;
  transition: 0.5s;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
 }

 .box .content {
  position: relative;
  padding: 0px 40px 10px 40px;
  backdrop-filter: blur(10px);
  z-index: 1;
  transform: 0.5s;
  background-color: rgba(255, 255, 255, 0.8);
  border-radius: 20px;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  margin-bottom: 0;
  font-size: 18px;
  color: #666;
  flex-grow: 1;
  text-align: right;
}

.content::before {
  content: "";
  background-image: url("../bk1.jpg");
  background-repeat: no-repeat;
  background-size: cover;
  opacity: 0.5;
  filter: blur(1px);
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}

.box .content p {
  font-size: 14px;
  font-weight: bolder;
  color: black;
}
 
.box .content h2 {
  font-size: 20px;
  margin-bottom: 10px;
  font-weight: bolder;
  color: black;
}

在这里插入图片描述

效果还不错,大家也可以根据自己的审美自己来设计页面

接下来我们来写JS,这里因为已经将数据存储在本地JSON文件中,所以我们用 XMLHttpRequest 对象来读取这个JSON文件,详细信息可以看一下注释:

// 当DOM加载完成时执行以下代码
document.addEventListener("DOMContentLoaded", function () {
    // 创建一个新的XMLHttpRequest对象
    let xhr = new XMLHttpRequest();

    // 指定要读取的文件路径
    xhr.open('GET', '../mycsdn.json', true);

    // 当请求完成时执行的回调函数
    xhr.onload = function() {
      if (xhr.status === 200) {
        // 将JSON字符串转换为JavaScript对象
        let data = JSON.parse(xhr.responseText);

        // 处理读取到的数据
        const allReadNum = document.querySelector("p:nth-of-type(1)");
        allReadNum.innerHTML = `总阅读数:${data.data.allReadNum}`;
      
        const articleNum = document.querySelector("p:nth-of-type(2)");
        articleNum.innerHTML = `文章数:${data.data.articleNum}`;
      
        const rank = document.querySelector("p:nth-of-type(3)");
        rank.innerHTML = `排名:${data.data.rank}`;
      
        const fans = document.querySelector("p:nth-of-type(4)");
        fans.innerHTML = `粉丝数:${data.data.fans}`;
      
        const like = document.querySelector(
          ".card-achievement p:nth-of-type(1)"
        );
        like.innerHTML = `点赞数:${data.achievement.like}`;
      
        const comment = document.querySelector(
          ".card-achievement p:nth-of-type(2)"
        );
        comment.innerHTML = `评论数:${data.achievement.comment}`;
      
        const favorite = document.querySelector(
          ".card-achievement p:nth-of-type(3)"
        );
        favorite.innerHTML = `收藏数:${data.achievement.favorite}`;
      
        const share = document.querySelector(
          ".card-achievement p:nth-of-type(4)"
        );
        share.innerHTML = `分享数:${data.achievement.share}`;
      }
    };
    // 发送请求
    xhr.send();

  // 设置插件图标
  chrome.browserAction.setIcon({ path: "icon/icon128.png" });
  // 设置插件标题
  chrome.browserAction.setTitle({ title: "CSDN个人数据展示" });
});

我们首先创建了一个XMLHttpRequest对象,然后使用open方法指定要读取的文件路径。接着我们定义了一个onload回调函数,在请求完成时执行。在这个回调函数中,我们首先检查请求的状态是否为200(表示成功),然后使用JSON.parse方法将JSON字符串转换为JavaScript对象,最后我们就可以处理读取到的数据将其显示在页面上。

在这里插入图片描述

进程管理工具PM2

到此为止,我们这个插件项目还剩最后一个问题没有解决:我们编写的这个nodejs 爬虫文件不可能一直在控制台运行,那么我们该怎么让这个文件一直运行从而来定时爬取更新JSON文件呢?

我们这里来用一个管理 Node.js 进程的第三方工具 PM2

PM2是一个流行的Node.js进程管理器,它可以帮助我们简化应用程序的部署、监控和管理:

  • 进程管理:PM2可以启动、停止、重启和删除进程,可以使用PM2来管理单个应用程序或多个应用程序。
  • 自动重启:如果进程崩溃或异常退出,PM2会自动重启它。
  • 监控和日志记录:PM2可以监控应用程序的CPU和内存使用情况,并将日志记录到文件中。
  • 负载均衡:如果运行多个实例,PM2可以使用负载均衡来将流量分配到不同的实例上。
  • 部署:PM2可以在生产环境中部署应用程序,可以将应用程序作为系统服务运行,并在系统启动时自动启动。

以下是一些PM2的常用命令:

  • pm2 start <file>:启动一个应用程序。
  • pm2 stop <id|name>:停止一个应用程序。
  • pm2 restart <id|name>:重启一个应用程序。
  • pm2 delete <id|name>:删除一个应用程序。
  • pm2 list:列出所有正在运行的应用程序。
  • pm2 monit:监视所有正在运行的应用程序的CPU和内存使用情况。

我们来安装一下 pm2:

npm install -g pm2

然后用 pm2 启动项目:

pm2 start /path/to/your/nodejs/script.js

这个命令会启动Node.js程序,并且在后台运行,即使关闭了终端也不会停止运行

在这里插入图片描述

如果想停止程序可以使用以下命令:

pm2 stop /path/to/your/nodejs/script.js

插件开发总结

本项目是Node爬虫和Chrome插件开发的一个综合案例,这个插件的功能非常实用,可以帮助我们更好地了解自己的CSDN博客个人数据。

我们首先用puppeteer编写node爬虫脚本爬取到了CSDN个人主页数据,然后将数据写入了JSON文件,并用node-schedule模块完成了定时爬取的功能。

之后我们完成了Chrome插件的主体开发,最后我们使用PM2进程管理工具让这个爬虫文件一直运行。

插件完整代码可以自取:https://github.com/KongC-X/node-creeper/tree/main/chrome

文章来源:https://blog.csdn.net/weixin_46232841/article/details/135306111
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。