基于nodejs如何爬取csdn上自己的文章

news2024/11/19 17:32:11

当你想把自己在csdn上写的文章转为hexo上可以发布的文章或是将文章写入自己的数据库时,可以用到

将所有博客数据写入数据库

获取你的文章的分页接口:

在浏览自己的所有文章时,我们不难发现,文章的数据是往下滑动到底时,才会刷新出新的数据,
那么此时肯定是发送了一个请求来获取后面的分页数据:
在这里插入图片描述
这时,我们再查看他的请求url:
在这里插入图片描述
尝试查看下他的res.data:
在这里插入图片描述
那么,在这个url中,page,size这两个参数可以调整,其他的参数还没有尝试
接口为:
https://blog.csdn.net/community/home-api/v1/get-business-list?page=2&size=20&businessType=lately&noMore=false&username=你的用户名

将接口请求到的数据写入数据库:

这里我使用的是nodejs和mysql,

  • database schema:
const {
	DataTypes
} = require('sequelize')
const seq = require('../db/sql')

const markdownFile = seq.define('markdownFile', {
	//id会被sequelize自动创建,管理
	type: {
		type: DataTypes.STRING,
		allowNull: true,
	},
	formatTime: {
		type: DataTypes.DATE,
		allowNull: true,
	},
	title: {
		type: DataTypes.STRING,
		allowNull: true,
	},
	description: {
		type: DataTypes.TEXT,
		allowNull: true,
	},
	hasOriginal: {
		type: DataTypes.BOOLEAN,
		allowNull: true,
	},
	diggCount: {
		type: DataTypes.INTEGER,
		allowNull: true,
	},
	commentCount: {
		type: DataTypes.INTEGER,
		allowNull: true,
	},
	postTime: {
		type: DataTypes.DATE,
		allowNull: true,
	},
	createTime: {
		type: DataTypes.DATE,
		allowNull: true,
	},
	url: {
		type: DataTypes.STRING,
		allowNull: true,
	},
	articleType: {
		type: DataTypes.INTEGER,
		allowNull: true,
	},
	viewCount: {
		type: DataTypes.INTEGER,
		allowNull: true,
	},
	rtype: {
		type: DataTypes.STRING,
		allowNull: true,
	},
	content: {
		type: DataTypes.TEXT,
		allowNull: true,
		default: '暂无内容'
	},
	email: {
		type: DataTypes.STRING,
		allowNull: true,
		default: '拥有者邮箱'
	}
});
//下面这个是初始化时才开启的

/*markdownFile.sync({
    force: 'true'
});*/

//下面这个是运行时才开启的
module.exports = markdownFile;

这里的schema是按照需求写的,具体需要哪些字段,是看通过接口请求得到的文章数据中,有哪些字段

  • 连接mysql的sql.js

这里的sql.js代码按照自己的配置来连接,其中functiontest为连接时测试是否成功

//本机数据库连接配置
const {Sequelize} = require('sequelize')
//实例化对象
const seq = new Sequelize('markdownfile', 'root', '123456', {
// const seq = new Sequelize('markdownfile', 'root','1df4490cbd872e80', {
    dialect: 'mysql',
    port: 3306
});

async function test() {
    try {
        await seq.authenticate()
        console.log('数据库连接成功')
    } catch (error) {
        console.error('数据库连接失败:  ', error)
    }
}
test();
module.exports = seq;

此时,只需要使用https包,请求api,并将数据写入数据库
下面是需要运行的代码:

//根据csdn的api接口获取文章列表
const markdownFile = require('./model/markdownFile')
const {
	create
} = require('./service/md')

const https = require("https");
const config = {
	url1: 'https://blog.csdn.net/community/home-api/v1/get-business-list?page=',
	url2: '&size=20&businessType=lately&noMore=false&username=ice_stone_kai',
	page: {
		num: '1',
		size: '20'
	},
	html: '',
	json: {}

};
//使用http
https.get(`${config.url1}10${config.url2}`, res => {
	res.on('data', function (chunk) {
		config.html += chunk;
	});
	res.on('end', () => {
		config.json = JSON.parse(config.html);
		console.log('data:');
		const dataList = config.json.data.list;
			dataList.forEach(item => {
				create(item);
			});
	})
});

其中create为:


const https = require("https");
const markdownFile = require('../model/markdownFile');
class md {
    async create(obj) {
        // console.log(obj)
        const {
            type,
            formatTime,
            title,
            description, hasOriginal,
            diggCount,
            commentCount,
            postTime,
            createTime,
            url,
            articleType,
            viewCount,
            rtype,
            email
        } = obj;
        // await md.getData(url)
        return await markdownFile.create({
            type,
            formatTime,
            title,
            description, hasOriginal,
            diggCount,
            commentCount,
            postTime,
            createTime,
            url,
            articleType,
            viewCount,
            rtype,
            email
        })
    }
}
module.exports = new md;
数据库创建:

将schema那部分代码的注释取消:

markdownFile.sync({
    force: 'true'
});

右键,run
在这里插入图片描述
进入datagrip查看:
在这里插入图片描述
创建完成之后,刚刚的代码一定要再加上注释,或者把force的部分加上注释:

/*
markdownFile.sync({
    force: 'true'
});
*/

它的意思是,不管数据库是否存在,都会强制再创建一个新的目标数据库

通过api写入数据库:

这里我们是通过分页的接口来获取数据的,那么就需要修改page的参数来请求不同的分页数据,所以,我们这里page为1开始:
在这里插入图片描述
查看数据库:
在这里插入图片描述
写入了,这里你有多少分页数据就修改page的参数即可
我的分页数据有10页,所以这里修改page的参数从1,2,一直到10,
别问为什么不用遍历来异步获取数据,不会

将数据库中的单个文章数据写入markdown文件:

此时我们的数据库:
在这里插入图片描述
注意此时数据库中的数据字段并没有文章数据:
在这里插入图片描述

数据库的item获取文章数据:

尝试下面代码,便利查看数据库所有数据:

const fs = require('fs');
const https = require("https");
const cheerio = require("cheerio");
const TurndownService = require('turndown');
const turndownService = new TurndownService();
const markdownFile = require('./model/markdownFile');
//将数据写入markdown文件

markdownFile.findAll({
	raw: true  //只显示原始数据
}).then(res => {
	res.forEach(item => {
		console.log(item)
	})
}).catch(e => {
	console.log(e)
});

在这里插入图片描述

通过url获取文章数据:

注意这里的代码可能导入的一些库没有写上去


const cheerio = require("cheerio");
readArtivcle('https://blog.csdn.net/ice_stone_kai/article/details/125666593');
function readArtivcle(url) {
	let html = '';
	https.get(`${url}`, res => {
		res.on('data', function (chunk) {
			html += chunk;
		});
		res.on('end', () => {
			console.log('html获取完毕');
			const $ = cheerio.load(html);
			const ele = $("#content_views");
			console.log('将要写入的数据:---');
			console.log(ele.html());
		})
	});
}

在这里插入图片描述
这里使用cheerio来操作网页的dom.

html转markdown

此时我们会发现获取的数据可能并不那么理想,我们要写入的,应该是markdown格式的文件,那么就可以使用一些库来将htmlk转markdown:

function readArtivcle(url, filename, title, description, date) {
	let html = '';
	https.get(`${url}`, res => {
		res.on('data', function (chunk) {
			html += chunk;
		});
		res.on('end', () => {
			console.log('html获取完毕');
			const $ = cheerio.load(html);
			const ele = $("#content_views");
			let markdown = '';
			try {
				markdown = turndownService.turndown(ele.html());
			} catch (e) {
				console.log('节点读取错误')
			}
			console.log('将要写入的数据:---');
			console.log(markdown);
		})
	});
}

在这里插入图片描述
这里就转为了markdown格式的字符串

markdown写入文件:

代码:

readArtivcle('https://blog.csdn.net/ice_stone_kai/article/details/125666593');

function readArtivcle(url, filename, title, description, date) {
	let html = '';
	https.get(`${url}`, res => {
		res.on('data', function (chunk) {
			html += chunk;
		});
		res.on('end', () => {
			console.log('html获取完毕');
			const $ = cheerio.load(html);
			const ele = $("#content_views");
			let markdown = '';
			try {
				markdown = turndownService.turndown(ele.html());
			} catch (e) {
				console.log('节点读取错误')
			}
			writeFileToMarkdown(markdown, 'demo1.md');
		})
	});
}


function writeFileToMarkdown(str, filename) {
	fs.access(`./demo/${filename}`, fs.constants.F_OK, (err) => {
		console.log(`first judgement: ${filename} ${err ? 'is not exist' : 'is exist'}`);
		if (err) {
			console.log(`${filename} is not exist,so I will create it`);
			fs.writeFile(`./demo/${filename}`, '', (error) => {
				//创建失败
				if (error) {
					console.log(`file id no's exist,and create error:${error}`)
				}
				//创建成功
				console.log(`file id no's exist,but create success!`);
				//自己调用下自己,写入str
				writeFileToMarkdown(str, filename)
			})
		} else {
			fs.writeFile(`./demo/${filename}`, str, err => {
				if (err) {
					console.log('file write error');
					console.log(err)
				} else {
					console.log('file write success');
				}
			})
		}
	});
}

在这里插入图片描述
在这里插入图片描述
这里的writeFileToMarkdown第一个参数接受需要写入的字符串,第二个参数接受该文件的文件名,这里的文件名需要带文件的扩展名(.md),当文件不存在时,会先创建一次目标文件,然后自己调用一次自己,再写入

那么查看markdown文件:
在这里插入图片描述
在浏览器中查看原来的网页:
在这里插入图片描述
还行,但是打开markdown文件你会发现,它的头部并没有像是hexo博客的那种格式:
hexo应该是:
在这里插入图片描述
那么我们尝试添加一下:

const fs = require('fs');
const https = require("https");
const cheerio = require("cheerio");
const TurndownService = require('turndown');
const turndownService = new TurndownService();
const markdownFile = require('./model/markdownFile');
//将数据写入markdown文件

markdownFile.findAll({
	raw: true  //只显示原始数据
}).then(res => {
	res.forEach(item => {
		console.log(item)
		const date = item.formatTime;
		const title = item.title;
		const name = item.title + ".md";
		const url = item.url;
		const description = item.description;

		setTimeout(function () {
			readArtivcle(url, name, title, description,date);
		}, 3000);
	})
}).catch(e => {
	console.log(e)
});

function readArtivcle(url, filename, title, description, date) {
	let html = '';
	https.get(`${url}`, res => {
		res.on('data', function (chunk) {
			html += chunk;
		});
		res.on('end', () => {
			console.log('html获取完毕');
			const $ = cheerio.load(html);
			const ele = $("#content_views");
			let markdown = '';
			try {
				markdown = turndownService.turndown(ele.html());
			} catch (e) {
				console.log('节点读取错误')
			}
			console.log('将要写入的数据:---');
			markdown = '---  \n' + markdown;
			markdown = `date:${date}  \n` + markdown;
			markdown = `categories:  \n  - ${description}  \n` + markdown;
			markdown = `author: icestone  \n` + markdown;
			markdown = `title: ${title}  \n` + markdown;
			markdown = '---  \n' + markdown;
			console.log(markdown);
			writeFileToMarkdown(markdown, filename);
		})
	});
}


function writeFileToMarkdown(str, filename) {
	fs.access(`./markdownFile/${filename}`, fs.constants.F_OK, (err) => {
		console.log(`first judgement: ${filename} ${err ? 'is not exist' : 'is exist'}`);
		if (err) {
			console.log(`${filename} is not exist,so I will create it`);
			fs.writeFile(`./markdownFile/${filename}`, '', (error) => {
				//创建失败
				if (error) {
					console.log(`file id no's exist,and create error:${error}`)
				}
				//创建成功
				console.log(`file id no's exist,but create success!`);
				//自己调用下自己,写入str
				writeFileToMarkdown(str, filename)
			})
		} else {
			fs.writeFile(`./markdownFile/${filename}`, str, err => {
				if (err) {
					console.log('file write error');
					console.log(err)
				} else {
					console.log('file write success');
				}
			})
		}
	});
}

注意,这里代码跑起来不会停,你估计文章写完了,就把它停了就ok:
在这里插入图片描述
在Typora中查看下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/82112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一篇文章教你实战Docker容器数据卷

在上一篇中,咱们对Docker中的容器数据卷做了介绍。已经知道了容器数据卷是什么?能干什么用。那么本篇咱们就来实战容器数据卷,Docker容器数据卷案例主要做以下三个案例 1:宿主机(也就是Docker所安装的机器)与容器之间的映射-让Do…

LeetCode 538. 把二叉搜索树转换为累加树(C++)

标签:二叉树搜索 深度优先遍历 二叉树 思路一:递归实现反向中序遍历,并累加递归过程中的根的值 思路二:使用迭代,给每个根节点添加一个反向中序遍历的前驱节点。 原题链接:https://leetcode.cn/problems/co…

数据分析业务场景 | CTR预估

一.概况 定义 是推荐中最核心的算法之一 对每次广告的点击情况做出预测,预测用户是点击还是不点击 就是预测点击与否的而分类算法,成功的关键之一就是样本的准确性 对于正样本,一般可发挥的空间不是很大,最多就是卡一个停留时…

LinkedList源码解析

LinkedList源码解析 简介 LinkedList 是一个双向链表(内部是 Node 节点)实现的 List,并且还实现了 Deque 接口,它除了作为 List 使用,还可以作为队列或者栈来使用。 这样看来,LinkedList 简直就是个全能…

【文字版】津津有味:感染新冠后没食欲,那咱也得吃饭啊!

点击文末“阅读原文”即可收听本期节目剪辑、音频 / 朱峰 编辑 / 姝琦 SandLiu监制 / 姝琦 文案 / 粒粒 产品统筹 / bobo你阳了吗?你嗓子疼吗?你的食欲还好吗?没有什么比好好吃饭更重要,生病的时候尤其是。营养对健康而言是预防…

浏览器上的Cookies有什么用?超级浏览器防关联如何实现?

Cookies是浏览器的指纹信息之一,它是一种文本文件,是网站为了辨别用户身份,对用户进行记录并由户客户端计算机进行暂时或永久保存的信息。一般情况下,网站对浏览器的指纹的记录主要是依靠Cookies来实现的。因为超级浏览器来可以生…

[附源码]JAVA毕业设计英语网站(系统+LW)

[附源码]JAVA毕业设计英语网站(系统LW) 项目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术&#xf…

[附源码]Python计算机毕业设计大学生健康系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

c#和Python交互,完美解决Python调用OpenCV等第三方库以及分发时需配置python环境的问题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、问题分析二、解决方案第一个问题第二个问题三、结果及源码四、总结前言 关于C#如何调用Python,网上提供了很多解决方案,有用ironPyt…

react组件深度解读

五、React 核心是组件 在 React 中,我们使用组件(有状态、可组合、可重用)来描述 UI 。 在任何编程语言中,你都可以将组件视为简单的函数。 React 组件也一样, 它的输入是 props,输出是关于 UI 的描述。我…

Win11 WSL Linux子系统安装与注销 配置conda环境 启动jupyter

1 前言 本篇博客讲解如何在Windows11系统中安装与注销Linux子系统,并配置conda环境、jupyter环境,实现在Local浏览器启动jupyter并运行项目。 2 安装Linux子系统(参考文章[1]) 1.1 WSL 在任务栏中的搜索功能中,搜索…

合并多文件后分组再结构化

【问题】 Heres the problem statement: In a folder in HDFS, therere a few csv files with each row being a record with the schema (ID, attribute1, attribute2, attribute3). Some of the columns (except ID) could be null or empty strings, and no 2 records wi…

汇编语言常用DOS功能调用示例

1.利用DOS功能调用输出响铃(响铃的ASCII码为07H)。建立源程序文件HELLO.ASM,通过汇编程序得到目标文件RING.OBJ以及列表文件RING.LST,通过连接程序得到可执行文件性文件 RING.EXE。对可执行性文件进行调试。 (1&…

【数据结构】——栈和队列

目录 1.栈 1.1栈的概念及结构 1.2栈的实现 1.2.1具体实现 Stack.h 栈初始化 栈销毁 入栈 出栈 取栈顶数据 判空 栈中有效元素的个数 全部Stack.c的代码 测试Test.c代码 2.队列 2.1队列的概念及结构 2.2队列的实现 Queue.h 队列初始化 队列销毁 队尾入队列…

Tomcat8.0使用tomcat-redis-session-manager共享session【开源】,tomcat实现session共享

前言 【可跳过,比较简单】 由于以前的项目配置了多个tomcat服务使用了nginx代理,但是关闭某个tomcat的时候登录用户信息丢失,用户得重新登录,这就让人体验不好了;我们可以复制各个tomcat服务的session来实现的sessio…

【供给需求优化算法】基于适应度-距离-平衡供给需求优化算法FDB-SDO附matlab代码

​✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法…

毕设选题推荐基于python的django框架的学生课程管理系统

💖🔥作者主页:计算机毕设老哥🔥 💖 精彩专栏推荐订阅:在 下方专栏👇🏻👇🏻👇🏻👇🏻 Java实战项目专栏 Python实…

前端二面常见手写面试题(必备)

用正则写一个根据name获取cookie中的值的方法 function getCookie(name) {var match document.cookie.match(new RegExp((^| ) name ([^;]*)));if (match) return unescape(match[2]); }获取页面上的cookie可以使用 document.cookie 这里获取到的是类似于这样的字符串&…

新一代推理部署工具FastDeploy与十大硬件公司联合打造:产业级AI模型部署实战课...

人工智能产业应用发展的越来越快,开发者需要面对的适配部署工作也越来越复杂。层出不穷的算法模型、各种架构的AI硬件、不同场景的部署需求、不同操作系统和开发语言,为AI开发者项目落地带来极大的挑战。为了解决AI部署落地难题,我们发布了新…

(附源码)springboot校园跳蚤市场 毕业设计 646515

基于Springboot校园跳蚤市场 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。现代社会越来…