This is the third day of my participation in Gwen Challenge

Code word is not easy, your praise is my motivation to continue to update the creation.

Why

Recently, the company suddenly informed us that we need to make a reservation for dinner one day in advance every day from now on. I don t know why the company made the change, but it did cause a lot of inconvenience. For example, there are many beggars in the group:

Of course, one night when I worked overtime, my partner and I could not have dinner because we did not order food in advance, so we could only eat our own bread silently.

As the saying goes, who pain who work! As a code of the new era of agriculture, in the automation is not manual, intelligent is not automatic brilliant thought shining, thinking can order this thing to the program to do it?

The answer, of course, is yes.

How

First of all, the ordering page is analyzed and found to be a simple form. Then, I remember that in the technical sharing of the team partner, Google mentioned a Node library for Controlling Headless Chrome — Puppeteer by DevTools protocol, which feels interesting.

Puppeteer

Puppeteer is similar to other frameworks that manipulate the Browser by manipulating instances of the Browser to react accordingly, see the following example code:

const puppeteer = require('puppeteer');

(async() = > {const browser = await puppeteer.launch(); // Start a browser and return to the browser instance
  const page = await browser.newPage(); // Create a new page instance, similar to a TAB in Chrome
  await page.goto('http://rennaiqian.com'); // Page jump
  await page.screenshot({path: 'example.png'}); // Take a screenshot and save it locally
  await page.pdf({path: 'example.pdf'.format: 'A4'}); // Generate a PDF and save it locally
  await browser.close(); // Automatically close the browser}) ();Copy the code

From this we can open the order page, but how to enter the data in the page form?

page.type('.field_2', name, {delay: 100}); 
Copy the code

This can be done using the method type on the page instance. The three parameters of type are defined as:

  • Selector, the same syntax as jQuery selector;
  • The value assigned to the input field;
  • Some other options may be empty.delay: 100Indicates the interval between each input100Ms;

With that in mind, let’s get started!

Order a meal

const puppeteer = require('puppeteer');
const utils = require('./utils');

/** ** order *@param {string} The name name *@param {string} JobNo gonghaowu * /
async function order(name, jobNo) {
  const browser = await puppeteer.launch({headless: false});
  const page = await browser.newPage();
  await page.goto('https://xxxxxxxxx.xxxxxx/xxxxxx'); // The reservation website
  await page.type('.field_2', name, {delay: 100}); 
  await page.type('.field_6', jobNo, {delay: 100});
  const tomorrowStr = utils.getTomorrowStr(); // Get tomorrow's date
  await page.type('.ant-picker-input > input', tomorrowStr);
  await page.click('.field_5 div:nth-child(5)');
  await page.click('.published-form__footer-buttons > button');
  await page.waitForNavigation();
  const clip = await page.evaluate(() = > {
    let {
        x,
        y,
        width,
        height
    } = document.querySelector('.code-info').getBoundingClientRect();
    return {
        x,
        y,
        width,
        height
    };
  });
  await page.waitFor(1000);
  const fileName = `${name}_${tomorrowStr}`;
  await page.screenshot({ path: `./screenshot/${fileName}.png`, clip });
  await page.waitFor(1000);
  browser.close();
  return fileName;
}

module.exports = {
  order,
}
Copy the code

Through the above code can save the order code to the local, but it is still not very convenient, every day to send from the computer to the mobile phone, so I thought of the robot.

Notification of successful reservation

Through checking the API, I found that if you send pictures, it must be an online link of the picture. How to convert local pictures into online links? Buy an Aliyun! Well! In this way, I can upload pictures to OSS to generate online links. Fortunately, I already have Ali Cloud, so I think about it and save more than 1000 yuan.

const OSS = require('ali-oss');
const fs = require('fs');

async function uploadToOSS(fileName) {
  const client = new OSS({
    region: 'oss-cn-beijing'.accessKeyId: 'accessKeyId'.accessKeySecret: 'accessKeySecret'.bucket: 'roc-auto-order'});const path = `./screenshot/${fileName}.png`;
  const result = await client.putStream(`${fileName}.png`, fs.createReadStream(path));
  return client.signatureUrl(result.name, { expires: 604800 }); / / 7 days
}

module.exports = {
  uploadToOSS
};
Copy the code

Directly call ali-OSS to complete the image upload and get the image link, which will be used for the next nail push.

const request = require('request');

function pushDingding(fileName, picUrl){
  const url = 'https://oapi.dingtalk.com/robot/send?access_token=ACCESS_TOKEN';
  const data = {
    "msgtype": "markdown"."markdown": {
        "title":"Reservation successful"."text": ` # # #${fileName}Reservation success \n>! [screenshot](${picUrl})\n> `
    },
     "at": {
        "isAtAll": false}};return new Promise(function(resolve, reject) {
    request({
      url: url,
      method: "POST".json: true.headers: {
          "content-type": "application/json",},body: data
    }, function(error, response, body) {
        if(! error && response.statusCode ==200) { resolve(); }}); }); };module.exports = {
  pushDingding,
}
Copy the code

Timing schedule

After the above operation, it is possible to automatically place an order when executing, but I want to place an order at 12:00 noon every day. I don’t need to operate it. How to deal with it?

const schedule = require('node-schedule');
const autoOrder = require('./auto-order');
const fileUpload = require('./file-upload');
const messagePush = require('./message-push');
const config = require('./config');
const utils = require('./utils');

async function doTask() {
  for(const one of config.personList) {
    const fileName = await autoOrder.order(one.name, one.jobNo);
    const picUrl = awaitfileUpload.uploadToOSS(fileName); messagePush.pushDingding(fileName, picUrl); }}function scheduleObjectLiteralSyntax() {
  // From Monday to Friday at 12:30 p.m
  schedule.scheduleJob('0 30 12 * * 1-5'.() = > {
    utils.delDir('.. /screenshot');
    doTask();
  });
}

scheduleObjectLiteralSyntax();
Copy the code

The last

Finally, use PM2 to start the above file.

results