起因
常常在上班的时候沉浸于知识的海洋,导致我无法第一时间收到优惠通知(比如某些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,因为在本地我们需要看到浏览器的动作,服务器上是没有图形化界面的
测试效果如下
接下来就是繁琐的开发测试流程,基本流程就是填写表单,登录网站,跳转对应页面然后通过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
最后就定期检查一下容器的任务执行情况就好了!