Skip to content

Commit

Permalink
feat: 添加实验性功能以模拟0毫秒的waitUntil并支持直接传参html字符串
Browse files Browse the repository at this point in the history
  • Loading branch information
sj817 committed Dec 27, 2024
1 parent 003f8dd commit 1bef5f3
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 12 deletions.
115 changes: 106 additions & 9 deletions src/puppeteer/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ChildProcess } from 'child_process'
import puppeteer, { Browser, GoToOptions, HTTPRequest, Page, LaunchOptions, ScreenshotOptions } from 'puppeteer-core'

export interface screenshot extends ScreenshotOptions {
/** http地址或本地文件路径 */
/** http地址、本地文件路径、html字符串 */
file: string
/**
* 选择的元素截图
Expand Down Expand Up @@ -98,10 +98,13 @@ export class Render {
list: Map<string, any>
/** 浏览器进程 */
process!: ChildProcess | null
/** 页面实例 */
// pages: Page[]
constructor (id: number, config: LaunchOptions) {
this.id = id
this.config = config
this.list = new Map()
// this.pages = []
}

/**
Expand Down Expand Up @@ -216,6 +219,7 @@ export class Render {
this.list.delete(echo)
if (page) {
common.emit('screenshot', this.id)
page.removeAllListeners()
await page?.close().catch(() => { })
}
}
Expand All @@ -228,21 +232,58 @@ export class Render {
async page (data: screenshot) {
/** 创建页面 */
const page = await this.browser.newPage()

/** 请求拦截处理 */
if (typeof data.setRequestInterception === 'function') {
await page.setRequestInterception(true)
page.on('request', (req) => data.setRequestInterception!(req, data))
}
// let page: Page

/** 打开页面数+1 */
common.emit('newPage', this.id)

// /** 如果waitUntil传参了 直接加载页面 */
// if (data?.pageGotoParams?.waitUntil) {
// /** 有监听器需求 new一个 */
// if (typeof data.setRequestInterception === 'function') {
// page = await this.browser.newPage()
// this.pages.push(page)

// /** 请求拦截处理 */
// await page.setRequestInterception(true)
// page.on('request', (req) => data.setRequestInterception!(req, data))
// } else {
// /** 无监听器需求 从页面中拿一个 */
// page = this.pages[0]
// }

// /** 设置HTTP 标头 */
// if (data.headers) await page.setExtraHTTPHeaders(data.headers)

// /** 打开、加载页面 */
// if (data.file.startsWith('http') || data.file.startsWith('file://')) {
// await page.goto(data.file, data.pageGotoParams)
// } else {
// await page.setContent(data.file, data.pageGotoParams)
// }
// } else {
// /** 有监听器需求 new一个 */
// page = await this.browser.newPage()
// this.pages.push(page)
// /** 设置HTTP 标头 */
// if (data.headers) await page.setExtraHTTPHeaders(data.headers)
// /** 模拟0毫秒的waitUntil */
// await this.simulateWaitUntil(page, data)
// }

/** 设置HTTP 标头 */
if (data.headers) await page.setExtraHTTPHeaders(data.headers)
if (typeof data.setRequestInterception === 'function') {
await page.setRequestInterception(true)
page.on('request', (req) => data.setRequestInterception!(req, data))
}

/** 加载页面 */
await page.goto(data.file, data.pageGotoParams)
/** 打开页面 */
if (data.file.startsWith('http') || data.file.startsWith('file://')) {
await page.goto(data.file, data.pageGotoParams)
} else {
await page.setContent(data.file, data.pageGotoParams)
}

/** 等待body加载完成 */
await page.waitForSelector('body')
Expand Down Expand Up @@ -315,4 +356,60 @@ export class Render {
}
await page.setViewport(setViewport)
}

/**
* 实验性功能
* @param page 页面实例
* @param data 截图参数
* @description 通过捕获请求和响应来模拟0毫秒的waitUntil
*/
async simulateWaitUntil (page: Page, data: screenshot) {
if (!data.pageGotoParams) data.pageGotoParams = {}
data.pageGotoParams.waitUntil = 'load'

const list: Record<string, number> = {}

const delCount = (url: string) => {
if (list[url]) list[url]--
if (list[url] <= 0) delete list[url]
if (Object.keys(list).length <= 0) common.emit('end', true)
}

page.on('request', (req) => {
const url = req.url()
if (typeof list[url] !== 'number') {
list[url] = 0
return
}

list[url]++
req.continue()
})

page.on('response', request => delCount(request.url()))
page.on('requestfailed', request => delCount(request.url()))
page.on('requestfinished', request => delCount(request.url()))

/** 加载页面 */
let result
if (data.file.startsWith('http') || data.file.startsWith('file://')) {
result = page.goto(data.file, data.pageGotoParams)
} else {
result = page.setContent(data.file, data.pageGotoParams)
}

await new Promise((resolve) => {
const timer = setTimeout(() => {
resolve(true)
common.emit('end', false)
}, 10000)

common.once('end', (bool) => {
if (bool) clearTimeout(timer)
resolve(true)
})
})

await result
}
}
6 changes: 4 additions & 2 deletions src/puppeteer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export class Puppeteer {
config: RunConfig
/** 启动浏览器的参数 初始化后才产生 */
browserOptions: LaunchOptions
/** 浏览器路径 */
chromePath!: string
constructor (config?: RunConfig) {
this.index = 0
this.list = []
Expand Down Expand Up @@ -79,8 +81,8 @@ export class Puppeteer {
if (!this.config?.executablePath) {
const version = PUPPETEER_REVISIONS[this.config.chrome!]
const init = new InitChrome(version, this.config.chrome!)
const executablePath = await init.init()
this.browserOptions.executablePath = executablePath
this.chromePath = await init.init()
this.browserOptions.executablePath = this.chromePath
}

/** 用户数据存储路径 */
Expand Down
15 changes: 14 additions & 1 deletion src/puppeteer/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface Info {
chromeDir: string
/** chrome二进制路径 */
chrome: string
/** deb.deps路径 仅在linux下存在 */
debDeps: string
}

/**
Expand Down Expand Up @@ -150,6 +152,10 @@ export default class InitChrome {
'xdg-utils',
]

if (process.getuid?.() !== 0) {
throw new Error('安装系统依赖需要root权限')
}

/** 获取当前的系统 */
const system = await common.exec('cat /etc/os-release').catch(() => '') as string

Expand All @@ -169,9 +175,13 @@ export default class InitChrome {

await install(list)
} else if (/debian|ubuntu/i.test(system)) {
let cmd = 'apt install fonts-wqy-microhei fonts-noto-cjk fonts-adobe-source-han-sans-cn'
if (this.info.debDeps && fs.existsSync(this.info.debDeps)) {
cmd = fs.readFileSync(this.info.debDeps, 'utf-8').split('\n').join(',')
}
const list = [
{ type: '依赖', command: `apt-get install -y ${Debian.join(' ')}` },
{ type: '字体', command: 'apt install fonts-wqy-microhei fonts-noto-cjk fonts-adobe-source-han-sans-cn' },
{ type: '字体', command: cmd }
]

await install(list)
Expand Down Expand Up @@ -234,6 +244,8 @@ export default class InitChrome {
const chromeDir = dir
/** chrome二进制路径 */
const chrome = path.join(chromeDir, `${this.browser}-${platform}`, `${this.browser}${isWin ? '.exe' : ''}`)
/** deb.deps路径 仅在linux下存在 */
const debDeps = path.join(chromeDir, `${this.browser}-${platform}`, 'deb.deps')

// tips: 压缩包解压后会带一个文件夹: ${this.browser}-${platform}
return {
Expand All @@ -245,6 +257,7 @@ export default class InitChrome {
zip,
chromeDir,
chrome,
debDeps,
}
}
}

0 comments on commit 1bef5f3

Please sign in to comment.