为什么别人的沸点可以获得几百条点赞和评论,而我的却石沉大海?
那是因为你的内容没有戳中掘友们的关注点。
本文通过前端技术去分析,如何编写沸点才能上热门。
分析结果
这是根据关键词热度的结果,到编写文章为止,只爬了两天的数据,所以准确性还很低,不过可以大概看出来,国庆期间关于结婚方面的内容比较热门。
这里贴出的是热度前 10 的关键词,实际上总共爬取的关键词有 500+。
大概也可以看出,热度低的关键词,确实没什么吸引力。
我拿排名前 100 的关键词,让 AI 去帮我划分一下分类:
跟朋友分享这个结果后,他用小号编写了一个沸点,并用 AI 生成了图片,很快就被推荐到了热门。
可见,根据数据提取出关键词去分析掘友们的关注点,就可以写出热门沸点。
需求分析
如果只通过阅读的方式去分析,也可以大概得出一些结论,比如美女自拍就可以吸引一群舔狗。
但是作为一名开发者,用这种方式肯定是不够看,那么如何使用已经掌握的前端技术去帮助我分析呢?首先明确以下几点,来满足分析的基本条件:
- 足够的数据。
- 关键词提取。
- 可视化结果。
技术分析
在着手之前,一定要调研清楚需求对应的技术栈是否可以实现。根据需求,依次理清所需要的技术栈:
基础环境搭建
首先声明,我认为只要是 JavaScript 能实现的都可以称之为前端技术,当然做这种分析浏览器是很难实现的,所以还是采取了 Nest 做为基础环境去开发。主要使用到的技术栈为:
- Nest.js
- MySql
足够的数据
有种大数据分析的感觉了,大量的数据可以使我们分析的结果更加准确。
- puppeteer,使用它可以爬取热门沸点的信息。
- @nestjs/schedule,可以做定时任务,每天特定时间去爬取沸点。
通过每天的定时任务,可以使数据量越来越大,每天的累计都会使分析更加精准。
关键词提取
每个沸点中都可以提炼出几个关键词,靠人力去分析就太麻烦了。
- @node-rs/jieba,提取关键词。
实现方式
Nest 的使用方式这里就不过多讲解了,主要还是以逻辑代码为主要讲解,如果有哪里不太明白的地方,可以参考源码。
初始化爬虫
使用 puppeteer 可以方便的爬取内容,拿到数据用以后续的分析。
首先初始化一个浏览器和页签,跳转到热门沸点网址:
const browser = await puppeteer.launch({ headless: 'new' });const page = await browser.newPage();await page.goto('https://juejin.cn/pins/hot');
由于掘金沸点浏览方式是无限向下滚动取加载更多沸点,所以这里需要做间隔时间去滚动到页面底部,以便获取更多的沸点:
await page.waitForSelector('.pin-list');// 每隔 5秒 滚动到底部,持续 5 次。for (let i = 0; i < 5; i++) {await page.evaluate(() => {window.scrollTo(0, document.body.scrollHeight);});await page.waitForTimeout(5000);}
这里只滚动 5 次,因为再向下可能会刷到更久以前或者点赞回复很少的沸点,意义不大。
爬取信息
上述步骤完成后,已经可以拿到整个 dom 树,这里就包含了我们需要的信息。
这时需要你打开开发者工具,去观察 dom 树,寻找你需要的信息,然后用代码去获取。
data-pin-id
是沸点的唯一 id,拿到它可以用来判断之前是否爬取过这条沸点,用来更新数据或新增数据。data-author-id
是作者 id,可以先爬下来可以为以后更深入的分析做准备。
.content
就是沸点内容。- 图片如果你有能力去做分析也可以爬下来。
.like-action
可以拿到点赞数。.comment-action
可以拿到评论数。
.club
是圈子,也可以先爬下来为深入的分析做准备。
const result = await page.evaluate(() => {const list = [...document.querySelectorAll('.pin-list .pin')];const pins = list.map((pin) => {const pinId = pin.getAttribute('data-pin-id');const authorId = pin.querySelector('.pin-header').getAttribute('data-author-id');const content = pin.querySelector('.content').textContent;const club = pin.querySelector('.club')" />;const comment = Number(pin.querySelector('.comment-action').textContent,);const like = Number(pin.querySelector('.like-action').textContent);return {// ...};});return pins;});
爬取到的数据保存到数据库即可。
关键词提取
使用 @node-rs/jieba 的原因:
- 支持 node 更高的版本,我目前用的 18,NodeJieba 目前只支持到 node 14,而且很久没有更新了。
- Rust 分析速度更快。
import { load, extract } from '@node-rs/jieba';load();const keywords = extract(sentence: string | Buffer, topn: number, allowedPos?: string);
extract 函数参数:
- sentence:爬取的沸点内容。
- topn:分析出几个关键词,这里建议 5 个即可。
- allowedPos:词性。
这里贴出可以使用的词性:
标签 | 含义 | 标签 | 含义 | 标签 | 含义 | 标签 | 含义 |
---|---|---|---|---|---|---|---|
n | 普通名词 | f | 方位名词 | s | 处所名词 | t | 时间 |
nr | 人名 | ns | 地名 | nt | 机构名 | nw | 作品名 |
nz | 其他专名 | v | 普通动词 | vd | 动副词 | vn | 名动词 |
a | 形容词 | ad | 副形词 | an | 名形词 | d | 副词 |
m | 数量词 | q | 量词 | r | 代词 | p | 介词 |
c | 连词 | u | 助词 | xc | 其他虚词 | w | 标点符号 |
PER | 人名 | LOC | 地名 | ORG | 机构名 | TIME | 时间 |
如果你想分析多个词性,可以以逗号分隔:
const keywords = extract(content, 5, 'n,nr,ns,nt,nw,nz,vn');
热度计算
关于热度计算,我直接使用了一个简单粗暴的公式:
关键词分析后,会返回关键词和权重字段,weight,代表关键词在这个沸点中的权重。
热度 = 权重 × (点赞数 + 评论数)
- count 是在所有沸点中出现过的次数,暂时没有加入到计算公式,理论上讲,它也很有意义。
可视化展示
直接在数据库里看不是很直观,可以利用 ECharts 做个可视化展示,可以更加清晰看清关键词的热度分布。
最后
我错了,我道歉。
还是有明白人啊哈哈。