当前位置:   article > 正文

掘金签到linux版selenium

掘金签到linux版selenium

仅供学习,请勿用于非法用途

安装linux版chromedriver和linux版chrome

#!/usr/bin/env sh
 
# 确保脚本抛出遇到的错误
set -e

echo "安装chromedriver"
wget https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/119.0.6045.105/linux64/chromedriver-linux64.zip
unzip chromedriver-linux64.zip
cd chromedriver-linux64
chmod 777 chromedriver

cd ../
echo "安装chrome"
wget https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/119.0.6045.105/linux64/chrome-linux64.zip
unzip chrome-linux64.zip
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

功能实现

  1. 使用selenium抓取掘金登录的二维码,使用稀土掘金app扫二维码登录
  2. html页面提供两个按钮,一个登录,一个查看登录状态

使用nest实现

创建项目

nest new juejin-tool
  • 1

安装依赖包

pnpm i @nestjs/config @nestjs/schedule cron@3.1.3 @types/selenium-webdriver selenium-webdriver
  • 1

@nestjs/config:从.env中读取配置

@nestjs/schedule:提供nest定时任务模块

cron:nest定时任务模块依赖包

selenium-webdriver:操作selenium

@types/selenium-webdriver:提供selenium使用的类型

开发模式启动服务

npm run start:dev
  • 1

访问localhost:3000,以下页面为启动成功

启动nest服务

前端提供两个按钮调用后端接口

后端提供两个接口,一个接口登录,一个接口获取当前登录状态

前端实现:

项目根路径下创建public文件夹,将文件夹作为静态资源目录

修改main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  // 支持静态资源访问并指定地址前缀为static(需要给create传入NestExpressApplication泛型参数才有useStaticAssets方法)
  app.useStaticAssets('public', { prefix: '/pages' });
  await app.listen(3000);
}
bootstrap();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在public文件夹下创建index.html文件,代码如下

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>掘金工具(自动签到)</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.min.js"></script>
</head>

<body>
  <button id="login">登录</button>
  <button id="get-login-status">查询登录状态</button>
  <div id="content">
  </div>
  <script>
    // 登录
    const loginButton = document.getElementById("login")
    const content = document.getElementById("content")
    loginButton.addEventListener("click", () => {
      content.innerHTML = '请求发送中...'
      axios({
        url: "/juejin/login"
      }).then(res => {
        console.log(res.data)
        if (res.data === '已登录') {
          content.innerHTML = "已登录"
          return
        }
        content.innerHTML = `请在20s内使用稀土掘金app扫以下二维码<br/><img src="${res.data}" />`
      })
    })
    // 获取登录状态
    const loginStatusButton = document.getElementById("get-login-status")
    loginStatusButton.addEventListener("click", () => {
      content.innerHTML = '请求发送中...'
      axios({
        url: "/juejin/login/status"
      }).then(res => {
        content.innerHTML = `当前登录状态为:${res.data}`
      })
    })
  </script>
</body>

</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

将localhost:3000指向这个页面

修改app.controller.ts文件

import { Controller, Get, Res } from '@nestjs/common';
import { AppService } from './app.service';
import { Response } from 'express';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(@Res() res: Response) {
    // return this.appService.getHello();
    res.redirect('/pages/index.html');
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

后端实现

根目录下创建.env文件添加三行配置

# chromedriver文件路径
CHROME_DRIVER_PATH=
# chrome二进制文件路径
CHROME_BINARY_PATH=
# chrome用户数据存储路径(为了保存掘金用户登录session)
CHROME_USER_DATA_DIR=
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用nest-cli生成junjin接口目录和selenium服务目录

nest g service selenium
nest g resource juejin
  • 1
  • 2

修改app.module.ts引入配置模块和定时任务模块

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SeleniumService } from './selenium/selenium.service';
import { JuejinModule } from './juejin/juejin.module';
import { ScheduleModule } from '@nestjs/schedule';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [JuejinModule, ScheduleModule.forRoot(), ConfigModule.forRoot()],
  controllers: [AppController],
  providers: [AppService, SeleniumService],
})
export class AppModule {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

修改selenium.service.ts文件

import { Injectable } from '@nestjs/common';
import { Builder, ThenableWebDriver } from 'selenium-webdriver';
import { Options, ServiceBuilder } from 'selenium-webdriver/chrome';

@Injectable()
export class SeleniumService {
  webdriver(): ThenableWebDriver {
    // 创建一个webdriver示例
    const webdriver = new Builder();
    // 创建一个remote.DriverService实例在一个子进程中管理ChromeDriver
    const serviceBuilder = new ServiceBuilder(process.env.CHROME_DRIVER_PATH);
    const chromeOptions = new Options();
    chromeOptions
      .addArguments(
        '--no-sandbox',
        `--user-data-dir=${process.env.CHROME_USER_DATA_DIR}`, // 设置用户数据存储路径
        'user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', // 模拟ua
      )
      .headless() // 无头模式启动
      .setChromeBinaryPath(process.env.CHROME_BINARY_PATH);
    webdriver
      .forBrowser('chrome')
      .setChromeOptions(chromeOptions)
      .setChromeService(serviceBuilder);
    return webdriver.build();
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

修改juejin.module.ts文件

import { Module } from '@nestjs/common';
import { JuejinService } from './juejin.service';
import { JuejinController } from './juejin.controller';
import { SeleniumService } from 'src/selenium/selenium.service';

@Module({
  controllers: [JuejinController],
  // 在juejin module中注册selenium service
  providers: [JuejinService, SeleniumService],
})
export class JuejinModule {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

修改jujin.controller.ts文件

import { Controller, Get } from '@nestjs/common';
import { JuejinService } from './juejin.service';

@Controller('juejin')
export class JuejinController {
  constructor(private readonly juejinService: JuejinService) {}

  // 掘金登录
  @Get('login')
  login() {
    return this.juejinService.login();
  }

  // 获取当前用户登录状态
  @Get('login/status')
  loginStatus() {
    return this.juejinService.getStatus();
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

修改juejin.service.ts文件

import { Inject, Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { By } from 'selenium-webdriver';
import { SeleniumService } from 'src/selenium/selenium.service';

@Injectable()
export class JuejinService {
  @Inject(SeleniumService)
  seleniumService: SeleniumService;

  // 登录功能
  async login() {
    const webdriver = this.seleniumService.webdriver();
    await webdriver.get('https://juejin.cn/');
    try {
      const loginbutton = webdriver.findElement(By.className('login-button'));
      await loginbutton.click();
      await webdriver.sleep(5000);
      const qrimg = webdriver.findElement(By.className('qrcode-img'));
      const qrimgData = await qrimg.getAttribute('src');
      setTimeout(async () => {
        await webdriver.quit();
      }, 20 * 1000);
      return qrimgData;
    } catch (e) {
      await webdriver.quit();
      return '已登录';
    }
  }

  // 查看当前登录状态
  async getStatus() {
    console.log('获取当前登录状态');
    const webdriver = this.seleniumService.webdriver();
    await webdriver.get('https://juejin.cn/user/center/signin?avatar_menu');
    try {
      const username = await webdriver.findElement(
        By.className('login-user-name'),
      );
      const usernameText = await username.getText();
      console.log(usernameText);
      await webdriver.quit();
      return '未登录';
    } catch (e) {
      await webdriver.sleep(3000);
      const username = await webdriver.findElement(By.className('username'));
      const usernameText = await username.getText();
      await webdriver.quit();
      return `已登录,用户名为:${usernameText}`;
    }
  }

  // 定时签到抽抽奖(每天上午10点)
  @Cron(CronExpression.EVERY_DAY_AT_10AM)
  async signIn() {
    console.log('定时签到抽奖');
    const webdriver = this.seleniumService.webdriver();
    await webdriver.get('https://juejin.cn/user/center/signin?avatar_menu');
    await webdriver.sleep(5 * 1000);
    console.log('点击签到按钮');
    let button = await webdriver.findElement(By.css('.code-calender .signin'));
    await button.click();
    await webdriver.sleep(5 * 1000);
    console.log('点击去抽奖');
    button = await webdriver.findElement(By.css('.btn-area .btn'));
    await button.click();
    await webdriver.sleep(5 * 1000);
    console.log('点击免费抽奖');
    button = await webdriver.findElement(By.css('.cost-box #turntable-item-0'));
    await button.click();
    await webdriver.sleep(5 * 1000);
    console.log('点击收下奖励');
    button = await webdriver.findElement(
      By.css('.byte-modal__body .wrapper .submit'),
    );
    await button.click();
    await webdriver.sleep(5 * 1000);
    await webdriver.quit();
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

完整代码:https://gitee.com/xianyu10086/juejin-tool

linux使用

linux部署

# 克隆代码
git clone https://gitee.com/xianyu10086/juejin-tool
# 切换目录
cd juejin-tool
# 安装依赖包
pnpm i
# 安装chrome和chromedriver
bash install.sh
# 配置.env
vim .env
# 打包
npm run build
# pm2 守护进程启动
pm2 start npm --name juejin-tool -- run start:prod
# pm2 查看日志
pm2 logs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

修改.env配置

遇到的问题

chrome和chromedriver报错,一般是因为缺少库,使用chromedriver -v 和 chrome -v查看缺少哪些库文件,然后百度安装,我遇到的缺少问题如下

问题:error while loading shared libraries: libnss3.so

yum install nss
  • 1

问题: error while loading shared libraries: libatk-bridge-2.0.so.0

yum install at-spi2-atk
  • 1

问题:error while loading shared libraries: libgbm.so.1

yum install libgbm*
  • 1

问题:error while loading shared libraries: libasound.so.2

yum install alsa-lib-devel
  • 1

问题:error while loading shared libraries: libxkbcommon.so.0

yum install libxkbcommon
  • 1

访问 服务器ip:3000

访问服务器ip:3000

扫完之后,稍等几秒,点击查询登录状态

查询登录状态

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号