记录一次使用 puppeteer 爬 微信小程序发布平台
以下代码主要功能为 爬取 微信小程序开发者平台页面,实现登录,发送二维码,点击版本管理等点击操作
const util = require('./utilVes5')
const puppeteer = require('puppeteer')
const fs = require('fs')
const { exit } = require('process')
const path = require('path')
const db = require('./dbVes5')
const wxWorkServerHost = 'http://00.0.0.0:0000'
const wxWorkNotification = async ({ content, image, touser }) => {
if (content) {
await util.req('POST', `${wxWorkServerHost}/api/txt`, { content, touser }, {})
}
if (image) {
await util.req('POST', `${wxWorkServerHost}/api/image`, {}, {}, { json: null, body: null, headers: { 'content-type': 'multipart/form-data' }, formData: { touser, file: fs.createReadStream(image) } })
}
}
(async () => {
await db.init()
const col = db.getCol('user')
const cursor = await col.find()
const list = await cursor.toArray()
const enameList = []
list.forEach(item => {
if (item.role && item.role.admin && item.role.admin.indexOf('super') !== -1) enameList.push(item.ename)
})
if (enameList.length === 0) exit(0)
try {
const browser = await puppeteer.launch({
// 是否开启无头模式
headless: true
})
const page = await browser.newPage()
// 打开页面
await page.goto('https://mp.weixin.qq.com', {
waitUntil: 'networkidle2'
})
const selectType = await page.$$('.login__type__container__select-type')
// 点击使用账户登录
await selectType[1].click()
const formInput = await page.$$('.weui-desktop-form__input')
const $username = formInput[0]
const $password = formInput[1]
// 输入账户
await $username.type('xxxxx@qq.com')
// 输入密码
await $password.type('xxxxxxx')
const btnLogin = await page.$('.btn_login')
// 点击登录
await btnLogin.click()
// 等待登录,加载二维码
await page.waitForNavigation({
waitUntil: 'networkidle0'
})
// 保存截图,备企业微信发送图片使用
await page.screenshot({ path: path.join(__dirname, '../../static/logQRCode.png') })
enameList.forEach(async ename => {
await wxWorkNotification({content: '小程序自动发布,请扫码登录', touser: ename, image: path.join(__dirname, '../../static/logQRCode.png')})
})
// 设置页面超时时间为半小时
page.setDefaultNavigationTimeout(1800000)
// 等待扫描二维码跳转页面
await page.waitForNavigation({
waitUntil: 'networkidle0'
})
const menuItem = await page.$$('.menu_item')
// 点击版本管理
await menuItem[0].click()
// 恢复页面默认等待超时时间
page.setDefaultNavigationTimeout(30000)
// 等待页面渲染完毕
await page.waitForNavigation({
waitUntil: 'networkidle0'
})
// 获取所有 class 名为 code_version_log 的元素
const codeVersionLog = await page.$$('.code_version_log')
codeVersionLog.forEach(async parent => {
// 查找名为 simple_preview_value的子级,是否满足 text 等于 uat
const isUat = await parent.$$eval('.simple_preview_value', node => {
for (let i = 0; i < node.length; i++) {
if (node[i].innerText.indexOf('UAT') !== -1) return true
}
})
// 查找名为 weui-desktop-btn的子级,是否满足 text 等于 提交审核
const isTop = await parent.$$eval('.weui-desktop-btn', node => {
for (let i = 0; i < node.length; i++) {
if (node[i].innerText === '提交审核') return true
}
})
if (isUat && isTop) {
// 如果两者同时满足,点击提交审核按钮
const weuiDesktopBtn = await parent.$('.weui-desktop-btn')
await weuiDesktopBtn.click()
}
})
// 延时 3500 毫秒,等待弹窗弹出
await page.waitForTimeout(3500)
// 获取所有名为 weui-desktop-dialog 的元素
const weuiDesktopDialog = await page.$$('.weui-desktop-dialog')
for (let p = 0; p < weuiDesktopDialog.length; p++) {
const parent = weuiDesktopDialog[p]
const text = await parent.$eval('h3', async node => {
return node.innerText
})
if (text === '提交审核') {
const weuiDesktopBtn = await parent.$('.weui-desktop-btn')
await weuiDesktopBtn.click()
break
}
}
// 延时 3500 毫秒,等待弹窗更新
await page.waitForTimeout(3500)
for (let p = 0; p < weuiDesktopDialog.length; p++) {
const parent = weuiDesktopDialog[p]
const text = await parent.$eval('h3', async node => node.innerText)
if (text === '提交审核的相关须知') {
const checkLabel = await parent.$('.weui-desktop-form__check-label')
await checkLabel.click()
await page.waitForTimeout(600)
const mr = await parent.$('.mr')
await mr.click()
break
}
}
const weuiDesktopDialogV2 = await page.$$('.weui-desktop-dialog')
const newPagePromise = new Promise(resolve => browser.once('targetcreated', target => resolve(target.page())))
let newPage = ''
// 延时 3500 毫秒,等待弹窗更新
await page.waitForTimeout(3500)
for (let p = 0; p < weuiDesktopDialogV2.length; p++) {
const parent = weuiDesktopDialogV2[p]
const text = await parent.$eval('h3', async node => node.innerText)
if (text === '代码提醒') {
const btnPrimary = await parent.$('.weui-desktop-btn_primary')
await btnPrimary.click()
// 点击提交审核后页面有跳转,将当前page对象抓取为新页面对象
newPage = await newPagePromise
await page.close()
break
}
}
// 等待页面渲染完毕
await newPage.waitForNavigation({
waitUntil: 'networkidle0'
})
// 点击提交审核
const btnPrimary = await newPage.$('.btn_primary')
await btnPrimary.click()
enameList.forEach(async ename => {
await wxWorkNotification({content: '小程序提交审核成功', touser: ename})
})
await newPage.close()
// 强制结束node 进程
exit(0)
} catch (e) {
enameList.forEach(async ename => {
await wxWorkNotification({content: '小程序自动提交审核失败, 请手动提交审核', touser: ename})
})
exit(0)
}
})()
用 node ./ 文件名,的方式启动,以上代码并不能直接运行,需自己修改一些,仅本人记录使用
浙公网安备 33010602011771号