如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(一)

文章目录

  • 效果展示
  • 说明
  • 利用工具
  • 整体思路
  • 代码


效果展示

请添加图片描述
请添加图片描述

说明

  • 看了看网上很少做这个功能,但是我有这个需求,就抽出事件写了个简单的工具
  • 目前只能导出专栏的文章,不过思路类似
  • 并没有做 Promise 失败的重新发送,代码仍然待完善,欢迎提交分支 PR,仓库地址:github 代码仓库地址

利用工具

  • puppeteer:自动化库
  • asyncPool:并发控制库

整体思路

  1. 获取到你想提取的文章 id
  2. 根据 id 打开编辑器,利用自带的导出按钮

代码

// index.js
import puppeteer from "puppeteer";
import asyncPool from "tiny-async-pool";
import { getPage, waitingOpenURL, findElement, clickImport } from "./tools.js";(async () => {// 关闭无头模式,显示浏览器窗口// userDataDir 表示把登录信息放到当前目录下,省着我们每次调用脚本都需要登录const browser = await puppeteer.launch({headless: false,userDataDir: "./userData",});const page = await browser.newPage();page.on("dialog", async (dialog) => {await dialog.accept();});let targetURL = "https://blog.csdn.net/u010263423/category_9162796.html";await page.goto(targetURL);await page.setViewport({ width: 1080, height: 1024 });const targetPageCount = await getPage(page);const willOpenArr = await waitingOpenURL(targetPageCount, targetURL);const findArray = [];findArray.push(...(await findElement(page)));if (targetPageCount > 1) {for (let i = 0; i < willOpenArr.length; i++) {await page.goto(willOpenArr[i]);findArray.push(...(await findElement(page)));}}const baseWriteURL = `https://editor.csdn.net/md/?articleId=`;const baseWriteURLArray = findArray.map((i) => `${baseWriteURL}${i.id}`);let successHandle = 0;function handleURL(url) {return new Promise(async (resolve) => {const page = await browser.newPage();page.on("dialog", async (dialog) => {await dialog.accept();});await page.goto(url);await clickImport(page);await page.close();await new Promise((r) => setTimeout(r, 300));resolve(`${url} 解析完成 ${++successHandle}`);});}for await (const ms of asyncPool(2, baseWriteURLArray, handleURL)) {console.log(ms);}console.log("***已完成所有解析***");
})();
// tools.js
/*** 功能:获取文章标题* @param {*} lis* @returns*/
export async function getTitle(lis) {const titles = await lis.$$eval(".title", (elements) => {return elements.map((e) =>e.innerHTML.replace("\n", "").split("<!--####试读-->")[0].replace("\n", "").trim());});return titles;
}/*** 功能:获取文章写作时间* - nth-child 选择器从1开始,前面尽量是标签名吧,如果是类的话,我试了一下选择不到* @param {*} lis*/
export async function getDate(lis) {const titleDate = await lis.$$eval(".column_article_data span:nth-child(2)",(elements) => {return elements.map((e) => e.innerHTML.trim().split(" &nbsp")[0]);});return titleDate;
}export async function getID(lis) {const titleId = await lis.$$eval("a", (elements) => {return elements.map((e) => e.href.split("details/")[1]);});return titleId;
}export async function getPage(page) {const pageContainer = await page.$(".ui-paging-container");let pageCount = 1;if (pageContainer) {const pageContext = await pageContainer.$$eval(".ui-pager", (elements) => {return elements.map((e) => e.innerHTML);});pageCount = Number(pageContext[pageContext.length - 3]);}console.log(pageCount);return pageCount;
}export async function waitingOpenURL(targetPageCount, targetURL) {const arr = [];if (targetPageCount > 1) {for (let i = 2; i <= targetPageCount; i++) {const front = targetURL.split(".html")[0];const url = `${front}_${i}.html`;arr.push(url);}}return arr;
}export async function findElement(page) {// 等待页面选择器的出现await page.waitForSelector(".column_article_list");const lis = await page.$(".column_article_list");// 获取文章标题、写作时间、文章idconst titles = await getTitle(lis);const titleId = await getID(lis);const titleDate = await getDate(lis);// 整理成数组对象const notes = [];titles.forEach((item, index) => {const obj = {title: item,date: titleDate[index],id: titleId[index],};notes.push(obj);});return notes;
}/*** 功能: 点击导出按钮* @param {*} page*/
export async function clickImport(page) {await new Promise((r) => setTimeout(r, 1500));const importButton ="div.layout__panel.layout__panel--navigation-bar.clearfix > nav > div.scroll-box > div:nth-child(1) > div:nth-child(22) > button";await page.waitForSelector(importButton);await page.click(importButton);// await new Promise((r) => setTimeout(r, 500));const nextImportButton ="div.side-bar__inner > div.side-bar__panel.side-bar__panel--menu > a:nth-child(1)";await page.waitForSelector(nextImportButton);await page.click(nextImportButton);// 这个时间是不能省的,一定要给点击事件留点时间,// 不然直接跳转页面,下载就失效了await new Promise((r) => setTimeout(r, 500));
}export function handleWriteURLs(url) {return new Promise((resolve) => {console.log(url);resolve();});
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端秘法基础式(CSS)(第一卷)

一.认识CSS CSS 指的是层叠样式表&#xff08;Cascading Style Sheets&#xff09;&#xff0c;它是一种用于描述网页外观和布局的语法 CSS 可以定义网页中元素的字体、颜色、大小、位置、背景等样式&#xff0c;使网页具有美观的外观和统 一的风格。 通过将 CSS 样式表与 HTML…

《VulnStack》ATTCK-1

title: 《VulnStack》ATT&CK-1 date: 2024-01-29 14:53:49 updated: 2024-02-14 18:55:49 categories: WriteUp&#xff1a;Cyber-Range excerpt: 主机发现、端口扫描&#xff0c;服务探测&#xff0c;操作系统探测、nmap 漏洞库扫描、网站首页信息泄露、msf 渗透与信息收集…

题解37-42

101. 对称二叉树 - 力扣&#xff08;LeetCode&#xff09; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,nul…

P1219 八皇后 (dfs 表格坐标关系)

一个正常的dfs&#xff08;数据范围1-13&#xff09;&#xff0c;发现一条对角线上&#xff0c;分别符合和与差相等。因为有负数&#xff0c;这里我最开始开的是map&#xff0c;发现卡了最后一个点TLE&#xff0c;记录一下时间复杂度&#xff08; map&#xff0c;set的时间复杂…

前端工程化面试题 | 09.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化

图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化 卷积神经网络的一些基本概念&#xff1a;图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化 1.图像卷积、步长、填充 图像卷积&#xff1a;卷积核矩阵在一个原始图像矩阵上 “从上往下、…

MessageQueue --- RabbitMQ

MessageQueue --- RabbitMQ RabbitMQ IntroRabbitMQ 核心概念RabbitMQ 分发类型Dead letter (死信)保证消息的可靠传递 RabbitMQ Intro 2007年发布&#xff0c;是一个在AMQP&#xff08;高级消息队列协议&#xff09;基础上完成的&#xff0c;可复用的企业消息系统&#xff0c;…

35岁转行,是我人生中最正确的选择

前言 经常听到有人说&#xff0c;35岁是职场的分水岭&#xff0c;但我觉得我的35岁&#xff0c;人生才刚刚开始。 35岁前后&#xff0c;我生二胎&#xff0c;考研&#xff0c;跳槽&#xff0c;转行&#xff0c;从传统行业到服务业&#xff0c;从服务业到新能源行业&#xff0…

【简写MyBatis】01-简单映射器

前言 新开一个坑&#xff0c;为了学习一下MyBatis的源码&#xff0c;写代码是次要的&#xff0c;主要为了吸收一下其中的思想和手法。 目的 关联对象接口和映射类的问题&#xff0c;把 DAO 接口使用代理类&#xff0c;包装映射操作。 知识点 动态代理简单工厂模式Invocati…

嵌入式Linux平台大文件生成以及处理方法

在日常工作中&#xff0c;为了验证某些场景下的功能&#xff0c;经常需要人为构造一些大文件进行测试&#xff0c;有时需要用大文件来测试下载速度&#xff0c;有时需要用大文件来覆盖磁盘空间&#xff1b;偶尔会看到一些网络博文会教大家如何构造大文件&#xff1b;但是当需要…

大整数因数分解工具——yafu

一、安装 yafu--下载链接 二、配置环境变量&#xff0c;直接从cmd打开 1.找到yafu-x64.exe 所在的文件路径 2.点击设置——系统——系统信息——高级系统设置——环境变量——点击PATH&#xff08;上下都可以&#xff09;——新建 添加yafu-x64.exe 所在路径——点击确定 3…

《Go 简易速速上手小册》第1章:Go 语言基础(2024 最新版)

文章目录 1.1 Go 语言的安装与环境配置1.1.1 基础知识讲解案例 Demo&#xff1a;简单的 Go 程序 1.1.2 重点案例&#xff1a;搭建一个 Go Web 服务准备工作步骤 1&#xff1a;创建项目目录步骤 2&#xff1a;编写 Web 服务代码步骤 3&#xff1a;运行你的 Web 服务步骤 4&#…