掘金签到&邮箱推送结果&阿里云函数自动执行

405 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

最近在看node.js,就想自己找点什么练一练,看到社区有好多「勇(da)士(lao)」在分享《签到》脚本,所以自己也想试一试。

Tips: 主要用于学习,切记不可滥用,官方已经发布公告,禁止脚本签到行为,所以jy一定要注意。

一睹为快

实现的功能

  • 签到
  • 抽奖(要是能一发入魂,中个大奖,上个墙该多好)
  • 沾喜气
  • 邮箱推送结果(因为邮箱免费😶)
  • 脚本自动执行(我用的是阿里云函数)

用到的node相关模块

  • fs : node核心模块之一,具备读写本地文件的能力
  • Nodemailer : 一个简单易用的Node.js邮件发送组件
  • Ejs :可以让JavaScript输出我们所需要的HTML
  • dayjs : Day.js是一个极简的JavaScript库,可以解析、验证、操作和显示日期和时间
  • axios : 基于 promise 的网络请求库

体验一把

  1. 先将项目auto-juejinFork到自己的仓库,然后将代码clone下来,
  2. 安装依赖 npm install
  3. 修改配置文件src/config.js
module.exports = {
  cookie : '',  // 掘金的cookie
  
  // 邮箱信息
  email  : {
    service:'qq',
    user: "xxxxxxx@qq.com",   
    from: "xxxxxxx@qq.com",
    to: "xxxxxx@qq.com",
    pass: "xxxxxxxxxxxxxx"   //邮箱授权码
  }
}
  1. 执行程序,在src目录下执行node index.js
  2. 查看结果
  • 查看终端输出结果 image.png
  • 查看邮件 image.png

获取cookie && 配置邮箱

获取掘金cookie

cookie有过期时间,大概是30天,或者退出登陆也会导致cookie过期。
  1. 登陆进入到掘金,F12(或者鼠标右键-检查)打开控制台
  2. 选择network(网络),随便点击一个接口,找到请求标头中的cookie,选中数据后鼠标右键复制值
  3. 粘贴到src/config.js文件里的cookie image.png

获取邮箱参数-QQ邮箱为例

  1. 登录QQ邮箱(网页版),邮箱设置 - 账户 - 下滑找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
  2. 开启服务,点击生成授权码 image.png
  3. 复制授权码,粘贴到src/config.js文件里的emailpass
  4. emailuserfromto全部填写自己的邮箱地址即可。
  email  : {
    service:'qq',
    user: "123456@qq.com", 
    from: "123456@qq.com",
    to: "123456@qq.com",
    pass: "授权码字符串"  
  }

自己实现

1. 先创建一个空项目

    mkdir auto-juejin
    cd auto-juejin
    npm init

2. 新建src/config.js,用来存放用户的配置信息(cookie和邮箱)。

// src/config.js

// 配置文件,cookie和邮箱配置
module.exports = {
  cookie : '', //设置你自己的cookie
  email  : {
    service:'qq',
    user: "123456@qq.com",     
    from: "123456@qq.com",
    to: "123456@qq.com",
    pass: "xxxxxxxxxxxxx"   //邮箱授权码
  }
}

3. 新建src/api/index.js文件,存放用到的接口地址。

 // src/api/index.js
 
 module.exports = {
  // 请求地址
  baseURL: 'https://api.juejin.cn/',
  // api地址
  api: {
    // 签到
    checkIn: 'growth_api/v1/check_in',
    // 查询签到
    getCheckStatus: 'growth_api/v1/get_today_status',
    // 查询签到天数
    getCheckInDays: 'growth_api/v1/get_counts',
    // 查询当前矿石
    getCurrentPoint: 'growth_api/v1/get_cur_point',
    // 查询抽奖
    getlotteryStatus: 'growth_api/v1/lottery_config/get',
    // 抽奖
    draw: 'growth_api/v1/lottery/draw',
    // 获取沾喜气列表用户
    getLuckyUserList: 'growth_api/v1/lottery_history/global_big',
    // 沾喜气
    dipLucky: 'growth_api/v1/lottery_lucky/dip_lucky'
  },
}
    

4. 新建src/http/index.js文件,封装一个axios实例。

先安装axios插件npm install axios

// src/http/index.js

const axios = require('axios');
const { baseURL } = require('../api/index')
const { cookie } = require('../config')
// 创建axios实例,并配置相关参数
const request = axios.create({
  baseURL,
  method:'get',
  timeout:3000,
  headers:{ cookie }
})

// 响应拦截处理
request.interceptors.response.use(
  (response) => {
    const { data } = response
    if (data.err_msg === 'success' && data.err_no === 0) {
      return data
    } else {
      return Promise.reject(data.err_msg)
    }
  }, 
  (error) => {
    return Promise.reject(error)
  }
)

module.exports = { request }

5. 实现查询是否已经签到的功能,新建src/index.js文件。

// src/index.js

// 引入封装的axios实例request
const { request } =  require('./http/index')

// 导入要用到的api
const { api } = require('./api/index')

/**
 * 查询今天是否已经签到
 *
 * @return {Boolean} 是否签到过
 */
const getCheckStatus = async () => {
  try {
    const { data : isCheckInToday } = await request({ url: api.getCheckStatus})
    // 打印日志
    console.log(`✍️ 今天${isCheckInToday?'已经完成':'尚未进行'}签到 ✍️`);
    return isCheckInToday
  } catch (error) {
    throw `查询签到失败!【${error}】`
  }
}

getCheckStatus().then(res=>{
  console.log("执行getCheckStatus方法",res);
})

6. 现在第一个「查询是否签到」的方法已经写完,我们执行一下程序,看是否能够调通。\

运行 `node src/index.js` \
看到类似结果,则代表我们已经成功调通第一个接口了。
```js
✍️ 今天已经完成签到 ✍️
执行getCheckStatus方法 true
```

7. 实现签到、抽奖、查矿石、沾喜气等功能

// src/index.js
   
/**
 * 查询当前矿石
 */
const getCurrentPoint = async () => {
  try {
    const { data } = await request({ url: api.getCurrentPoint})
    // 打印日志
    console.log(`💎 当前拥有矿石${data}枚 💎`)
  } catch (error) {
    throw `查询矿石失败!${error.err_msg}`
  }
}

/**
 * 查询免费抽奖次数
 * @return {Boolean} 是否有免费抽奖次数
 */
const getlotteryStatus = async () => {
  try {
    const { data } = await request({ url: api.getlotteryStatus})
    // 打印日志
    console.log(`🎟 剩余免费抽奖${data.free_count}次 🎟`);
    return data.free_count 
  } catch (error) {
    throw `查询免费抽奖失败!【${error}】`
  }
}

/**
 * 抽奖
 */
const draw = async () => {
  try {
    // 获取免费次数
    const freeCount = await getlotteryStatus()
    if (freeCount > 0) {
      // 开始抽奖
      const drawRes = await request({ url: api.draw, method: 'post' })
      console.log(`🎉 恭喜抽到【${drawRes.data.lottery_name}】🎉`)
    } else {
      console.log(` 👉👉👉 抽奖任务终止成功 👈👈👈`)
    }
  } catch (error) {
    console.error(`抽奖失败!=======> 【${error}】`)
  }
}

/**
 * 获取沾喜气列表用户historyId
 *
 * @return {string} 被沾的幸运儿的history_id
 */
const getLuckyUserHistoryId = async () => {
  try {
    // 接口为分页查询  默认查询条10条数据 {page_no: 0, page_size: 5}
    const { data } = await request({ url: api.getLuckyUserList , method: 'post'})
    // 生成随机数,用于随机抽取一位被粘用户
    const random = Math.floor(Math.random() * data.lotteries.length ) 
    // // 获取这位幸运用户的history_id
    const { history_id ,user_name} = data.lotteries[random]
    // 打印日志
    console.log(`💃 本次被沾的幸运儿是「${user_name}」 💃`);
    return history_id
  } catch (error) {
    throw `获取沾喜气列表用户historyId失败`
  }
}

/**
 * 沾喜气
 */
const dipLucky = async () => {
  try {
    // 获取historyId
    const historyId = await getLuckyUserHistoryId()
    // 沾喜气接口   传递lottery_history_id
    const { data } = await request({ url: api.dipLucky, method: 'post', data: { lottery_history_id: historyId } })
    // 打印日志
    console.log(`🎉 沾喜气成功,当前幸运值:${data.total_value}/6000 🎉`)
  } catch (error) {
    throw `占喜气失败! ${error}`
  }
}

/**
 * 查询签到天数
 * @return {Object} continuousDay 连续签到天数 sumCount 总签到天数
 */
const getCheckInDays = async () => {
  try {
    const { data } = await request({ url: api.getCheckInDays})
    // 打印日志
    console.log(`🌞『连续签到天数:${data.cont_count}天』『累计签到天数:${data.sum_count}天』🌞`)
    return { contCount: data.cont_count, sumCount: data.sum_count }
  } catch (error) {
    throw `查询签到天数失败!`
  }
}


/**
 * 签到
 */
const checkIn = async () => {
  try {
    // 先判断今天是否已经签到
    const checkStatusRes = await getCheckStatus()
    if (checkStatusRes){
      console.log("👉👉👉 签到任务终止成功 👈👈👈");
    } else {
      // 执行签到程序
      const { data : checkInRes } = await request({ url: api.checkIn, method: 'post' })
      // 打印日志
      console.log(`✅ 签到成功,本次获得${checkInRes.incr_point}矿石,总矿石${checkInRes.sum_point}`)
    }
  } catch (error) {
    console.error(`❗️签到失败!>>>>>>${error}`)
  }
}

8. 实现邮件发送功能

到这所有的功能基本已经写完了,接下来我们实现邮件发送。
先安装nodeMailer插件npm install nodeMailer

// src/index.js

// 邮件发送需要用到我们设置好的邮箱参数和一个nodeMailer插件
const nodeMailer = require('nodemailer');
const { email } = require('./config') 
/**
 * 发送邮件
 */
const sendEmail = async () => {
  try {
    const {service,user,pass,from,to} = email
    const transporter = nodeMailer.createTransport({ service, auth: { user, pass}})
    // 发送邮件
    await transporter.sendMail({ from, to, subject: '邮件发送测试', html: '这是一封神秘的邮件,用于测试。'})
    //打印日志
    console.log(`📨邮件发送成功!`);
  } catch (error) {
    console.error(`邮件发送失败!${error}`)
  }
}

//调用一下,看邮件能否发送成功
sendEmail()

执行程序 node src/index.js
不出意外的话,终端会输出“📨邮件发送成功!”,并且邮箱里能够收到这封测试邮件。


未完待续!