ITADN
microlinkhq/browserless
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈
browserless browserless

Powered by microlink.io Last version Coverage Status NPM Status

基于 Puppeteer 的无头 Chrome/Chromium 驱动程序。


亮点

安装

你可以通过 npm 安装:

npm install browserless puppeteer --save

Browserless 运行在 Puppeteer 之上,因此您需要先安装它才能开始使用。

您可以根据使用场景选择 puppeteerpuppeteer-core

用法

以下是一个展示 Browserless 部分功能的完整示例:

const createBrowser = require('browserless')
const termImg = require('term-img')

// First, create a browserless factory
// This is similar to opening a browser for the first time
const browser = createBrowser()

// Browser contexts are like browser tabs
// You can create as many as your resources can support
// Cookies/caches are limited to their respective browser contexts, just like browser tabs
const browserless = await browser.createContext()

// Perform your required browser actions.
// e.g., taking screenshots or fetching HTML markup
const buffer = await browserless.screenshot('http://example.com', {
  device: 'iPhone 6'
})

console.log(termImg(buffer))

// After your task is done, destroy your browser context
await browserless.destroyContext()

// At the end, gracefully shutdown the browser process
await browser.close()

如你所见,Browserless 使用单个浏览器进程,允许你在同一进程中创建和销毁多个浏览器上下文。

如果你已经在项目中使用 Puppeteer,只需安装 Browserless 即可将其叠加使用。

你还可以包含额外的 Browserless 软件包 以满足你的特定需求,它们都能与 Puppeteer 良好配合。

云 API 解决方案

如果你不想管理该基础设施,可以使用完全托管的 Microlink API

它涵盖了所有 browserless 用例,但会自动处理代理轮换、付费墙、机器人检测以及受限平台(如主要社交网络),同时按需扩展。

定价采用按量付费模式,免费开始

CLI

使用 Browserless 命令行工具,你可以通过终端窗口与 Browserless 交互,或将其作为自动化流程的一部分使用:

使用你喜欢的包管理器全局安装 @browserless/cli

npm install -g @browserless/cli

然后在终端中运行 browserless 以查看可用命令列表。

初始化浏览器

初始化 Browserless 会创建一个无头浏览器实例。

const createBrowser = require('browserless')

const browser = createBrowser({
  timeout: 25000,
  lossyDeviceName: true,
  ignoreHTTPSErrors: true
})

此实例提供了若干高级方法。

例如:

// Call `createContext` to create a browser tab
const browserless = await browser.createContext({ retry: 2 })

const buffer = await browserless.screenshot('https://example.com')

// Call `destroyContext` to close the browser tab.
await browserless.destroyContext()

浏览器会持续运行,直到你显式关闭它:

// At the end, gracefully shutdown the browser process
await browser.close()

.constructor(options)

createBrowser 方法支持 puppeteer.launch#options

Browserless 提供了创建浏览器实例的额外选项:

defaultDevice

将浏览器视口设置为指定设备的视口:

type: string
default: 'Macbook Pro 13'

lossyDeviceName

type: boolean
default: false

允许在设置设备名称时存在误差范围。


// Initialize browser instance
const browser = require('browserless')({ lossyDeviceName: true });

(async () => {
    // Create context/tab
    const tabInstance = await browser.createContext();

    // Even if the device name is misspelled, the property will default to 'MacBook Pro'
    console.log(tabInstance.getDevice({ device: 'MacBook Pro' }))
    console.log(tabInstance.getDevice({ device: 'macbook pro 13' }))
    console.log(tabInstance.getDevice({ device: 'MACBOOK PRO 13' }))
    console.log(tabInstance.getDevice({ device: 'macbook pro' }))
    console.log(tabInstance.getDevice({ device: 'macboo pro' }))
})()

提供的名称将被解析为最接近匹配的设备。

这在设备名称由第三方设置的情况下非常有用。

mode

type: string
default: launch
values: 'launch' | 'connect'

指定是否应使用 puppeteer.launchpuppeteer.connect 来生成浏览器实例。

timeout

type: number
default: 30000

更改默认的导航最大时间。

puppeteer

type: Puppeteer
default: puppeteer|puppeteer-core|puppeteer-firefox

默认情况下,它会自动检测安装了哪个库(因此基于您安装的依赖项,使用 puppeteerpuppeteer-core)。

.createContext(options)

初始化浏览器后,您可以创建一个浏览器上下文,这相当于打开一个标签页:

const browserless = await browser.createContext({
  retry: 2
})

每个浏览器上下文都是隔离的,因此 Cookie/缓存仅保留在其对应的浏览器上下文中,类似于浏览器标签页。每个上下文都可以使用其自身的一组选项进行初始化。

options

支持 Puppeteer 的所有 browser.createBrowserContext#options

Browserless 提供额外的浏览器上下文选项:

retry

类型: number
默认值: 2

在将导航视为失败之前可以执行的重试次数。

.browser()

返回内部的 Browser 实例。

const headlessBrowser = await browser.browser()

console.log('My headless browser PID is', headlessBrowser.process().pid)
console.log('My headless browser version is', await headlessBrowser.version())

.respawn()

重新生成内部浏览器。

const getPID = promise => (await promise).process().pid

console.log('Process PID:', await getPID(browser.browser()))

await browser.respawn()

console.log('Process PID:', await getPID(browser.browser()))

此方法属于实现细节,通常无需调用。

.close()

关闭内部浏览器。

const { onExit } = require('signal-exit')
// automatically teardown resources after
// `process.exit` is called
onExit(browser.close)

内置

.html(url, options)

将目标 url 的内容序列化为 HTML。

const html = await browserless.html('https://example.com')

console.log(html)
// => "<!DOCTYPE html><html><head>…"

options

请参阅 browserless.goto 以获取所有选项和支持的值。

.text(url, options)

将目标 url 的内容序列化为纯文本。

const text = await browserless.text('https://example.com')

console.log(text)
// => "Example Domain\nThis domain is for use in illustrative…"

options

请参阅 browserless.goto 以获取所有选项和支持的值。

.pdf(url, options)

生成位于 url 之后的网站的 PDF 版本。

const buffer = await browserless.pdf('https://example.com')

console.log(`PDF generated in ${buffer.byteLength()} bytes`)

options

此方法默认使用以下选项:

{
  margin: '0.35cm',
  printBackground: true,
  scale: 0.65
}

参见 browserless.goto 以获取所有选项和支持的值。

此外,Puppeteer 的所有 page.pdf 选项均受支持。

另外,您可以设置:

margin

type: string | string[]
default: '0.35cm'

设置屏幕边距。支持的单位包括:

  • px 表示像素。
  • in 表示英寸。
  • cm 表示厘米。
  • mm 表示毫米。

您可以通过将边距属性作为 object 传入来设置它们:

const buffer = await browserless.pdf(url.toString(), {
  margin: {
    top: '0.35cm',
    bottom: '0.35cm',
    left: '0.35cm',
    right: '0.35cm'
  }
})

如果仅提供单个边距值,该值将应用于所有边:

const buffer = await browserless.pdf(url.toString(), {
  margin: '0.35cm'
})

.screenshot(url, options)

基于指定的 url 生成截图。

const buffer = await browserless.screenshot('https://example.com')

console.log(`Screenshot taken in ${buffer.byteLength()} bytes`)

options

此方法默认使用以下选项:

{
  device: 'macbook pro 13'
}

请参阅 browserless.goto 以获取所有选项和支持的值。

此外,Puppeteer 的所有 page.screenshot 选项均受支持。

另外,Browserless 提供以下选项:

codeScheme

type: string
default: 'atom-dark'

每当传入的响应 'Content-Type' 设置为 'json' 时,JSON 负载将以格式化的 JSON 字符串形式呈现,并使用提供的 codeScheme 主题或默认的 atom-dark 进行美化。

颜色方案基于 Prism library

automad-prism-themes 仓库 提供了多种可供选择的主题,以及 CDN 选项

element

type: string

基于 CSS 选择器 返回第一个匹配的 DOM 元素实例。此操作在元素显示在屏幕上或达到指定的最大 超时时间 之前保持未解决状态。

overlay

type: object

截图完成后,此选项允许你应用一个覆盖层(背景)。

Overlay example

您可以通过指定以下内容来配置叠加层:

  • browser:指定要使用的浏览器模板的颜色,因此分别对应浅色模式和深色模式的 lightdark
  • background:指定要使用的背景。支持多种值类型:
    • 十六进制/RGB/RGBA 颜色代码,例如 #c1c1c1
    • CSS 渐变,例如 linear-gradient(225deg, #FF057C 0%, #8D0B93 50%, #321575 100%)
    • 图像 URL,例如 https://picsum.photos/1920/1080
const buffer = await browserless.screenshot(url.toString(), {
  styles: ['.crisp-client, #cookies-policy { display: none; }'],
  overlay: {
    browser: 'dark',
    background:
      'linear-gradient(45deg, rgba(255,18,223,1) 0%, rgba(69,59,128,1) 66%, rgba(69,59,128,1) 100%)'
  }
})

.destroyContext(options)

销毁当前的浏览器上下文。

const browserless = await browser.createContext({ retry: 0 })

const content = await browserless.html('https://example.com')

await browserless.destroyContext()

options

force

type: string
default: 'force'

当设置 force 时,如果正在执行浏览器操作,它将阻止上下文的重新创建。

.getDevice(options)

用于设置特定的设备类型,此方法会设置设备属性。

browserless.getDevice({ device: 'Macbook Pro 15' })

// => {
//   userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
//   viewport: {
//     width: 1440,
//     height: 900,
//     deviceScaleFactor: 2,
//     isMobile: false,
//     hasTouch: false,
//     isLandscape: false
//   }
// }

此方法通过添加一些缺失的设备来扩展 Puppeteer.KnownDevices 列表。

options

device

type: string

设备描述符名称。它用于获取与设备关联的预设值。

当启用 lossyDeviceName 时,将执行模糊搜索而非严格搜索,以最大化找到匹配项的可能性。

viewport

type: object

设置额外的视口配置。这些配置将与预设配置合并。

browserless.getDevice({
  device: 'iPad',
  viewport: {
    isLandscape: true
  }
})
headers

type: object

将与设备预设合并的额外 headers。

browserless.getDevice({
  device: 'iPad',
  headers: {
    'user-agent': 'googlebot'
  }
})

.evaluate(fn, gotoOpts)

它提供了一个用于创建自定义 evaluate 函数的接口,并允许访问 pageresponse

fn 将接收 pageresponse 作为参数:

const ping = browserless.evaluate((page, response) => ({
  statusCode: response.status(),
  url: response.url(),
  redirectUrls: response.request().redirectChain()
}))

await ping('https://example.com')
// {
//   "statusCode": 200,
//   "url": "https://example.com/",
//   "redirectUrls": []
// }

您无需关闭页面,它会自动关闭。

内部,该方法执行 browserless.goto,因此可以通过第二个参数传递额外参数:

const serialize = browserless.evaluate(page => page.evaluate(() => document.body.innerText), {
  waitUntil: 'domcontentloaded'
})

await serialize('https://example.com')
// => '<!DOCTYPE html><html><div>…'

.goto(page, options)

执行 page.goto,并具备许多额外功能:

const page = await browserless.page()
const { response, device } = await browserless.goto(page, { url: 'http://example.com' })

options

在此处传递的任何选项都将透传至 page.goto

此外,你可以设置:

abortTypes

type: array
default: []

设置基于 ResourceType 中止请求的能力。

adblock

type: boolean
default: true

启用内置的 adblocker by Cliqz,用于中止与广告服务相关的非必要第三方请求。

animations

type: boolean
default: false

禁用 CSS animationstransitions,同时相应地设置 prefers-reduced-motion

authenticate

type: object

它将向下传递至 page.authenticate

click

type: string | string[]

点击匹配 CSS selector 的 DOM 元素。

colorScheme

type: string
default: 'no-preference'

设置 prefers-color-scheme CSS 媒体特性,用于检测用户是否请求系统使用 'light''dark' 颜色主题。

device

type: string
default: 'macbook pro 13'

它指定用于检索 userAgentviewportdevice 描述符。

headers

type: object

一个包含随每个请求发送的额外 HTTP 头的对象。

const browserless = require('browserless')

const page = await browserless.page()
await browserless.goto(page, {
  url: 'http://example.com',
  headers: {
    'user-agent': 'googlebot',
    cookie: 'foo=bar; hello=world'
  }
})

这会在匹配的元素上设置 visibility: hidden

html

type: string

如果您提供 HTML 标记,则 page.setContent 避免从目标 URL 获取内容。

javascript

type: boolean
default: true

当为 false 时,它会禁用当前页面上的 JavaScript。

mediaType

type: string
default: 'screen'

使用 page.emulateMediaType 更改页面的 CSS 媒体类型。

modules

type: string | string[]

向浏览器页面注入 <script type="module">

它可以接受:

  • 绝对 URL(例如,'https://cdn.jsdelivr.net/npm/@microlink/mql@0.3.12/src/browser.js')。
  • 本地文件(例如,`'local-file.js')。
  • 内联代码(例如,"document.body.style.backgroundColor = 'red'")。
const buffer = await browserless.screenshot(url.toString(), {
  modules: [
    'https://cdn.jsdelivr.net/npm/@microlink/mql@0.3.12/src/browser.js',
    'local-file.js',
    "document.body.style.backgroundColor = 'red'"
  ]
})
onPageRequest

type:function

为页面中的每个请求关联一个处理程序。

scripts

type: string | string[]

向浏览器页面注入 <script>

它可以接受:

  • 绝对 URL(例如,'https://cdn.jsdelivr.net/npm/@microlink/mql@0.3.12/src/browser.js')。
  • 本地文件(例如,`'local-file.js')。
  • 内联代码(例如,"document.body.style.backgroundColor = 'red'")。
const buffer = await browserless.screenshot(url.toString(), {
  scripts: [
    'https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js',
    'local-file.js',
    "document.body.style.backgroundColor = 'red'"
  ]
})

尽可能使用 modules

scroll

type: string

滚动到匹配 CSS selector 的 DOM 元素。

styles

type: string | string[]

向浏览器页面注入 <style>

它可以接受:

  • 绝对 URL(例如,'https://cdn.jsdelivr.net/npm/hack@0.8.1/dist/dark.css')。
  • 本地文件(例如,`'local-file.css')。
  • 内联代码(例如,"body { background: red; }")。
const buffer = await browserless.screenshot(url.toString(), {
  styles: [
    'https://cdn.jsdelivr.net/npm/hack@0.8.1/dist/dark.css',
    'local-file.css',
    'body { background: red; }'
  ]
})
timezone

type: string

更改页面的 timezone

url

type: string

目标 URL。

viewport

使用 page.setViewport 方法设置自定义视口。

waitForSelector

type:string

使用 page.waitForSelector 等待一段时间、选择器或函数。

waitForTimeout

type:number

等待指定毫秒数。

waitUntil

type: string | string[]
default: 'auto'
values: 'auto' | 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'

确定何时认为导航成功。

如果提供了事件字符串数组,则当所有事件都触发后,导航被视为成功。

事件可以是:

  • 'auto': 以智能方式组合 'load''networkidle2' 以等待最短必要时间。
  • 'load': 当 load 事件触发时,认为导航完成。
  • 'domcontentloaded': 当 DOMContentLoaded 事件触发时,认为导航完成。
  • 'networkidle0': 当网络连接数不超过 0 且持续至少 500 ms 时,认为导航完成。
  • 'networkidle2': 当网络连接数不超过 2 且持续至少 500 ms 时,认为导航完成。

.context()

返回与您的实例关联的 BrowserContext

const browserContext = await browserless.context()

console.log(browserContext.id)
// => 'D2CD28FDECB1859772B9C5919E563C84'

.withPage(fn, [options])

返回一个高阶函数,作为与页面交互的便捷方式:

const getTitle = browserless.withPage((page, goto) => async opts => {
  const result = await goto(page, opts)
  return page.title()
})

该函数将以以下方式被调用:

const title = getTitle({ url: 'https://example.com' })

fn

type: function

要执行的函数。它接收 page, goto 作为参数。

options

timeout

type: number
default: browserless.timeout

此设置将更改默认的导航最大时间。

.page([name])

返回一个与当前浏览器上下文关联的独立 Page

const page = await browserless.page()
await page.content()
// => '<html><head></head><body></body></html>'

name

type: string
default: undefined

页面的可选名称,用于调试日志。

Extended

function

@browserless/function 包提供了一个安全沙箱,用于在运行时访问浏览器页面的情况下运行任意 JavaScript 代码:

const createFunction = require('@browserless/function')()

const code = async ({ page }) => page.evaluate('jQuery.fn.jquery')

const version = createFunction(code)

const { isFulfilled, value } = await version('https://jquery.com')

// => {
//   isFulfilled: true,
//   value: '1.13.1'
// }

options

除以下属性外,提供的任何其他参数都将在代码执行期间可用。

vmOpts

托管代码运行在通过 isolated-function 创建的安全沙箱中。

gotoOpts

可以传递任何 goto#options 以调整内部 URL 解析。

lighthouse

@browserless/lighthouse 包为您提供运行由 browserless 支持的 Lighthouse 报告的设置。

const createLighthouse = require('@browserless/lighthouse')
const createBrowser = require('browserless')
const { writeFile } = require('fs/promises')
const { onExit } = require('signal-exit')

const browser = createBrowser()
onExit(browser.close)

const lighthouse = createLighthouse(async teardown => {
  const browserless = await browser.createContext()
  teardown(() => browserless.destroyContext())
  return browserless
})

const report = await lighthouse('https://microlink.io')
await writeFile('report.json', JSON.stringify(report, null, 2))

该报告将为提供的 URL 生成。这会扩展 lighthouse:default 设置。这些设置类似于开发者工具中的 Google Chrome Audits 报告。

options

将扩展 'lighthouse:default' 设置的 Lighthouse 配置

const report = await lighthouse(url, {
  onlyAudits: ['accessibility']
})

此外,你还可以从不同的预设配置进行扩展:

const report = await lighthouse(url, {
  preset: 'desktop',
  onlyAudits: ['accessibility']
})

此外,你可以设置:

Lighthouse 执行作为 worker thread 运行,支持任何 worker#options

logLevel

type: string
default: 'error'
values: 'silent' | 'error' | 'info' | 'verbose'

要启用的日志级别。

output

type: string | string[]
default: 'json'
values: 'json' | 'csv' | 'html'

要生成的报告输出类型。

timeout

type: number
default: browserless.timeout

更改默认的导航最大时间。

screencast

@browserless/screencast 包允许你使用 puppeteer 捕获浏览器导航的每一帧。

此 API 类似于 screenshots,但你可以对帧和输出进行更细粒度的控制:

const createScreencast = require('@browserless/screencast')
const createBrowser = require('browserless')

const browser = createBrowser()
const browserless = await browser.createContext()
const page = await browserless.page()

const screencast = createScreencast(page, { 
  maxWidth: 1280, 
  maxHeight: 800 
})

const frames = []
screencast.onFrame(data => frames.push(data))

screencast.start()
await browserless.goto(page, { url, waitForTimeout: 300 })
await screencast.stop()

console.log(frames)

查看一个完整示例,用于生成 GIF。

page

类型:object

Page 对象。

options

请参阅 Page.startScreencast 以了解所有受支持的选项和值。

browserless 在内部被划分为多个包,这样您只需使用所需的代码。

版本
browserlessnpm
@browserless/benchmarknpm
@browserless/capturenpm
@browserless/clinpm
@browserless/devicesnpm
@browserless/errorsnpm
@browserless/examplesnpm
@browserless/functionnpm
@browserless/gotonpm
@browserless/lighthousenpm
@browserless/pdfnpm
@browserless/screencastnpm
@browserless/screenshotnpm

常见问题

问:为什么使用 browserless 而不是 puppeteer

browserless 并不取代 Puppeteer;它是 Puppeteer 的补充。它作为官方 Headless Chrome 之上的语法糖层,针对生产场景进行了优化。

问:是否有托管的云端解决方案?

是的。如果你不想管理无头浏览器、代理和反机器人规避的基础设施,请使用我们构建的 Microlink API

它按需扩展,定价 从免费开始

问:为什么默认阻止广告脚本?

与仅从网站获取内容相比,无头导航的成本更高。

为了加快处理速度,我们默认阻止广告脚本,因为其中大多数资源消耗较大。

问:我的输出与预期不同

Browserless 可能过于智能,阻止了你需要的请求。

你可以使用 DEBUG=browserless 环境变量启用调试模式,以查看底层发生了什么:

建议提交一个包含调试跟踪信息的 issue

问:我想在我的 AWS Lambda 类项目中使用 browserless

是的,请查看 chrome-aws-lambda 以设置具有二进制兼容性的 AWS Lambda。

许可证

browserless © Microlink,根据 MIT 许可证发布。
Microlink 编写和维护,并得到 contributors 的帮助。

logoxinh studio 设计。

microlink.io · GitHub microlinkhq · X @microlinkhq