UNPKG

multi-automator

Version:
282 lines (281 loc) 8.42 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * @desc: Web Handler * @author: john_chen * @date: 2023.03.13 */ const fs_1 = require("fs"); const puppeteer_core_1 = __importStar(require("puppeteer-core")); const Element_1 = __importDefault(require("./Element")); const config_1 = require("../config"); ; /** * web 操控类 */ class WebHandler { /** * Web Operator * * @param {string} browserPath 浏览器地址,默认使用 chromium 地址 */ constructor(browserPath) { this.emulate = false; this.model = 'Galaxy S5'; this.browserPath = browserPath; this.launchOptions = {}; this.browser = null; this.page = null; this.screenSize = null; } /** * init 参数处理 * * @param launchOptions LaunchOptions */ checkInitOptions(launchOptions) { launchOptions = launchOptions || {}; const { headless = true, devtools = false, defaultViewport = null, args = ['--start-fullscreen'], ignoreDefaultArgs = ['--enable-automation', '--enable-blink-features=IdleDetection'] } = launchOptions; this.launchOptions = { executablePath: this.browserPath, headless, devtools, defaultViewport, args, ignoreDefaultArgs }; } /** * init Web operator * * @param {boolean} headless 是否采用无头方案 * @param {boolean} devtools 是否启用调试工具 * @param {array{object}} cookies 需要设置的 cookies * @param {string} emulate 是否开启设备模拟 * @param {object} headers headers */ async init(launchOptions, cookies, emulate = false, headers) { config_1.logger.info('[web.init]'); await this.close(); // 初始化浏览器实例 this.checkInitOptions(launchOptions); this.browser = await puppeteer_core_1.default.launch(this.launchOptions); // 初始化页面实例 let pages = await this.browser.pages(); this.page = pages[0]; // 选定设备型号 if (emulate) { this.emulate = true; // @ts-ignore await this.page.emulate(puppeteer_core_1.KnownDevices[this.model]); } // 设置 cookie if (undefined !== cookies && cookies.length > 0) { for (let cookie of cookies) { await this.page.setCookie(cookie); } } // 设置 header if (undefined !== headers) { await this.page.setExtraHTTPHeaders(headers); } } /** * 通过 xpath 获取元素操作对象列表 * * @param {string} expression XPath表达式 * @returns {Promise<Array<ElementHandle>>} */ async $x(expression) { let result = await this.page.$x(expression); let elements = []; for (let element of result) { elements.push(new Element_1.default({ device: this, element, })); } return elements; } /** * 通过 CSS 选择器获取元素操作对象 * * @param selector CSS 选择器 * @returns {Promise<ElementHandle|null>} */ async $(selector) { let element = await this.page.$(selector); if (null === element) { return null; } return new Element_1.default({ device: this, element, }); } /** * 通过 CSS 选择器获取元素操作对象列表 * * @param selector CSS 选择器 * @returns {Promise<Array<ElementHandle>>} */ async $$(selector) { let result = await this.page.$$(selector); let elements = []; for (let element of result) { elements.push(new Element_1.default({ device: this, element, })); } return elements; } /** * 屏幕点击 * * @param {number} x 横坐标 * @param {number} y 纵坐标 * @return <Promise> */ async tap(x, y) { let res = await this.page.touchscreen.tap(x, y); return res; } /** * 页面滑动 * * @param {number} fx 起点横坐标 * @param {number} fy 起点纵坐标 * @param {number} tx 终点横坐标 * @param {number} ty 终点纵坐标 */ async swipe(fx, fy, tx, ty) { await this.page.mouse.move(fx, fy); await this.page.mouse.wheel({ deltaX: fx - tx, deltaY: fy - ty }); } /** * 跳转 HTTP 地址 * * @param {string} path url 路径 * @returns {string} */ async goto(path = '') { for (let index = 0; index < 3; index++) { try { await this.page.goto(path, { waitUntil: 'networkidle2' }); break; } catch (err) { config_1.logger.error(`[web.goto] page.goto fail ${index + 1} times: ${err.message}`); continue; } } return path; } /** * 获取页面宽高 * * @return {object} screenSize * @return {number} screenSize.width 宽度,单位是像素 * @return {number} screenSize.height 高度,单位是像素 */ async getScreenSize() { if (this.emulate) { let res = await this.page.viewport(); if (null === this.screenSize) { this.screenSize = { width: res.width * res.deviceScaleFactor, height: res.height * res.deviceScaleFactor, }; } } else { let { width, height } = await this.page.evaluate(() => { return { width: window.innerWidth, height: window.innerHeight, deviceScaleFactor: window.devicePixelRatio, }; }); this.screenSize = { width, height, }; } return this.screenSize; } /** * 截图 * * @param {string} path 图片路径 * @returns {Promise{Buffer|String}} */ async screenshot(path) { let res = await this.page.screenshot(path); if (path) { (0, fs_1.writeFileSync)(path, res); } return res; } /** * 页面 dom 树 * * @return <Promise{string}> */ async source() { let res = await this.page.content(); return res; } /** * browser version * * @returns {string} 浏览器版本号 */ async version() { let res = await this.browser.version(); let version = res.split('/')[1]; return version; } /** * 关闭设备 */ async close() { config_1.logger.info('[web.close]'); if (this.page && this.page.close) { await this.page.close(); this.page = null; } if (this.browser && this.browser.close) { await this.browser.close(); this.browser = null; } } } exports.default = WebHandler; ;