为了准时收到优惠通知,我决定......

211 阅读4分钟

起因

常常在上班的时候沉浸于知识的海洋,导致我无法第一时间收到优惠通知(比如某些yh的立减金兑换...), 因此愤怒的我决定做一个可以定时爬取优惠网站,然后判定有新优惠之后给我邮箱发邮件通知的脚本,说干就干!

开发

首先寻找一个爬虫框架

因为我的技术栈是node方向,在基于不给自己找事的原则上,就近找到了puppeteer和playwright两种,最后选择了playwright,原因也很简单,playwright使用起来感觉会比较顺滑一些,虽然两者在api方面差距不是很大

写一个基础例子测试试试

const { chromium } = require('playwright')
(async () => {
  const browser = await chromium.launch({ headless: false })
  const context = await browser.newContext()
  const page = await context.newPage()
  try {
    // 打开目标页面
    await page.goto('https://www.xx.com/')
    // 等待按钮加载完成
    await page.waitForSelector('.a-close') // 这里假设按钮是一个 <button> 元素
    // 获取按钮元素
    const button = await page.$('.a-close')
    if (button) {
      // 点击按钮
      await button.click({ noWaitAfter: false })
      console.log('按钮已被点击')
    } else {
      console.log('找不到按钮')
    }
  } catch (error) {
    console.error('发生错误:', error)
  }
})()

刚开始需要把headless这个属性设置为false,但是后面上服务器的时候需要用true,因为在本地我们需要看到浏览器的动作,服务器上是没有图形化界面的

测试效果如下

image.png

接下来就是繁琐的开发测试流程,基本流程就是填写表单,登录网站,跳转对应页面然后通过dom节点获取数据(也可以监听接口),鉴于过审原因,代码就不放出了,有兴趣的后台找我

这里还有一个问题,既然是要定时爬取,那么肯定离不开定时任务了,我用的是node的一个库叫做node-cron 这个库还是比较好用的

使用方法

const cron = require('node-cron')

cron.schedule('*/15 * * * *', async () => {
    // 执行任务
}) // 每15分钟执行一次

前面可以看到我的代码都是用require引入的,并没有采用import,因为只是在一个js文件里面写,没有去配置es6,不过问题不大,数据库方面因为数据量不大,也就一张表,其实随便用一个都可以实现,这里就略过了

配置好定时任务之后,就需要上服务器运行任务了,因为我们总不可能让任务一直在本地跑保持电脑不关机(其实感觉也不是不行

之前一直采用的是pm2方法来跑脚本的,但是一直感觉不得劲,这次采用的是docker运行方式

首先我们需要一个dockerfile文件用于docker打包成容器,这中间还是会有问题的,最后经过多次测试有了这份dockerfile文件

FROM node:18

# 设置工作目录
WORKDIR /usr/src/app

# 创建新的 sources.list 文件
RUN echo "deb http://mirrors.aliyun.com/debian/ buster main contrib non-free" > /etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/debian/ buster-updates main contrib non-free" >> /etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/debian-security/ buster/updates main" >> /etc/apt/sources.list && \
    apt-get update && apt-get install -y \
        libnss3 \
        libnspr4 \
        libdbus-1-3 \
        libatk1.0-0 \
        libatk-bridge2.0-0 \
        libcups2 \
        libdrm2 \
        libxkbcommon0 \
        libxcomposite1 \
        libxdamage1 \
        libxfixes3 \
        libxrandr2 \
        libgbm1 \
        libasound2 \
        libatspi2.0-0 \
    && rm -rf /var/lib/apt/lists/*

# 复制 package.json 和 package-lock.json
COPY package*.json ./

# 设置 npm 镜像源
RUN npm config set registry https://registry.npmmirror.com

# 安装依赖
RUN npm install

# 下载 Playwright 浏览器
RUN npx playwright install

# 复制项目文件
COPY . .

# 运行应用
CMD ["node", "index.js"]  # 替换为你的主文件名

中间那一大堆都是playwright运行的时候报缺失依赖的问题所以加上的,最后的CMD这里是容器打包好后的执行方式,我这里是因为写在index.js文件中,所以执行直接就是node index.js,如果是在nestjs这种框架中,就可以去执行package.json下的脚本命令来启动项目

最后把写好的文件往服务器找一个文件夹放,然后运行

docker build -t 构建的镜像名称 .

构建完毕之后运行

docker run -d --name 容器名称 --restart always 构建的镜像名称

--restart always命令是在docker容器中的任务执行失败的时候自动重启容器,亲测是可以自动重启的,有时候脚本也会执行错误,通过这个命令可以查看容器的重启次数

docker inspect 容器id | grep RestartCount

最后就定期检查一下容器的任务执行情况就好了!