dillywilly
Regular Member
- May 6, 2020
- 250
- 93
Yes, it's fairly straight forward if you spend a day or so understanding the Puppeteer API: https://github.com/puppeteer/puppeteer
Then all you need to do is install Node: https://nodejs.org/en/download/ and run your script. You can write it any editor or IDE, I use JetBrains products, but many people love VSCode which is free: https://code.visualstudio.com/
There are lots of starter scripts that you can find on the Puppeteer repo, but here is my base class that I build my Actors on top of:
Code:const puppeteer = require('puppeteer'); const _ = require('lodash'); class Actor { // ================ Setup ================ browser; page; identity; config; pos; ready = false; /** * Accept construction variables * * @param config * @param identity */ constructor(config, identity) { this.identity = identity; // Login information etc this.config = config; // Platform specific variables } /** * Initialize plugins and set stat to ready * * @returns {Promise<void>} */ async init() { return new Promise(async (resolve, reject) => { try { this.browser = await puppeteer.launch({ headless: false, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36', '--lang=en-US,en;q=0.9' ], userDataDir: this.identity.cookies, // Eg: './storage/identities/username' defaultViewport: this.identity.browser.viewport }); this.page = await this.browser.newPage(); this.ready = true; } catch (error) { reject(this.error(error)); } }); } /** * Your primary browse function, can rename to whatever you like * * @returns {Promise<void>} */ async browse() { return new Promise(async (resolve, reject) => { try { // This is where you would build your bot actions } catch (error) { reject(this.error(error)); } }); } /** * Scroll the page, optionally with a direction or distance * * @returns {Promise<void>} * @param direction * @param distance */ async scroll(direction, distance) { return new Promise(async (resolve, reject) => { try { this.logStart('Scroll'); const noise = this.config.noise; const selectors = this.config.selectors; const viewport = this.identity.browser.viewport; // Limit to viewport let limits = { min: Math.ceil(viewport.height * 0.30), max: Math.ceil(viewport.height * 0.85) }; distance = distance ? distance : _.random(limits.min, limits.max); if (!direction || (direction !== 'up' && direction !== 'down')) { // Roll scroll direction direction = await this.chance(noise.scroll.probability) ? 'down' : 'up'; // Detect header or footer tag const footer = await this.page.$(selectors.footer); if (footer && await footer.isIntersectingViewport()) { direction = 'up'; } else { const header = await this.page.$(selectors.header); if (header && await header.isIntersectingViewport()) { direction = 'down'; } } } distance = direction === 'down' ? distance : (distance * -1); await this.page.evaluate(async distance => { return new Promise((resolve, reject) => { try { window.scrollBy(0, distance); resolve(); } catch (error) { reject(this.error(error)); } }); }, distance); await this.delay(100, 500); resolve(); } catch (error) { reject(this.error(error)); } }); } /** * Handles delays with noise * * @returns {Promise<void>} * @param min * @param max */ async delay(min, max) { return new Promise(async (resolve, reject) => { try { const noise = this.config.noise; let delay = _.random(min ? min : noise.delay.min, max ? max : noise.delay.max); await this.page.waitFor(delay); resolve(); } catch (error) { reject(this.error(error)); } }); } /** * Moves the mouse to a position and adds noise * * @returns {Promise<void>} * @param pos * @param delay */ async moveMouseTo(pos, delay) { return new Promise(async (resolve, reject) => { try { delay = delay ? delay : _.random(10, 80); await this.page.mouse.move(pos.x + _.random(0, 2), pos.y + _.random(0, 2)); await this.delay(delay, (delay + 8)); this.pos = pos; resolve(); } catch (error) { reject(this.error(error)); } }); } /** * Move the mouse a set or random number of times around the page * * @returns {Promise<void>} * @param count */ async randomMouseMovement(count) { return new Promise(async (resolve, reject) => { try { const noise = this.config.noise; await this.delay(50, 80); count = count ? parseInt(count) : _.random(noise.mouse.sequence.min, noise.mouse.sequence.max); for (let i = 0; i < count; i++) { let startPos = await this.getCurrentMousePosition(); let endPos = await this.getRandomMousePosition(); await this.panMouse(startPos, endPos); // You will need to implement your own panning function } await this.delay(50, 1000); resolve(); } catch (error) { reject(this.error(error)); } }); } /** * Select a new random mouse position from within the viewport * * @returns {Promise<void>} */ async getRandomMousePosition() { return new Promise(async (resolve, reject) => { try { const viewport = this.identity.browser.viewport; let pos = { x: Math.ceil(viewport.width * _.random(0.10, 0.90)), y: Math.ceil(viewport.height * _.random(0.10, 0.90)) }; resolve(pos); } catch (error) { reject(this.error(error)); } }); } /** * Finds a dom element on the page * * @returns {Promise<void>} * @param selector */ async getElement(selector) { return new Promise(async (resolve, reject) => { try { const element = (typeof selector === 'string') ? (await this.page.$(selector)) : selector; resolve(element); } catch (error) { reject(this.error(error)); } }); } /** * Gets the x,y position of a dom element * * @returns {Promise<void>} * @param selector */ async getElementPosition(selector) { return new Promise(async (resolve, reject) => { try { const element = await this.getElement(selector); if (element) { const boundingBox = await element.boundingBox(); let pos = { x: Math.ceil(boundingBox.x + (boundingBox.width * _.random(0.3, 0.7))), y: Math.ceil(boundingBox.x + (boundingBox.height * _.random(0.3, 0.7))), }; resolve(pos); } else { resolve(); } } catch (error) { reject(this.error(error)); } }); } /** * Returns the current mouse position or starts at a new position if none found * * @returns {Promise<void>} */ async getCurrentMousePosition() { return new Promise(async (resolve, reject) => { try { let pos = this.pos; if (!(pos && pos.x && pos.y)) { pos = await this.getRandomMousePosition(); this.pos = pos; } resolve(pos); } catch (error) { reject(this.error(error)); } }); } /** * Helper function for handling randomness * * @returns {Promise<void>} * @param probability */ async chance(probability) { return new Promise(async (resolve, reject) => { try { probability = probability ? parseInt(probability) : 50; resolve(!!_.random(0, 100) < probability); } catch (error) { reject(this.error(error)); } }); } /** * Error handler that prints error * * @returns {Promise<void>} * @param error */ error(error) { const string = _.get(error, 'message', error); console.error(string); return error; } } module.exports = Actor;
damn ill check it out thanks