| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- const net = require('net')
- const CDP = require('chrome-remote-interface')
- const chromeFinder = require('chrome-finder')
- const {
- exec,
- spawn,
- } = require('child_process')
- const path = require('node:path')
- const os = require('node:os')
- class WebDriver {
- constructor (params = {
- args: [],
- host: '127.0.0.1',
- port: 0,
- chromePath: '',
- userDataDir: '',
- }) {
- this.args = params.args || []
- this.host = params.host || '127.0.0.1'
- this.port = params.port || 0
- this.chromePath = params.chromePath || ''
- this.userDataDir = params.userDataDir || ''
- }
- headless () {
- this.args.push('--headless=old')
- }
- getCDP () {
- return this.cdp
- }
- setProxy (proxy) {
- this.args.push(`--proxy-server=${proxy}`)
- }
- addArguments (arg) {
- if (arg) {
- this.args.push(arg)
- } else {
- throw new Error('Arguments cannot be null')
- }
- }
- setChromeBinaryPath (binaryPath) {
- this.chromePath = binaryPath
- }
- setUserDataDirPath (binaryPath) {
- this.userDataDir = binaryPath
- }
- async builder () {
- try {
- if (!this.port) {
- this.port = await this.isPortTaken(this.getRandomNumber())
- }
- if (!this.chromePath) {
- this.chromePath = chromeFinder()
- }
- if (!this.userDataDir) {
- this.userDataDir = path.join(os.tmpdir(), `scoped_dir${new Date().getTime()}`)
- }
- console.info('启动端口:', this.port)
- const command = `${this.chromePath}`
- const args = [
- `--user-data-dir=${this.userDataDir}`,
- `--disk-cache-dir=${this.userDataDir}`,
- `--remote-debugging-port=${this.port}`,
- '--no-first-run',
- '--no-dleck',
- '--disable-plugins',
- '--no-default-browser-check',
- '--new-tab',
- // 'data:,',
- ]
- const mergedArray = args.concat(this.args)
- const { spawn } = require('child_process')
- return new Promise((resolve, reject) => {
- const childProcess = spawn(command, mergedArray)
- childProcess.stderr.on('data', async (data) => {
- await this.connectToChrome(1, this.port)
- resolve(true)
- })
- childProcess.on('close', (code) => {
- console.info(`子进程退出成功,退出码: ${code}`)
- })
- childProcess.on('error', (err) => {
- console.error(`子进程错误:${err.message}`)
- })
- })
- } catch (e) {
- console.error(e)
- }
- }
- createCDPConnection () {
- return {
- host: this.host,
- port: this.port,
- }
- }
- checkBrowser () {
- return !!(this.chromePath || chromeFinder())
- }
- isPortTaken (port) {
- return new Promise((resolve) => {
- const server = net.createServer()
- server.on('listening', () => {
- server.close(() => {
- resolve(port)
- })
- })
- server.on('error', async () => {
- this.isPortTaken(port + 1).then(resolve)
- })
- server.listen(port, '127.0.0.1')
- })
- }
- async connectToChrome (time, port) {
- const waitingTime = {
- 1: 1000,
- 2: 3000,
- 3: 5000,
- 4: 10000,
- }
- if (!this.cdp) {
- try {
- this.cdp = await CDP({ port })
- console.info('CDP 连接成功')
- } catch (error) {
- console.error('连接失败,正在重试...')
- await new Promise(resolve => setTimeout(resolve, waitingTime[time]))
- if (time < 4) {
- await this.connectToChrome(time + 1, port)
- } else {
- await this.quit()
- await this.builder()
- }
- }
- }
- }
- getRandomNumber () {
- return Math.floor(Math.random() * (65535 - 10000 + 1)) + 10000
- }
- quit () {
- const command = `netstat -ano | findstr LISTENING | findstr :${this.port}`
- return new Promise((resolve, reject) => {
- exec(command, (error, stdout, stderr) => {
- if (error) {
- resolve(`执行命令时出错: ${error}`)
- return
- }
- const lines = stdout.split('\n')
- const processIds = []
- lines.forEach((line) => {
- const parts = line.trim().split(/\s+/)
- if (parts.length >= 2) {
- const pid = parts[parts.length - 1]
- processIds.push(pid)
- }
- })
- if (processIds.length === 0) {
- resolve(`未找到在端口 ${this.port} 上运行的进程`)
- return
- }
- if (processIds.length > 0) {
- processIds.forEach((pid) => {
- exec(`taskkill /F /PID ${pid}`, (error) => {
- if (error) {
- resolve(`关闭进程时出错: ${error}`)
- } else {
- resolve(this.port)
- }
- })
- })
- }
- })
- })
- }
- }
- module.exports = { WebDriver: WebDriver }
|