基于 Puppeteer 的无头 Chrome/Chromium 驱动程序。
亮点
- 兼容 Puppeteer API(文本、截图、HTML、PDF)。
- 内置 广告拦截器,用于取消不必要的请求。
- 通过 Browserless CLI 进行 Shell 交互。
- 轻松集成 Google Lighthouse。
- 自动重试与错误处理。
- 合理的默认配置。
安装
你可以通过 npm 安装:
npm install browserless puppeteer --save
Browserless 运行在 Puppeteer 之上,因此您需要先安装它才能开始使用。
您可以根据使用场景选择 puppeteer 或 puppeteer-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.launch 或 puppeteer.connect 来生成浏览器实例。
timeout
type: number
default: 30000
更改默认的导航最大时间。
puppeteer
type: Puppeteer
default: puppeteer|puppeteer-core|puppeteer-firefox
默认情况下,它会自动检测安装了哪个库(因此基于您安装的依赖项,使用 puppeteer 或 puppeteer-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
截图完成后,此选项允许你应用一个覆盖层(背景)。

您可以通过指定以下内容来配置叠加层:
- browser:指定要使用的浏览器模板的颜色,因此分别对应浅色模式和深色模式的
light或dark。 - background:指定要使用的背景。支持多种值类型:
- 十六进制/RGB/RGBA 颜色代码,例如
#c1c1c1。 - CSS 渐变,例如
linear-gradient(225deg, #FF057C 0%, #8D0B93 50%, #321575 100%) - 图像 URL,例如
https://picsum.photos/1920/1080。
- 十六进制/RGB/RGBA 颜色代码,例如
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 函数的接口,并允许访问 page 和 response。
fn 将接收 page 和 response 作为参数:
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 animations 和 transitions,同时相应地设置 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'
它指定用于检索 userAgent 和 viewport 的 device 描述符。
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 在内部被划分为多个包,这样您只需使用所需的代码。
常见问题
问:为什么使用 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 的帮助。
logo 由 xinh studio 设计。
microlink.io · GitHub microlinkhq · X @microlinkhq