记录一次使用 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 ./ 文件名,的方式启动,以上代码并不能直接运行,需自己修改一些,仅本人记录使用

原文地址:https://www.cnblogs.com/SuperBrother/p/15688310.html