Nightmare
Nightmare is a high-level browser automation library from Segment.
The goal is to expose a few simple methods that mimic user actions (like goto
, type
and click
), with an API that feels synchronous for each block of scripting, rather than deeply nested callbacks. It was originally designed for automating tasks across sites that don't have APIs, but is most often used for UI testing and crawling.
Under the covers it uses Electron, which is similar to PhantomJS but roughly twice as fast and more modern.
⚠️ Security Warning: We've implemented many of the security recommendations outlined by Electron to try and keep you safe, but undiscovered vulnerabilities may exist in Electron that could allow a malicious website to execute code on your computer. Avoid visiting untrusted websites.
🛠 Migrating to 3.x: You'll want to check out this issue before upgrading. We've worked hard to make improvements to nightmare while limiting the breaking changes and there's a good chance you won't need to do anything.
Niffy is a perceptual diffing tool built on Nightmare. It helps you detect UI changes and bugs across releases of your web app.
Daydream is a complementary chrome extension built by @stevenmiller888 that generates Nightmare scripts for you while you browse.
Many thanks to @matthewmueller and @rosshinkley for their help on Nightmare.
Nightmare是来自Segment的高级浏览器自动化库。我们的目标是公开一些模仿用户操作的简单方法(如goto,type和click),以及一个对每个脚本块都感觉同步的API,而不是深度嵌套的回调。它最初设计用于在没有API的网站上自动执行任务,但最常用于UI测试和爬网。在它的封面下,它使用了与PhantomJS类似的Electron,但速度大约是现代的两倍。
⚠️安全警告:我们已经实施了Electron概述的许多安全建议,以确保您的安全,但Electron中可能存在未被发现的漏洞,可能允许恶意网站在您的计算机上执行代码。避免访问不受信任的网站。
🛠迁移到3.x:在升级之前,您需要检查此问题。我们一直在努力改善Nightmare,同时限制突变,并且您很可能不需要做任何事情。
Niffy是建立在Nightmare之上的感知差异的构建工具。它可以帮助您检测Web应用程序发行版中的UI更改和错误。
Daydream是由@ stevenmiller888构建的补充Chrome扩展,可在您浏览时为您生成Nightmare脚本。
非常感谢@matthewmueller和@rosshinkley在Nightmare上的帮助。
Examples
Let's search on DuckDuckGo:
让我们搜索DuckDuckGo:
const Nightmare = require('nightmare') const nightmare = Nightmare({ show: true }) nightmare .goto('https://duckduckgo.com') .type('#search_form_input_homepage', 'github nightmare') .click('#search_button_homepage') .wait('#r1-0 a.result__a') .evaluate(() => document.querySelector('#r1-0 a.result__a').href) .end() .then(console.log) .catch(error => { console.error('Search failed:', error) })
You can run this with:你可以运行这个:
npm install --save nightmare node example.js
Or, let's run some mocha tests:或者,让我们运行一些摩卡测试:
const Nightmare = require('nightmare') const chai = require('chai') const expect = chai.expect describe('test duckduckgo search results', () => { it('should find the nightmare github link first', function(done) { this.timeout('10s') const nightmare = Nightmare() nightmare .goto('https://duckduckgo.com') .type('#search_form_input_homepage', 'github nightmare') .click('#search_button_homepage') .wait('#links .result__a') .evaluate(() => document.querySelector('#links .result__a').href) .end() .then(link => { expect(link).to.equal('https://github.com/segmentio/nightmare') done() }) }) })
You can see examples of every function in the tests here.
To get started with UI Testing, check out this quick start guide.
你可以在这里看到测试中每个函数的例子。要开始使用UI测试,请查看本快速入门指南。
To install dependencies安装依赖关系
npm install
To run the mocha tests运行摩卡测试
npm test
Node versions
Nightmare is intended to be run on NodeJS 4.x or higher.
Nightmare在运行在NodeJS 4.x或更高版本上。
API
Nightmare(options)
Creates a new instance that can navigate around the web. The available options are documented here, along with the following nightmare-specific options.
创建一个可以在网络中导航的新实例。这里记录可用的选项,以及以下Nightmare特定的选项。
waitTimeout (default: 30s)
Throws an exception if the .wait()
didn't return true
within the set timeframe.
如果.wait()在设定的时间内没有返回true,则会引发异常。waitTimeout(默认:30秒)
const nightmare = Nightmare({ waitTimeout: 1000 // in ms })
gotoTimeout (default: 30s)
Throws an exception if the .goto()
didn't finish loading within the set timeframe. Note that, even though goto
normally waits for all the resources on a page to load, a timeout exception is only raised if the DOM itself has not yet loaded.
如果.goto()未在设定的时间范围内完成加载,则会引发异常。请注意,即使goto正常等待页面上的所有资源加载,只有当DOM本身尚未加载时才会引发超时异常。
gotoTimeout(默认:30秒)
const nightmare = Nightmare({ gotoTimeout: 1000 // in ms })
loadTimeout (default: infinite)
Forces Nightmare to move on if a page transition caused by an action (eg, .click()
) didn't finish within the set timeframe. If loadTimeout
is shorter than gotoTimeout
, the exceptions thrown by gotoTimeout
will be suppressed.
如果由动作引起的页面转换(例如,.click())未在设定的时间范围内完成,则强制“nightmare”继续前进。如果loadTimeout比gotoTimeout短,gotoTimeout抛出的异常将被抑制。
loadTimeout(默认:无限)
const nightmare = Nightmare({ loadTimeout: 1000 // in ms })
executionTimeout (default: 30s)
The maximum amount of time to wait for an .evaluate()
statement to complete.
等待执行.evaluate()语句完成的最长时间。
const nightmare = Nightmare({ executionTimeout: 1000 // in ms })
paths
The default system paths that Electron knows about. Here's a list of available paths: https://github.com/atom/electron/blob/master/docs/api/app.md#appgetpathname
You can overwrite them in Nightmare by doing the following:
Electron知道的默认系统路径。以下是可用路径的列表:https://github.com/atom/electron/blob/master/docs/api/app.md#appgetpathname
您可以通过执行以下操作在“Nightmare”中覆盖它们:
const nightmare = Nightmare({ paths: { userData: '/user/data' } })
switches
The command line switches used by the Chrome browser that are also supported by Electron. Here's a list of supported Chrome command line switches:
https://github.com/atom/electron/blob/master/docs/api/chrome-command-line-switches.md
Chrome浏览器使用的命令行开关也支持Electron。以下是支持的Chrome命令行开关列表:https://github.com/atom/electron/blob/master/docs/api/chrome-command-line-switches.md
const nightmare = Nightmare({ switches: { 'proxy-server': '1.2.3.4:5678', 'ignore-certificate-errors': true } })
electronPath
The path to the prebuilt Electron binary. This is useful for testing on different versions of Electron. Note that Nightmare only supports the version on which this package depends. Use this option at your own risk.
预建的Electron二进制文件的路径。这对于在不同版本的Electron上进行测试很有用。请注意,nightmare只支持这个包依赖的版本。使用此选项需要您自担风险。
const nightmare = Nightmare({ electronPath: require('electron') })
dock (OS X)
A boolean to optionally show the Electron icon in the dock (defaults to false
). This is useful for testing purposes.
一个布尔值,可选择在dock显示Electron图标(默认为false)。这对于测试目的很有用。
const nightmare = Nightmare({ dock: true })
openDevTools
Optionally shows the DevTools in the Electron window using true
, or use an object hash containing mode: 'detach'
to show in a separate window. The hash gets passed to contents.openDevTools()
to be handled. This is also useful for testing purposes. Note that this option is honored only if show
is set to true
.
可以选择使用true在Electron窗口中显示DevTools,或使用包含对象哈希模式:'detach'在单独的窗口中显示。散列被传递给contents.openDevTools()进行处理。这对于测试目的也很有用。请注意,只有show设置为true时,此选项才有效。
const nightmare = Nightmare({ openDevTools: { mode: 'detach' }, show: true })
typeInterval (default: 100ms)
How long to wait between keystrokes when using .type()
.
使用.type()时按键间的等待时间。
const nightmare = Nightmare({ typeInterval: 20 })
pollInterval (default: 250ms)
How long to wait between checks for the .wait()
condition to be successful.
检查.wait()条件是否成功需要等待多长时间。
const nightmare = Nightmare({ pollInterval: 50 //in ms })
maxAuthRetries (default: 3)
Defines the number of times to retry an authentication when set up with .authenticate()
.
定义使用.authenticate()进行设置时重试认证的次数。
const nightmare = Nightmare({ maxAuthRetries: 3 })
certificateSubjectName
A string to determine the client certificate selected by electron. If this options is set, the select-client-certificate
event will be set to loop through the certificateList and find the first certificate that matches subjectName
on the electron Certificate Object
.
用于确定electron选择的客户端证书的字符串。如果设置了此选项,则select-client-certificate事件将设置为循环遍历certificateList,并找到与electron证书对象上的subjectName匹配的第一个证书。
const nightmare = Nightmare({ certificateSubjectName: 'tester' })
.engineVersions()
Gets the versions for Electron and Chromium.
获取Electron和Chromium的版本。
.useragent(useragent)
Sets the useragent
used by electron.
设置electron使用的用户代理。
.authentication(user, password)
Sets the user
and password
for accessing a web page using basic authentication. Be sure to set it before calling .goto(url)
.
使用基本身份验证设置访问网页的用户和密码。请务必在调用.goto(url)之前进行设置。
.end()
Completes any queue operations, disconnect and close the electron process. Note that if you're using promises, .then()
must be called after .end()
to run the .end()
task. Also note that if using an .end()
callback, the .end()
call is equivalent to calling .end()
followed by .then(fn)
. Consider:
完成任何队列操作,断开并关闭electron进程。请注意,如果您使用承诺,则必须在.end()之后调用.then()才能运行.end()任务。另请注意,如果使用.end()回调,则.end()调用等同于调用.end()后跟.then(fn)。考虑:
nightmare .goto(someUrl) .end(() => 'some value') //prints "some value" .then(console.log)
.halt(error, done)
Clears all queued operations, kills the electron process, and passes error message or 'Nightmare Halted' to an unresolved promise. Done will be called after the process has exited.
清除所有排队的操作,杀死electron进程,并将错误消息或'nightmare停止'传递给未解决的承诺。完成后将在完成后调用完成。
Interact with the Page 页面交互
.goto(url[, headers])
Loads the page at url
. Optionally, a headers
hash can be supplied to set headers on the goto
request.
When a page load is successful, goto
returns an object with metadata about the page load, including:
根据url加载页面。可选地,可以提供头部哈希以在goto请求上设置头部。当页面加载成功时,goto返回一个包含页面加载元数据的对象,其中包括:
url
: The URL that was loadedcode
: The HTTP status code (e.g. 200, 404, 500)method
: The HTTP method used (e.g. "GET", "POST")referrer
: The page that the window was displaying prior to this load or an empty string if this is the first page load.headers
: An object representing the response headers for the request as in{header1-name: header1-value, header2-name: header2-value}
If the page load fails, the error will be an object with the following properties:
如果页面加载失败,则该错误将是具有以下属性的对象:
message
: A string describing the type of errorcode
: The underlying error code describing what went wrong. Note this is NOT the HTTP status code. For possible values, see https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.hdetails
: A string with additional details about the error. This may be null or an empty string.url
: The URL that failed to load
Note that any valid response from a server is considered “successful.” That means things like 404 “not found” errors are successful results for goto
. Only things that would cause no page to appear in the browser window, such as no server responding at the given address, the server hanging up in the middle of a response, or invalid URLs, are errors.
You can also adjust how long goto
will wait before timing out by setting the gotoTimeout
option on the Nightmare constructor.
请注意,来自服务器的任何有效响应都被视为“成功”。这意味着404“找不到”错误是goto的成功结果。只有那些不会导致页面出现在浏览器窗口中的东西,比如没有服务器响应给定的地址,响应中间挂起的服务器或无效的URL都是错误。您还可以通过在Nightmare构造函数中设置gotoTimeout选项来调整goto在超时之前等待的时间。
.back()
Goes back to the previous page.
回到上一页。
.forward()
Goes forward to the next page.
转到下一页。
.refresh()
Refreshes the current page.
刷新当前页面。
.click(selector)
Clicks the selector
element once.
单击选择器元素一次。
.mousedown(selector)
Mousedowns the selector
element once.
Mousedowns选择元素一次。
.mouseup(selector)
Mouseups the selector
element once.
将鼠标移到选择元素一次。
.mouseover(selector)
Mouseovers the selector
element once.
将鼠标移到选择元素一次。
.mouseout(selector)
Mouseout the selector
element once.
将鼠标移出选择元素一次。
.type(selector[, text])
Enters the text
provided into the selector
element. Empty or falsey values provided for text
will clear the selector's value.
.type()
mimics a user typing in a textbox and will emit the proper keyboard events.
Key presses can also be fired using Unicode values with .type()
. For example, if you wanted to fire an enter key press, you would write .type('body', '\u000d')
.
输入提供给选择器元素的文本。为文本提供的空值或伪值将清除选择器的值。
.type()模仿在文本框中输入的用户,并发出正确的键盘事件。
按键也可以使用.type()的Unicode值进行触发。例如,如果您想按下回车键,则会写入.type('body',' u000d')。
If you don't need the keyboard events, consider using
.insert()
instead as it will be faster and more robust.
如果您不需要键盘事件,请考虑使用.insert(),因为它会更快更健壮。
.insert(selector[, text])
Similar to .type()
, .insert()
enters the text
provided into the selector
element. Empty or falsey values provided for text
will clear the selector's value.
.insert()
is faster than .type()
but does not trigger the keyboard events.
类似于.type(),.insert()输入提供给selector元素的文本。为文本提供的空值或伪值将清除选择器的值。.insert()比.type()快,但不会触发键盘事件。
.check(selector)
Checks the selector
checkbox element.
检查选择器复选框元素。
.uncheck(selector)
Unchecks the selector
checkbox element.
取消选中复选框元素。
.select(selector, option)
Changes the selector
dropdown element to the option with attribute [value=option
]
将选择器下拉元素更改为属性为[value = option]的选项
.scrollTo(top, left)
Scrolls the page to desired position. top
and left
are always relative to the top left corner of the document.
将页面滚动到所需的位置。
顶部和左侧总是相对于文档的左上角。
.viewport(width, height)
Sets the viewport size.
设置视口大小。
.inject(type, file)
Injects a local file
onto the current page. The file type
must be either js
or css
.
将本地文件注入当前页面。文件类型必须是js或css。
.evaluate(fn[, arg1, arg2,...])
Invokes fn
on the page with arg1, arg2,...
. All the args
are optional. On completion it returns the return value of fn
. Useful for extracting information from the page. Here's an example:
在页面上用arg1,arg2,...调用fn。所有参数都是可选的。
完成后返回fn的返回值。
用于从页面提取信息。
这是一个例子:
const selector = 'h1' nightmare .evaluate(selector => { // now we're executing inside the browser scope. return document.querySelector(selector).innerText }, selector) // <-- that's how you pass parameters from Node scope to browser scope .then(text => { // ... })
Error-first callbacks are supported as a part of evaluate()
. If the arguments passed are one fewer than the arguments expected for the evaluated function, the evaluation will be passed a callback as the last parameter to the function. For example:
作为evaluate()的一部分支持Error-first回调。
如果传递的参数少于预期的评估函数的参数,评估将作为函数的最后一个参数传递回调。
const selector = 'h1' nightmare .evaluate((selector, done) => { // now we're executing inside the browser scope. setTimeout( () => done(null, document.querySelector(selector).innerText), 2000 ) }, selector) .then(text => { // ... })
Note that callbacks support only one value argument (eg function(err, value)
). Ultimately, the callback will get wrapped in a native Promise and only be able to resolve a single value.
Promises are also supported as a part of evaluate()
. If the return value of the function has a then
member, .evaluate()
assumes it is waiting for a promise. For example:
请注意,回调仅支持一个值参数(例如,函数(err,value))。
最终,回调将被包装在原生Promise中,并且只能解析单个值。
作为evaluate()的一部分,承诺也被支持。
如果函数的返回值有一个then成员,则.evaluate()假定它正在等待承诺。
例如:
const selector = 'h1'; nightmare .evaluate((selector) => ( new Promise((resolve, reject) => { setTimeout(() => resolve(document.querySelector(selector).innerText), 2000); )}, selector) ) .then((text) => { // ... })
.wait(ms)
Waits for ms
milliseconds e.g. .wait(5000)
.
等待ms毫秒,例如
.wait(selector)
Waits until the element selector
is present e.g. .wait('#pay-button')
.
等待直到元素选择器存在为止,例如
.wait(fn[, arg1, arg2,...])
Waits until the fn
evaluated on the page with arg1, arg2,...
returns true
. All the args
are optional. See .evaluate()
for usage.
等到fn在页面上用arg1,arg2,...返回true评估为止。
所有的参数都是可选的。
请参阅.evaluate()以了解使用情况。
.header(header, value)
Adds a header override for all HTTP requests. If header
is undefined, the header overrides will be reset.
为所有HTTP请求添加标头覆盖。
如果头未定义,头覆盖将被重置。
Extract from the Page从页面中提取
.exists(selector)
Returns whether the selector exists or not on the page.
返回页面上是否存在选择器。
.visible(selector)
Returns whether the selector is visible or not.
返回选择器是否可见。
.on(event, callback)
Captures page events with the callback. You have to call .on()
before calling .goto()
. Supported events are documented here.
用回调捕获页面事件。
您必须在调用.goto()之前调用.on()。
这里记录了受支持的事件。
Additional "page" events额外的“页面”事件
.on('page', function(type="error", message, stack))
This event is triggered if any javascript exception is thrown on the page. But this event is not triggered if the injected javascript code (e.g. via .evaluate()
) is throwing an exception.
如果在页面上抛出任何javascript异常,则触发此事件。
但是,如果注入的JavaScript代码(例如通过.evaluate())抛出异常,则不会触发此事件。
"page" events
Listens for window.addEventListener('error')
, alert(...)
, prompt(...)
& confirm(...)
.
.on('page', function(type="error", message, stack))
Listens for top-level page errors. This will get triggered when an error is thrown on the page.
侦听顶级页面错误。
这会在页面上发生错误时触发。
.on('page', function(type="alert", message))
Nightmare disables window.alert
from popping up by default, but you can still listen for the contents of the alert dialog.
Nightmare将禁用window.alert默认弹出,但仍然可以侦听警报对话框的内容。
.on('page', function(type="prompt", message, response))
Nightmare disables window.prompt
from popping up by default, but you can still listen for the message to come up. If you need to handle the confirmation differently, you'll need to use your own preload script.
Nightmare使得window.prompt默认不弹出,但你仍然可以听到消息出现。
如果您需要以不同方式处理确认,则需要使用自己的预加载脚本。
.on('page', function(type="confirm", message, response))
Nightmare disables window.confirm
from popping up by default, but you can still listen for the message to come up. If you need to handle the confirmation differently, you'll need to use your own preload script.
Nightmare使得window.prompt默认不弹出,但你仍然可以听到消息出现。
如果您需要以不同方式处理确认,则需要使用自己的预加载脚本。
.on('console', function(type [, arguments, ...]))
type
will be either log
, warn
or error
and arguments
are what gets passed from the console. This event is not triggered if the injected javascript code (e.g. via .evaluate()
) is using console.log
.
类型将是日志,警告或错误,参数是从控制台传递的。如果注入的JavaScript代码(例如,通过.evaluate())使用console.log,则不会触发此事件。
.once(event, callback)
Similar to .on()
, but captures page events with the callback one time.
与.on()类似,但一次捕获具有回调的页面事件。
.removeListener(event, callback)
Removes a given listener callback for an event.
删除给定事件的侦听器回调。
.screenshot([path][, clip])
Takes a screenshot of the current page. Useful for debugging. The output is always a png
. Both arguments are optional. If path
is provided, it saves the image to the disk. Otherwise it returns a Buffer
of the image data. If clip
is provided (as documented here), the image will be clipped to the rectangle.
截取当前页面的屏幕截图。用于调试。
输出总是一个PNG。
两个参数都是可选的。
如果提供路径,它将图像保存到磁盘。
否则它会返回图像数据的缓冲区。
如果提供剪辑(如此处所述),图像将被剪裁到矩形。
.html(path, saveType)
Saves the current page as html as files to disk at the given path. Save type options are here.
将当前页面保存为html,并将文件保存到指定路径的磁盘中。
保存类型选项在这里。
.pdf(path, options)
Saves a PDF to the specified path
. Options are here.
将PDF保存到指定的路径。
选项在这里。
.title()
Returns the title of the current page.
返回当前页面的标题。
.url()
Returns the url of the current page.
返回当前页面的网址。
.path()
Returns the path name of the current page.
返回当前页面的路径名称。
Cookies
.cookies.get(name)
Gets a cookie by it's name
. The url will be the current url.
通过它的名字获取一个cookie。
.cookies.get(query)
Queries multiple cookies with the query
object. If a query.name
is set, it will return the first cookie it finds with that name, otherwise it will query for an array of cookies. If no query.url
is set, it will use the current url. Here's an example:
用查询对象查询多个cookie。
如果设置了query.name,它将返回它找到的第一个cookie,否则它将查询一个cookie数组。
如果没有设置query.url,它将使用当前的url。
这是一个例子:
// get all google cookies that are secure // and have the path `/query` nightmare .goto('http://google.com') .cookies.get({ path: '/query', secure: true }) .then(cookies => { // do something with the cookies })
Available properties are documented here: https://github.com/atom/electron/blob/master/docs/api/session.md#sescookiesgetdetails-callback
这里记录可用的属性:
.cookies.get()
Gets all the cookies for the current url. If you'd like get all cookies for all urls, use: .get({ url: null })
.
获取当前网址的所有Cookie。如果您想为所有网址获取所有Cookie,请使用:.get({url:null})。
.cookies.set(name, value)
Sets a cookie's name
and value
. This is the most basic form, and the url will be the current url.
设置cookie的名称和值。这是最基本的形式,并且网址将成为当前网址。
.cookies.set(cookie)
Sets a cookie
. If cookie.url
is not set, it will set the cookie on the current url. Here's an example:
设置一个cookie。如果cookie.url未设置,它将在当前网址上设置cookie。这是一个例子:
nightmare .goto('http://google.com') .cookies.set({ name: 'token', value: 'some token', path: '/query', secure: true }) // ... other actions ... .then(() => { // ... })
Available properties are documented here: https://github.com/atom/electron/blob/master/docs/api/session.md#sescookiessetdetails-callback
这里记录可用的属性:
.cookies.set(cookies)
Sets multiple cookies at once. cookies
is an array of cookie
objects. Take a look at the .cookies.set(cookie)
documentation above for a better idea of what cookie
should look like.
一次设置多个Cookie。 cookie是一组cookie对象。查看上面的.cookies.set(cookie)文档,以更好地了解cookie应该是什么样子。
.cookies.clear([name])
Clears a cookie for the current domain. If name
is not specified, all cookies for the current domain will be cleared.
清除当前域的Cookie。如果未指定名称,则会清除当前域的所有Cookie。
nightmare .goto('http://google.com') .cookies.clear('SomeCookieName') // ... other actions ... .then(() => { // ... })
.cookies.clearAll()
Clears all cookies for all domains.
清除所有域的所有Cookie。
nightmare .goto('http://google.com') .cookies.clearAll() // ... other actions ... .then(() => { //... })
Proxies
Proxies are supported in Nightmare through switches.
If your proxy requires authentication you also need the authentication call.
The following example not only demonstrates how to use proxies, but you can run it to test if your proxy connection is working:
通过交换机在梦魇中支持代理。如果您的代理需要认证,您还需要认证呼叫。以下示例不仅演示了如何使用代理,但您可以运行它来测试代理连接是否正常工作:
import Nightmare from 'nightmare'; const proxyNightmare = Nightmare({ switches: { 'proxy-server': 'my_proxy_server.example.com:8080' // set the proxy server here ... }, show: true }); proxyNightmare .authentication('proxyUsername', 'proxyPassword') // ... and authenticate here before `goto` .goto('http://www.ipchicken.com') .evaluate(() => { return document.querySelector('b').innerText.replace(/[^\d\.]/g, ''); }) .end() .then((ip) => { // This will log the Proxy's IP console.log('proxy IP:', ip); }); // The rest is just normal Nightmare to get your local IP const regularNightmare = Nightmare({ show: true }); regularNightmare .goto('http://www.ipchicken.com') .evaluate(() => document.querySelector('b').innerText.replace(/[^\d\.]/g, ''); ) .end() .then((ip) => { // This will log the your local IP console.log('local IP:', ip); });
Promises ES6承诺
By default, Nightmare uses default native ES6 promises. You can plug in your favorite ES6-style promises library like bluebird or q for convenience!
默认情况下,Nightmare使用默认的本地ES6承诺。你可以插入你最喜欢的ES6风格的承诺库,如蓝鸟或Q为方便!
Here's an example:
var Nightmare = require('nightmare') Nightmare.Promise = require('bluebird') // OR: Nightmare.Promise = require('q').Promise
You can also specify a custom Promise library per-instance with the Promise
constructor option like so:
您还可以使用Promise构造函数选项为每个实例指定一个自定义Promise库,如下所示:
var Nightmare = require('nightmare') var es6Nightmare = Nightmare() var bluebirdNightmare = Nightmare({ Promise: require('bluebird') }) var es6Promise = es6Nightmare .goto('https://github.com/segmentio/nightmare') .then() var bluebirdPromise = bluebirdNightmare .goto('https://github.com/segmentio/nightmare') .then() es6Promise.isFulfilled() // throws: `TypeError: es6EndPromise.isFulfilled is not a function` bluebirdPromise.isFulfilled() // returns: `true | false`
Extending Nightmare
Nightmare.action(name, [electronAction|electronNamespace], action|namespace)
You can add your own custom actions to the Nightmare prototype. Here's an example:
您可以将自己的自定义操作添加到Nightmare原型中。这是一个例子:
Nightmare.action('size', function(done) { this.evaluate_now(() => { const w = Math.max( document.documentElement.clientWidth, window.innerWidth || 0 ) const h = Math.max( document.documentElement.clientHeight, window.innerHeight || 0 ) return { height: h, width: w } }, done) }) Nightmare() .goto('http://cnn.com') .size() .then(size => { //... do something with the size information })
Remember, this is attached to the static class
Nightmare
, not the instance.
You'll notice we used an internal function evaluate_now
. This function is different than nightmare.evaluate
because it runs it immediately, whereas nightmare.evaluate
is queued.
An easy way to remember: when in doubt, use evaluate
. If you're creating custom actions, use evaluate_now
. The technical reason is that since our action has already been queued and we're running it now, we shouldn't re-queue the evaluate function.
We can also create custom namespaces. We do this internally for nightmare.cookies.get
and nightmare.cookies.set
. These are useful if you have a bundle of actions you want to expose, but it will clutter up the main nightmare object. Here's an example of that:
请记住,这是附加到静态类Nightmare,而不是实例。你会注意到我们使用了一个内部函数evaluate_now。此功能与nightmare.evaluate不同,因为它立即运行它,而nightmare.evaluate已排队。一个简单的方法来记住:如有疑问,请使用评估。如果您正在创建自定义操作,请使用evaluate_now。技术上的原因是,由于我们的操作已经排队并且现在正在运行,所以我们不应该重新排列评估函数。我们也可以创建自定义名称空间。我们在内部为nightmare.cookies.get和nightmare.cookies.set执行此操作。如果你有一堆你想要暴露的动作,这些是很有用的,但它会混淆主要的nightmare对象。这是一个例子:
Nightmare.action('style', { background(done) { this.evaluate_now( () => window.getComputedStyle(document.body, null).backgroundColor, done ) } }) Nightmare() .goto('http://google.com') .style.background() .then(background => { // ... do something interesting with background })
You can also add custom Electron actions. The additional Electron action or namespace actions take name
, options
, parent
, win
, renderer
, and done
. Note the Electron action comes first, mirroring how .evaluate()
works. For example:
您还可以添加自定义Electron操作。额外的Electron动作或命名空间动作包括名称,选项,父级,获胜,渲染器和完成。请注意,Electron动作首先会反映.evaluate()如何工作。例如:
Nightmare.action( 'clearCache', (name, options, parent, win, renderer, done) => { parent.respondTo('clearCache', done => { win.webContents.session.clearCache(done) }) done() }, function(done) { this.child.call('clearCache', done) } ) Nightmare() .clearCache() .goto('http://example.org') //... more actions ... .then(() => { // ... })
...would clear the browser’s cache before navigating to example.org
.
See this document for more details on creating custom actions.
...在导航到example.org之前会清除浏览器的缓存。有关创建自定义操作的更多细节,请参阅此文档。
.use(plugin)
nightmare.use
is useful for reusing a set of tasks on an instance. Check out nightmare-swiftly for some examples.
nightmare.use用于重用实例上的一组任务。快速查看一些例子的噩梦。
Custom preload script自定义预加载脚本
If you need to do something custom when you first load the window environment, you
can specify a custom preload script. Here's how you do that:
如果您在第一次加载窗口环境时需要自定义某些内容,则可以指定自定义预加载脚本。你如何做到这一点:
import path from 'path' const nightmare = Nightmare({ webPreferences: { preload: path.resolve('custom-script.js') //alternative: preload: "absolute/path/to/custom-script.js" } })
The only requirement for that script is that you'll need the following prelude:
该脚本的唯一要求是您需要以下前奏:
window.__nightmare = {} __nightmare.ipc = require('electron').ipcRenderer
To benefit of all of nightmare's feedback from the browser, you can instead copy the contents of nightmare's preload script.
为了从浏览器中获得所有nightmare的反馈,您可以改为复制nightmare的预加载脚本的内容。
Storage Persistence between nightmare instances存储持久性之间的噩梦实例
By default nightmare will create an in-memory partition for each instance. This means that any localStorage or cookies or any other form of persistent state will be destroyed when nightmare is ended. If you would like to persist state between instances you can use the webPreferences.partition api in electron.
默认情况下,nightmare会为每个实例创建一个内存分区。这意味着,当nightmare结束时,任何localStorage或cookie或任何其他形式的持久状态都将被销毁。如果你想在实例之间保持状态,你可以在electron中使用webPreferences.partition api。
import Nightmare from 'nightmare'; nightmare = Nightmare(); // non persistent paritition by default yield nightmare .evaluate(() => { window.localStorage.setItem('testing', 'This will not be persisted'); }) .end(); nightmare = Nightmare({ webPreferences: { partition: 'persist: testing' } }); yield nightmare .evaluate(() => { window.localStorage.setItem('testing', 'This is persisted for other instances with the same paritition name'); }) .end();
If you specify a null
paritition then it will use the electron default behavior (persistent) or any string that starts with 'persist:'
will persist under that partition name, any other string will result in in-memory only storage.
如果你指定一个空分区,那么它将使用electron默认行为(持久化),或者以'persist:'开头的任何字符串将保留在该分区名称下,任何其他字符串将导致仅存储在内存中。
Usage
Installation
Nightmare is a Node.js module, so you'll need to have Node.js installed. Then you just need to npm install
the module:
安装Nightmare是一个Node.js模块,所以你需要安装Node.js。那么你只需要npm安装模块:
$ npm install --save nightmare
Execution
Nightmare is a node module that can be used in a Node.js script or module. Here's a simple script to open a web page:
执行Nightmare是一个节点模块,可以在Node.js脚本或模块中使用。这里有一个简单的脚本来打开一个网页:
import Nightmare from 'nightmare'; const nightmare = Nightmare(); nightmare.goto('http://cnn.com') .evaluate(() => { return document.title; }) .end() .then((title) => { console.log(title); })
If you save this as cnn.js
, you can run it on the command line like this:
如果你把它保存为cnn.js,你可以像这样在命令行上运行它:
npm install --save nightmare node cnn.js
Common Execution Problems
Nightmare heavily relies on Electron for heavy lifting. And Electron in turn relies on several UI-focused dependencies (eg. libgtk+) which are often missing from server distros.
For help running nightmare on your server distro check out How to run nightmare on Amazon Linux and CentOS guide.
常见执行问题Nightmare很大程度上依赖于Electron来举重。而Electron依赖于几个基于UI的依赖项(例如libgtk +),这些依赖项通常从服务器发行版中丢失。如需帮助在服务器上运行Nightmare发行版,请查看如何在Amazon Linux和CentOS指南上运行Nightmare。
Debugging
There are three good ways to get more information about what's happening inside the headless browser:
- Use the
DEBUG=*
flag described below. - Pass
{ show: true }
to the nightmare constructor to have it create a visible, rendered window where you can watch what is happening. - Listen for specific events.
To run the same file with debugging output, run it like this DEBUG=nightmare node cnn.js
(on Windows use set DEBUG=nightmare & node cnn.js
).
This will print out some additional information about what's going on:
有三种好方法可以获得关于无头浏览器内发生的更多信息:使用下面描述的DEBUG = *标志。将{show:true}传给梦魇构造函数,让它创建一个可见的渲染窗口,在那里你可以看到发生了什么。倾听特定事件。要使用调试输出运行相同的文件,请像这样运行DEBUG = nightmare节点cnn.js(在Windows上使用set DEBUG = nightmare&node cnn.js)。这将打印出一些关于正在发生的更多信息:
nightmare queueing action "goto" +0ms nightmare queueing action "evaluate" +4ms Breaking News, U.S., World, Weather, Entertainment & Video News - CNN.com
Debug Flags调试标志
All nightmare messages所有nightmare信息
DEBUG=nightmare*
Only actions只有行动
DEBUG=nightmare:actions*
Only logs只有日志
DEBUG=nightmare:log*
Additional Resources其他资源
Ross Hinkley's Nightmare Examples is a great resource for setting up nightmare, learning about custom actions, and avoiding common pitfalls.
Nightmare Issues has a bunch of standalone runnable examples. The script numbers correspond to nightmare issue numbers.
Nightmarishly good scraping is a great tutorial by Ændrew Rininsland on getting up & running with Nightmare using real-life data.
罗斯欣克利的噩梦示例是设置恶梦,了解自定义操作以及避免常见陷阱的绝佳资源。Nightmare问题有许多独立的可运行示例。脚本编号对应于噩梦问题编号。噩梦般的好消息是ÆndrewRininsland通过使用真实数据在梦魇中起床和运行的绝佳教程。
Tests
Automated tests for nightmare itself are run using Mocha and Chai, both of which will be installed via npm install
. To run nightmare's tests, just run make test
.
When the tests are done, you'll see something like this:
恶梦本身的自动测试使用Mocha和Chai进行,两者都将通过npm install进行安装。要运行恶梦的测试,只需运行make test。测试完成后,您会看到如下所示的内容:
make test ․․․․․․․․․․․․․․․․․․ 18 passing (1m)
Note that if you are using xvfb
, make test
will automatically run the tests under an xvfb-run
wrapper. If you are planning to run the tests headlessly without running xvfb
first, set the HEADLESS
environment variable to 0
.
请注意,如果您使用的是xvfb,则make test会自动运行xvfb运行包装下的测试。如果您计划在无需首先运行xvfb的情况下无头运行测试,请将HEADLESS环境变量设置为0。
License (MIT)
WWWWWW||WWWWWW W W W||W W W || ( OO )__________ / | \ /o o| MIT \ \___/||_||__||_|| * || || || || _||_|| _||_|| (__|__|(__|__|
Copyright (c) 2015 Segment.io, Inc. mailto:friends@segment.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
来源:https://www.cnblogs.com/shen55/p/12241695.html