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: 100
Indicates the interval between each input100
Ms;
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.