文章教你如何作掘金站内数据抓取,数据解析,最后造成排序后的排名。前端
0821更新: 掘金总点赞量前 5000 排行发布 | 掘金总关注量前 5000 排行(20190821)vue
0827更新: 【第三方掘金功能】掘金我的数据统计,第三方实现的掘金用户 dashboardnode
项目原由是我忽然想看看掘金站内有哪些优质做者,为了避免错过每个大佬,我选择直接抓取站内全部的文章信息找到做者并进行排名。各位关注 + 文章阅读 一条龙走起!webpack
项目地址 juejin-spider 欢迎 star issueios
掘金 spider 和数据分析,主要关注了下面几个排行和统计,排行点击直接查看git
先上掘金前50排名,关注一波???? 前5000排名看这里程序员
🎉 等级,👦 关注数,🏠公司github
获取掘金站内全部标签信息web
npm run tagList
复制代码
会把标签信息写入到 src/assets/tagList/tagList.json
,每一个标签包含下面的信息,主要是 title
和 id
面试
{
"id": "5597a063e4b08a686ce57030",
"title": "后端",
"createdAt": "2015-07-04T00:59:16Z",
"updatedAt": "2017-06-18T23:34:00Z",
"color": "#C679FF",
"icon": "https://lc-gold-cdn.xitu.io/d83da9d012ddb7ae85f4.png",
"background": "",
"showOnNav": true,
"relationTagId": "",
"alias": "backend houduan",
"isCategory": true,
"entryCount": 19840,
"subscribersCount": 295562,
"isSubscribe": false
},
复制代码
将会采集全站全部标签下面的全部文章,采集过程会由于网速和机器性能表现出差别,请各位耐心等待采集完成
这一步采集的数据很是重要,是后面全部分析的基础
采集到的文件会存放在 src/assets/articleData
下面,包含有不少 json 文件,每一个文件包含这个标签下的全部专栏文章元信息
npm run allTagData
复制代码
数组中每一个对象
{
"collectionCount": 5, // 点赞数
"userRankIndex": 5.4006856695164,
"buildTime": 1565582852.8327,
"commentsCount": 2, // 评论数
"gfw": false,
"objectId": "5d40d29d518825221b4cbb40",
"checkStatus": true,
"isEvent": false,
"entryView": "",
"subscribersCount": 0, // 无用
"ngxCachedTime": 1565627197,
"verifyStatus": true,
"tags": [
{
"ngxCachedTime": 1565627193,
"ngxCached": true,
"title": "React.js",
"id": "555e99ffe4b00c57d99556aa"
}
],
"updatedAt": "2019-08-12T04:07:32.818Z",
"rankIndex": 0.005346156248974,
"hot": false,
"autoPass": false,
"originalUrl": "https://juejin.im/post/5d3ef3646fb9a06b1b1999fd", // 文章的 url
"verifyCreatedAt": "2019-07-31T01:36:14.238Z",
"createdAt": "2019-07-31T01:36:14.238Z",
"user": {
"community": {
"weibo": { "uid": "5345591282", "nickname": "岁月痕迹A88" },
"wechat": {
"avatarLarge": "http://thirdwx.qlogo.cn/mmopen/vi_32/cabLXAUXiavVhiaDh2050AOOEToUvnZTWsSNqqKZC4hzPzHABC7fxwv6VxwebIxfKdaRkYDZoic8UXfonLDyiafuiaw/132"
},
"github": {
"username": "lxfriday",
"avatarLarge": "https://avatars0.githubusercontent.com/u/20264467?v=4",
"uid": "20264467"
}
},
"collectedEntriesCount": 154, // 点赞数
"company": "xxx", // 公司
"followersCount": 35, // 被关注数
"followeesCount": 70, // 关注数
"role": "guest", // 用户角色
"postedPostsCount": 19, // 发布的专栏数
"level": 2, // 用户等级
"isAuthor": false,
"postedEntriesCount": 2, // 分享数?
"totalCommentsCount": 16, // 总评论数
"ngxCachedTime": 1565627197,
"viewedEntriesCount": 1347, // 查看的文章数
"jobTitle": "前端", // 工做:前端
"subscribedTagsCount": 166, // 关注的标签数
"totalCollectionsCount": 120, // 总收藏数
"username": "云影sky", // 用户名
"avatarLarge": "https://user-gold-cdn.xitu.io/2019/7/14/16bf1155693d96c2?w=570&h=488&f=png&s=312610",
"objectId": "57a0c28979bc440054958498" // 用户 id
},
"author": "",
"screenshot": "https://user-gold-cdn.xitu.io/2019/7/29/16c3e3d979a96831?w=1097&h=573&f=png&s=58239",
"original": true,
"hotIndex": 21.2095,
"content": "给 PureComponent 从新指向构造函数以后,_assign 复制对象属性时, Component 构造函数不会覆盖 PureComponent 构造函数,看下面的例子就明白了。 把 PureComponent 变成 Component,userInfo 可正常变化。",
"title": "React 源码系列-Component、PureComponent、function Component 分析",
"lastCommentTime": "2019-08-03T16:53:20.577Z",
"type": "post",
"english": false,
"category": {
"ngxCached": true,
"title": "frontend",
"id": "5562b415e4b00c57d9b94ac8",
"name": "前端",
"ngxCachedTime": 1565627098
},
"viewsCount": 267, // 浏览量
"summaryInfo": "通过 处理以后,三个组件的区别就是 type 不同了 和 看不懂能够看下这篇文章 https://www.zhihu.com/question/34183746 js 中 和 的区别和关系 函数的 属性对象上的 是不可枚举的,因此下面两句 给 PureComponent 从新指向构造函数以后, ...",
"isCollected": false
}
复制代码
获取站内浏览量
npm run follower
复制代码
脚本执行完成会产生两个文件
src/assets/calcUserRank/用户followerRank.json
是排行后的元信息src/assets/calcUserRank/用户followerRank.md
按排名编排的 md 文档获取站内点赞排行
npm run dianzan
复制代码
脚本执行完成会产生两个文件
src/assets/calcDianzanRank/点赞rank.json
是排行后的元信息src/assets/calcDianzanRank/点赞rank.md
按排名编排的 md 文档例子
获取站内浏览量
npm run view
复制代码
脚本执行完成会产生两个文件
src/assets/calcViewRank/浏览量rank.json.json
是排行后的元信息src/assets/calcViewRank/浏览量rank.json.md
按排名编排的 md 文档获取站内浏览量
npm run comment
复制代码
脚本执行完成会产生两个文件
src/assets/calcCommentRank/calcCommentRank.json
是排行后的元信息src/assets/calcCommentRank/calcCommentRank.md
按排名编排的 md 文档async
并发控制chalk
多彩命令行request
发送 http 请求request-promise
把 request promise 化,方便使用 async项目辅助工具 dev assistant
commitlint
规范 commit messageeslint
你们都懂prettier
自动格式化代码husky
提供 git 钩子lint-staged
只对当前变更的文件执行格式化和 eslint 校验jest
测试排序算法正确性构建小顶堆,不断往堆中添加数据,比堆顶小的直接抛弃,比堆顶大的,替换成堆顶并对二叉树进行调整,维持小顶堆。遍历全部数据以后 小顶堆就是咱们要的全部最大值排行,再对这个数组排序依次就能够获取排名了!!!
// 最小值上浮
function heapify(arr, len, i, compareVal) {
let min = i
const l = 2 * i + 1
const r = 2 * i + 2
if (l < len && compareVal(arr[l]) < compareVal(arr[min])) min = l
if (r < len && compareVal(arr[r]) < compareVal(arr[min])) min = r
if (min !== i) {
swap(arr, i, min)
heapify(arr, len, min, compareVal)
}
}
/** * 对 target 建堆 * @param {array} target 堆数组 * @param {*} compareVal 从 dataUnit 对象获取比对值 */
function createHeap(target, compareVal = v => v) {
for (let i = Math.floor((target.length - 1) / 2); i >= 0; i--) {
heapify(target, target.length, i, compareVal)
}
}
function findMaxPrev(dataUnit, target, compareVal = v => v) {
if (compareVal(dataUnit) > compareVal(target[0])) {
target[0] = dataUnit
heapify(target, target.length, 0, compareVal)
}
}
复制代码
👀 浏览量,📌 标签
👍 点赞数,📌 标签
'掘金' === '前端社区'
????
🐶 评论数,📌 标签
分析的内容就是这些了,我还统计了掘金站内的总的文章数和在标签下发布文章的用户总数
看看 npm scripts 开始玩耍吧
npm run all
一行命名抓取数据分析全流程走完,整个流程处理的数据量比较大,须要半个小时左右
"scripts": {
"all": "npm run tagList && npm run allTagData && npm run dianzan && npm run view && npm run comment && npm run follower",
"start": "npm run tagList",
"tagList": "TASK=tagList node App.js",
"allTagData": "TASK=allTagData node App.js",
"composeArticleData": "TASK=composeArticleData node App.js",
"userData": "TASK=userData node App.js",
"dianzan": "TASK=dianzan node App.js",
"view": "TASK=view node App.js",
"comment": "TASK=comment node App.js",
"follower": "TASK=follower node App.js",
"lint": "eslint .",
"test": "jest"
},
复制代码
最后欢迎你们关注个人 github 和 微信公众号