10秒自动生成Markdown文件:轻松高效完成任务

背景

最近有一个小需求,就是从网上爬取内容下来,然后在生成对应的markdown文件,本篇主要记录一下这个过程

生成markdown

生成markdown文件过程如下所示

爬取html内容

在nodejs中爬取html文件的方式有多,这里以axios为例

javascript 复制代码
const url = `https://baike.baidu.com/item/${name}?fromModule=lemma_search-box`
const { data } = axios.get(url) // data就是html

爬取html内容的时候,可能会碰到2个常见的问题

  1. 接口返回403,这是因为服务端判断了一下请求是否来自浏览器客户端,如果不是则直接禁止访问
  2. 接口超时,这是因为我们在国内访问国外的资源,网络较慢,或者被墙了导致无法正常访问

解决403的问题,一般在headers里面带上User-Agent即可,如下所示

javascript 复制代码
// 可以创建一个新实例,所有请求公用
this.request = axios.create({
    headers: {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
    }
})

// 也可以单个请求的时候传User-Agent
axios.get(movieUrl, {
  headers: {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
  }
})

解决超时的问题,一般可以通过设置代理,走我们梯子的本地代理服务来访问国外站点

javascript 复制代码
const { HttpsProxyAgent } = require("https-proxy-agent");

const httpsAgent = new HttpsProxyAgent(`http://127.0.0.1:1087`);

axios.get(movieUrl, {
    // proxy: { // 这种方式不行,response会返回空字符串
    //     protocol: 'http',
    //     host: '127.0.0.1',
    //     port: 1087,
    // },
    httpsAgent,
    proxy:false,
})

注意:在给axios配置代理的时候,先使用的是axios proxy配置,但是发现请求是可以正常响应,但是response.data为空字符串,所以后面换成了传入httpsAgent,并且将proxy:设置成false这种代理设置方式,这样response.data就能正常获取到内容

解析html内容

拿到html之后,怎么从html里面获取到自己想要的信息,这里可以选择的方式有很多种,这里选择最常用的cheerio,通过cheerio来获取html中我们想要的信息

cheerio使用起来相当简单

  1. 安装依赖
  2. load html内容
  3. 通过选择器命中对应的元素
  4. 通过cheerio提供的方法,操作元素内容、属性、样式等

安装依赖

javascript 复制代码
pnpm add cheerio

load html内容

javascript 复制代码
const $ = cheerio.load(html)  //$是 cherrio 规定的

通过选择器命中对应元素

javascript 复制代码
// 标签选择器
$('c-header-content');

// 属性选择器
$('c-list-doc[data-title="测试"]')

// 类选择器
$('.J-lemma-content')

通过cheerio提供的方法,操作元素内容、属性、样式等

javascript 复制代码
// 获取文本内容
$('.J-lemma-content').text()

// 获取属性值
$('c-doc-content').attr('data-original-src');

下载图片

因为现在很多网站的图片都设置了防盗链,当我们在本地使用链接图片的时候可能没问题,但是当我们生成的markdown发布到掘金、微信公众号等这样的平台时,就会导致图片无法正常展示,所以我们可能需要将图片先下载下来,然后在进行下一步处理

npm里面提供了很多下载图片的包,而这次我们使用的比较简单,直接使用axios下载图片即可,代码如下所示

javascript 复制代码
async downloadImage(url, filename) {
    // 将 responseType设置成arraybuffer即可
    const response = await axios.get(url, { responseType: 'arraybuffer' });

    // 然后通过fs.writeFile写入到本地
    return fs.writeFile(filename, response.data);
}

try {
  await downloadImage(图片url, 本地路径)
} catch(err) {
  console.log('图片下载失败', err)
}

上传图片

有时候我们并不想自己写一个服务来返回上一步下载的图片,这时候我们会想到图床

常用的免费图床有

收费图床有

  • 又拍云
  • 腾讯云cos
  • 阿里云的oss

等更多图床内容可以参考最全的图床集合(国内外,站长必备)

这里我们选择免费的hello图床,hello图床有对应的api文档,比如上传图片调用方式如下所示

javascript 复制代码
loadImage(filePath) {
    const data = new FormData();
    const file = fs.createReadStream(filePath)
    data.append('file', file)
    data.append('permission', 0)
    // 返回值就会包括图片的url 
    return this.request.post(`https://www.helloimg.com/api/v1/upload`, data, {
        headers: {
            'Content-Type': 'multipart/form-data',
            "Authorization": "Bearer xxxxxxxxx",
            Accept: 'application/json'
        }
    })
}

需要注意的是file只能传单个图片,不支持传数组,更多的使用方式可以参考接口文档,还有就是免费的是有调用次数、频率、存储限制的,如果要求高的话,可以考虑其它图床

生成模版

当我们数据都准备好之后,最后就只剩生成内容了,生成内容的方式有很多中,比如直接使用模版字符串生成,如下所示

javascript 复制代码
fs.writeFileSync(`${articsDir}/${name}.md`, `
标题:xxx
图片:${imgUrl}
`)

如果我们的模版内容比较简单,那么通过模版字符串是完全没问题的,但是当我们的模版内容比较复杂,比如有if、else if、遍历等比较复杂的场景时,这时候通过模版字符串就不太好处理,或者代码会不太美观了,这时候我们可以借助模版引擎,只需要两步就可以帮助我们生成内容

  • 第一步:创建对应的模版
  • 第二步:传入对应的数据

这里使用nunjucks模版引擎

创建模版

javascript 复制代码
## 概况
{% for item in actorInfo %}
**{{ item.actor }}**<br/>
{% for it in item.info %}{{ it }}<br/>{{'\n'}}{% endfor %}
简介:{{ item.abstract.trim() }}<br/>
**{{ item.comment }}**<br/>
图片:
{% for img in item.tcImageUrls %}
![]({{img}})
{% endfor %}
{% else %}
  主角信息不存在
{% endfor %}

## 介绍


{% if bkSummary %}
{{bkSummary}}
{% else %}
{{summary}}
{% endif %}

传入数据

javascript 复制代码
const nunjucks = require('nunjucks')

nunjucks.configure({ autoescape: true });

const content = nunjucks.renderString(fs.readFileSync(this.articTemplatePath, 'utf-8'), {
    ...info,
});

fs.writeFileSync(`${articsDir}/${name}.md`, content)

总结

整个过程并不复杂,让我觉得最有用的可能还是使用模版引擎nunjucks生成markdown的这个步骤,因为可以根据事先定义的模版来生成最终的产物,那么在一些需要动态创建文件的场景就会非常有用,因为这种模版引擎的方式相比于模版字符串的方式,代码的可读性会高很多

相关推荐
zczlsy1137 分钟前
webpack介绍
前端·webpack·node.js
六个点39 分钟前
关于vue的面试考点总结🤯
前端·vue.js·面试
浪遏1 小时前
今晚揭开单例模式的面纱~
前端·设计模式·面试
驯龙高手_追风2 小时前
谷歌Chrome或微软Edge浏览器修改网页任意内容
前端·chrome·edge
luckyext2 小时前
Postman发送GET请求示例及注意事项
前端·后端·物联网·测试工具·小程序·c#·postman
dorabighead2 小时前
重构版:JavaScript 的 new 操作符——从“黑箱仪式”到“亲手造物”的认知跃迁
开发语言·javascript·重构
小满zs2 小时前
React第三十章(css原子化)
前端·react.js
一直在学习的小白~3 小时前
前端项目中创建自动化部署脚本,用于 Jenkins 触发 npm run publish 来完成远程部署
前端·自动化·jenkins
Perfect—完美3 小时前
Vue 3 事件总线详解:构建组件间高效通信的桥梁
前端·javascript·vue.js
wtrees_松阳3 小时前
【编程向导】-JavaScript-基础语法-类型检测
开发语言·javascript·原型模式