Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Chrome Debugging Protocol interface for Node.js

License

NotificationsYou must be signed in to change notification settings

cyrus-and/chrome-remote-interface

Repository files navigation

CI status

Chrome Debugging Protocol interface that helps to instrument Chrome (or anyother suitableimplementation) by providing a simpleabstraction of commands and notifications using a straightforward JavaScriptAPI.

Sample API usage

The following snippet loadshttps://github.com and dumps every request made:

constCDP=require('chrome-remote-interface');asyncfunctionexample(){letclient;try{// connect to endpointclient=awaitCDP();// extract domainsconst{Network, Page}=client;// setup handlersNetwork.requestWillBeSent((params)=>{console.log(params.request.url);});// enable events then start!awaitNetwork.enable();awaitPage.enable();awaitPage.navigate({url:'https://github.com'});awaitPage.loadEventFired();}catch(err){console.error(err);}finally{if(client){awaitclient.close();}}}example();

Find more examples in thewiki. You may also want to take a look at theFAQ.

Installation

npm install chrome-remote-interface

Install globally (-g) to just use thebundled client.

Implementations

This module should work with every application implementing theChrome Debugging Protocol. In particular, it has been tested against thefollowing implementations:

ImplementationProtocol versionProtocolListNewActivateCloseVersion
Chrometip-of-treeyes¹yesyesyesyesyes
Operatip-of-treeyesyesyesyesyesyes
Node.js (v6.3.0+)nodeyesnonononoyes
Safari (iOS)partialnoyesnononono
Edgepartialyesyesnononoyes
Firefox (Nightly)partialyesyesnoyesyesyes

¹ Not available onChrome for Android, hence a local version of the protocol must be used.

The meaning oftarget varies according to the implementation, for example,each Chrome tab represents a target whereas for Node.js a target is thecurrently inspected script.

Setup

An instance of either Chrome itself or another implementation needs to berunning on a known port in order to use this module (defaults tolocalhost:9222).

Chrome/Chromium

Desktop

Start Chrome with the--remote-debugging-port option, for example:

google-chrome --remote-debugging-port=9222
Headless

Since version 59, additionally use the--headless option, for example:

google-chrome --headless --remote-debugging-port=9222

Android

Plug the device and make sure to authorize the connection from the device itself. Thenenable the port forwarding, for example:

adb -d forward tcp:9222 localabstract:chrome_devtools_remote

After that you should be able to usehttp://127.0.0.1:9222 as usual, but note that inAndroid, Chrome does not have its own protocol available, so a local version must be used.Seehere for more information.

WebView

In order to be inspectable, a WebView mustbeconfigured for debugging and the corresponding process ID must beknown. There are several ways to obtain it, for example:

adb shell grep -a webview_devtools_remote /proc/net/unix

Finally, port forwarding can be enabled as follows:

adb forward tcp:9222 localabstract:webview_devtools_remote_<pid>

Opera

Start Opera with the--remote-debugging-port option, for example:

opera --remote-debugging-port=9222

Node.js

Start Node.js with the--inspect option, for example:

node --inspect=9222 script.js

Safari (iOS)

Install and run theiOS WebKit Debug Proxy. Then use it with thelocaloption set totrue to use the local version of the protocol or pass a customdescriptor upon connection (protocol option).

Edge

Start Edge with the--devtools-server-port option, for example:

MicrosoftEdge.exe --devtools-server-port 9222 about:blank

Please find more informationhere.

Firefox (Nightly)

Start Firefox with the--remote-debugging-port option, for example:

firefox --remote-debugging-port 9222

Bear in mind that this is an experimental feature of Firefox.

Bundled client

This module comes with a bundled client application that can be used tointeractively control a remote instance.

Target management

The bundled client exposes subcommands to interact with the HTTP frontend(e.g.,List,New, etc.),run with--help to display the list of available options.

Here are some examples:

$chrome-remote-interfacenew'http://example.com'{"description":"","devtoolsFrontendUrl":"/devtools/inspector.html?ws=localhost:9222/devtools/page/b049bb56-de7d-424c-a331-6ae44cf7ae01","id":"b049bb56-de7d-424c-a331-6ae44cf7ae01","thumbnailUrl":"/thumb/b049bb56-de7d-424c-a331-6ae44cf7ae01","title":"","type":"page","url":"http://example.com/","webSocketDebuggerUrl":"ws://localhost:9222/devtools/page/b049bb56-de7d-424c-a331-6ae44cf7ae01"}$chrome-remote-interfaceclose'b049bb56-de7d-424c-a331-6ae44cf7ae01'

Inspection

Using theinspect subcommand it is possible to performcommand executionandevent binding in a REPL fashion that provides completion.

Here is a sample session:

$chrome-remote-interfaceinspect>>>Runtime.evaluate({expression:'window.location.toString()'}){result:{type:'string',value:'about:blank'}}>>>Page.enable(){}>>>Page.loadEventFired(console.log)[Function]>>>Page.navigate({url:'https://github.com'}){frameId:'E1657E22F06E6E0BE13DFA8130C20298',loaderId:'439236ADE39978F98C20E8939A32D3A5'}>>>{timestamp:7454.721299}// from Page.loadEventFired>>>Runtime.evaluate({expression:'window.location.toString()'}){result:{type:'string',value:'https://github.com/'}}

Additionally there are some custom commands available:

>>>.help[...].resetRemovealltheregisteredeventhandlers.targetDisplaythecurrenttarget

Embedded documentation

In both the REPL and the regular API every object of the protocol isdecoratedwith the meta information found within the descriptor. In addition Thecategory field is added, which determines if the member is acommand, anevent or atype.

For example to learn how to callPage.navigate:

>>>Page.navigate{[Function]  category:'command',parameters:{url:{type:'string',description:'URL to navigate the page to.'}},returns:[{name:'frameId','$ref':'FrameId',hidden:true,description:'Frame id that will be navigated.'}],description:'Navigates current page to the given URL.',handlers:['browser','renderer']}

To learn about the parameters returned by theNetwork.requestWillBeSent event:

>>>Network.requestWillBeSent{[Function]  category:'event',description:'Fired when page is about to send HTTP request.',parameters:{requestId:{'$ref':'RequestId',description:'Request identifier.'},frameId:{'$ref':'Page.FrameId',description:'Frame identifier.',hidden:true},loaderId:{'$ref':'LoaderId',description:'Loader identifier.'},documentURL:{type:'string',description:'URL of the document this request is loaded for.'},request:{'$ref':'Request',description:'Request data.'},timestamp:{'$ref':'Timestamp',description:'Timestamp.'},wallTime:{'$ref':'Timestamp',hidden:true,description:'UTC Timestamp.'},initiator:{'$ref':'Initiator',description:'Request initiator.'},redirectResponse:{optional:true,'$ref':'Response',description:'Redirect response data.'},type:{'$ref':'Page.ResourceType',optional:true,hidden:true,description:'Type of this resource.'}}}

To inspect theNetwork.Request (note that unlike commands and events, typesare named in upper camel case) type:

>>>Network.Request{category:'type',id:'Request',type:'object',description:'HTTP request data.',properties:{url:{type:'string',description:'Request URL.'},method:{type:'string',description:'HTTP request method.'},headers:{'$ref':'Headers',description:'HTTP request headers.'},postData:{type:'string',optional:true,description:'HTTP POST request data.'},mixedContentType:{optional:true,type:'string',enum:[Object],description:'The mixed content status of the request, as defined in http://www.w3.org/TR/mixed-content/'},initialPriority:{'$ref':'ResourcePriority',description:'Priority of the resource request at the time request is sent.'}}}

Chrome Debugging Protocol versions

By defaultchrome-remote-interfaceasks the remote instance to provide itsown protocol.

This behavior can be changed by setting thelocal option totrueuponconnection, in which case thelocal version ofthe protocol descriptor is used. This file is manually updated from time to timeusingscripts/update-protocol.sh and pushed to this repository.

To further override the above behavior there are basically two options:

  • pass a custom protocol descriptor uponconnection(protocol option);

  • use theraw version of thecommandsandevents interface to use bleeding-edge features thatdo not appear in thelocal version of the protocol descriptor;

Browser usage

This module is able to run within a web context, with obvious limitationsthough, namely external HTTP requests(List,New, etc.) cannotbe performed directly, for this reason the user must provide a globalcriRequest in order to use them:

functioncriRequest(options,callback){}

options is the same object used by the Node.jshttp module andcallback isa function taking two arguments:err (JavaScriptError object ornull) anddata (string result).

Usingwebpack

It just works, simply require this module:

constCDP=require('chrome-remote-interface');

Usingvanilla JavaScript

To generate a JavaScript file that can be used with a<script> element:

  1. runnpm install from the root directory;

  2. manually run webpack with:

     TARGET=var npm run webpack
  3. use as:

    <script>functioncriRequest(options,callback){/*...*/}</script><scriptsrc="chrome-remote-interface.js"></script>

TypeScript Support

TypeScript definitions are kindly provided byKhairul Azhar Kasmiran andSeth Westphal, and can be installed fromDefinitelyTyped:

npm install --save-dev @types/chrome-remote-interface

Note that the TypeScript definitions are automatically generated from the npm packagedevtools-protocol@0.0.927104. For other versions of devtools-protocol:

  1. Install patch-package usingthe instructions given.
  2. Copy the contents of the correspondinghttps://github.com/ChromeDevTools/devtools-protocol/tree/master/types folder (according to commit) intonode_modules/devtools-protocol/types.
  3. Runnpx patch-package devtools-protocol so that the changes persist across annpm install.

API

The API consists of three parts:

CDP([options], [callback])

Connects to a remote instance using theChrome Debugging Protocol.

options is an object with the following optional properties:

  • host: HTTP frontend host. Defaults tolocalhost;

  • port: HTTP frontend port. Defaults to9222;

  • secure: HTTPS/WSS frontend. Defaults tofalse;

  • useHostName: do not perform a DNS lookup of the host. Defaults tofalse;

  • alterPath: afunction taking and returning the path fragment of a URLbefore that a request happens. Defaults to the identity function;

  • target: determines which target this client should attach to. The behaviorchanges according to the type:

    • afunction that takes the array returned by theList method and returnsa target or its numeric index relative to the array;
    • a targetobject like those returned by theNew andList methods;
    • astring representing the raw WebSocket URL, in this casehost andport are not used to fetch the target list, yet they are used to completethe URL if relative;
    • astring representing the target id.

    Defaults to a function which returns the first available target according tothe implementation (note that at most one connection can be established to thesame target);

  • protocol:Chrome Debugging Protocol descriptor object. Defaults to use theprotocol chosen according to thelocal option;

  • local: a boolean indicating whether the protocol must be fetchedremotelyor if the local version must be used. It has no effect if theprotocoloption is set. Defaults tofalse.

These options are also valid properties of all the instances of theCDPclass. In addition to that, thewebSocketUrl field contains the currently usedWebSocket URL.

callback is a listener automatically added to theconnect event of thereturnedEventEmitter. Whencallback is omitted aPromise object isreturned which becomes fulfilled if theconnect event is triggered andrejected if theerror event is triggered.

TheEventEmitter supports the following events:

Event: 'connect'

function(client){}

Emitted when the connection to the WebSocket is established.

client is an instance of theCDP class.

Event: 'error'

function(err){}

Emitted whenhttp://host:port/json cannot be reached or if it is not possibleto connect to the WebSocket.

err is an instance ofError.

CDP.Protocol([options], [callback])

Fetch theChrome Debugging Protocol descriptor.

options is an object with the following optional properties:

  • host: HTTP frontend host. Defaults tolocalhost;
  • port: HTTP frontend port. Defaults to9222;
  • secure: HTTPS/WSS frontend. Defaults tofalse;
  • useHostName: do not perform a DNS lookup of the host. Defaults tofalse;
  • alterPath: afunction taking and returning the path fragment of a URLbefore that a request happens. Defaults to the identity function;
  • local: a boolean indicating whether the protocol must be fetchedremotelyor if the local version must be returned. Defaults tofalse.

callback is executed when the protocol is fetched, it gets the followingarguments:

Whencallback is omitted aPromise object is returned.

For example:

constCDP=require('chrome-remote-interface');CDP.Protocol((err,protocol)=>{if(!err){console.log(JSON.stringify(protocol,null,4));}});

CDP.List([options], [callback])

Request the list of the available open targets/tabs of the remote instance.

options is an object with the following optional properties:

  • host: HTTP frontend host. Defaults tolocalhost;
  • port: HTTP frontend port. Defaults to9222;
  • secure: HTTPS/WSS frontend. Defaults tofalse;
  • useHostName: do not perform a DNS lookup of the host. Defaults tofalse;
  • alterPath: afunction taking and returning the path fragment of a URLbefore that a request happens. Defaults to the identity function.

callback is executed when the list is correctly received, it gets thefollowing arguments:

  • err: aError object indicating the success status;
  • targets: the array returned byhttp://host:port/json/list containing thetarget list.

Whencallback is omitted aPromise object is returned.

For example:

constCDP=require('chrome-remote-interface');CDP.List((err,targets)=>{if(!err){console.log(targets);}});

CDP.New([options], [callback])

Create a new target/tab in the remote instance.

options is an object with the following optional properties:

  • host: HTTP frontend host. Defaults tolocalhost;
  • port: HTTP frontend port. Defaults to9222;
  • secure: HTTPS/WSS frontend. Defaults tofalse;
  • useHostName: do not perform a DNS lookup of the host. Defaults tofalse;
  • alterPath: afunction taking and returning the path fragment of a URLbefore that a request happens. Defaults to the identity function;
  • url: URL to load in the new target/tab. Defaults toabout:blank.

callback is executed when the target is created, it gets the followingarguments:

  • err: aError object indicating the success status;
  • target: the object returned byhttp://host:port/json/new containing thetarget.

Whencallback is omitted aPromise object is returned.

For example:

constCDP=require('chrome-remote-interface');CDP.New((err,target)=>{if(!err){console.log(target);}});

CDP.Activate([options], [callback])

Activate an open target/tab of the remote instance.

options is an object with the following properties:

  • host: HTTP frontend host. Defaults tolocalhost;
  • port: HTTP frontend port. Defaults to9222;
  • secure: HTTPS/WSS frontend. Defaults tofalse;
  • useHostName: do not perform a DNS lookup of the host. Defaults tofalse;
  • alterPath: afunction taking and returning the path fragment of a URLbefore that a request happens. Defaults to the identity function;
  • id: Target id. Required, no default.

callback is executed when the response to the activation request isreceived. It gets the following arguments:

  • err: aError object indicating the success status;

Whencallback is omitted aPromise object is returned.

For example:

constCDP=require('chrome-remote-interface');CDP.Activate({id:'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'},(err)=>{if(!err){console.log('target is activated');}});

CDP.Close([options], [callback])

Close an open target/tab of the remote instance.

options is an object with the following properties:

  • host: HTTP frontend host. Defaults tolocalhost;
  • port: HTTP frontend port. Defaults to9222;
  • secure: HTTPS/WSS frontend. Defaults tofalse;
  • useHostName: do not perform a DNS lookup of the host. Defaults tofalse;
  • alterPath: afunction taking and returning the path fragment of a URLbefore that a request happens. Defaults to the identity function;
  • id: Target id. Required, no default.

callback is executed when the response to the close request is received. Itgets the following arguments:

  • err: aError object indicating the success status;

Whencallback is omitted aPromise object is returned.

For example:

constCDP=require('chrome-remote-interface');CDP.Close({id:'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'},(err)=>{if(!err){console.log('target is closing');}});

Note that the callback is fired when the target isqueued for removal, but theactual removal will occur asynchronously.

CDP.Version([options], [callback])

Request version information from the remote instance.

options is an object with the following optional properties:

  • host: HTTP frontend host. Defaults tolocalhost;
  • port: HTTP frontend port. Defaults to9222;
  • secure: HTTPS/WSS frontend. Defaults tofalse;
  • useHostName: do not perform a DNS lookup of the host. Defaults tofalse;
  • alterPath: afunction taking and returning the path fragment of a URLbefore that a request happens. Defaults to the identity function.

callback is executed when the version information is correctly received, itgets the following arguments:

  • err: aError object indicating the success status;
  • info: a JSON object returned byhttp://host:port/json/version containingthe version information.

Whencallback is omitted aPromise object is returned.

For example:

constCDP=require('chrome-remote-interface');CDP.Version((err,info)=>{if(!err){console.log(info);}});

Class: CDP

Event: 'event'

function(message){}

Emitted when the remote instance sends any notification through the WebSocket.

message is the object received, it has the following properties:

  • method: a string describing the notification (e.g.,'Network.requestWillBeSent');
  • params: an object containing the payload;
  • sessionId: an optional string representing the session identifier.

Refer to theChrome Debugging Protocol specification for more information.

For example:

client.on('event',(message)=>{if(message.method==='Network.requestWillBeSent'){console.log(message.params);}});

Event: '<domain>.<method>'

function(params,sessionId){}

Emitted when the remote instance sends a notification for<domain>.<method>through the WebSocket.

params is an object containing the payload.

sessionId is an optional string representing the session identifier.

This is just a utility event which allows to easily listen for specificnotifications (see'event'), for example:

client.on('Network.requestWillBeSent',console.log);

Additionally, the equivalent<domain>.on('<method>', ...) syntax is available, for example:

client.Network.on('requestWillBeSent',console.log);

Event: '<domain>.<method>.<sessionId>'

function(params,sessionId){}

Equivalent to the following but only for those events belonging to the givensession:

client.on('<domain>.<event>',callback);

Event: 'ready'

function(){}

Emitted every time that there are no more pending commands waiting for aresponse from the remote instance. The interaction is asynchronous so the onlyway to serialize a sequence of commands is to use the callback provided bythesend method. This event acts as abarrier and it is useful to avoid thecallback hell in certain simplesituations.

Users are encouraged to extensively check the response of each method and shouldprefer the promises API when dealing with complex asynchronous program flows.

For example to load a URL only after having enabled the notifications of bothNetwork andPage domains:

client.Network.enable();client.Page.enable();client.once('ready',()=>{client.Page.navigate({url:'https://github.com'});});

In this particular case, not enforcing this kind of serialization may cause thatthe remote instance does not properly deliver the desired notifications theclient.

Event: 'disconnect'

function(){}

Emitted when the instance closes the WebSocket connection.

This may happen for example when the user opens DevTools or when the tab isclosed.

client.send(method, [params], [sessionId], [callback])

Issue a command to the remote instance.

method is a string describing the command.

params is an object containing the payload.

sessionId is a string representing the session identifier.

callback is executed when the remote instance sends a response to thiscommand, it gets the following arguments:

  • error: a boolean value indicating the success status, as reported by theremote instance;
  • response: an object containing either the response (result field, iferror === false) or the indication of the error (error field, iferror === true).

Whencallback is omitted aPromise object is returned instead, with thefulfilled/rejected states implemented according to theerror parameter. TheError object returned contains two additional parameters:request andresponse which contain the raw massages, useful for debugging purposes. Incase of low-level WebSocket errors, theerror parameter contains theoriginatingError object and noresponse is returned.

Note that the fieldid mentioned in theChrome Debugging Protocolspecification is managed internally and it is not exposed to the user.

For example:

client.send('Page.navigate',{url:'https://github.com'},console.log);

client.<domain>.<method>([params], [sessionId], [callback])

Just a shorthand for:

client.send('<domain>.<method>',params,sessionId,callback);

For example:

client.Page.navigate({url:'https://github.com'},console.log);

client.<domain>.<event>([sessionId], [callback])

Just a shorthand for:

client.on('<domain>.<event>[.<sessionId>]',callback);

Whencallback is omitted the event is registered only once and aPromiseobject is returned. Notice though that in this case the optionalsessionId usually passed tocallback is not returned.

Whencallback is provided, it returns a function that can be used tounsubscribecallback from the event, it can be useful when anonymous functionsare used as callbacks.

For example:

constunsubscribe=client.Network.requestWillBeSent((params,sessionId)=>{console.log(params.request.url);});unsubscribe();

client.close([callback])

Close the connection to the remote instance.

callback is executed when the WebSocket is successfully closed.

Whencallback is omitted aPromise object is returned.

client['<domain>.<name>']

Just a shorthand for:

client.<domain>.<name>

Where<name> can be a command, an event, or a type.

FAQ

InvokingDomain.methodOrEvent I obtainDomain.methodOrEvent is not a function

This means that you are trying to use a method or an event that are not presentin the protocol descriptor that you are using.

If the protocol is fetched from Chrome directly, then it means that this versionof Chrome does not support that feature. The solution is to update it.

If you are using a local or custom version of the protocol, then it means thatthe version is obsolete. The solution is to provide an up-to-date one, or if youare using the protocol embedded in chrome-remote-interface, make sure to berunning the latest version of this module. In case the embedded protocol isobsolete, pleasefile an issue.

Seehere for more information.

InvokingDomain.method I obtainDomain.method wasn't found

This means that you are providing a custom or local protocol descriptor(CDP({protocol: customProtocol})) which declaresDomain.method while theChrome version that you are using does not support it.

To inspect the currently available protocol descriptor use:

$ chrome-remote-interface inspect

Seehere for more information.

Why my program stalls or behave unexpectedly if I run Chrome in a Docker container?

This happens because the size of/dev/shm is set to 64MB by default in Dockerand may not be enough for Chrome to navigate certain web pages.

You can change this value by running your container with, say,--shm-size=256m.

UsingRuntime.evaluate withawaitPromise: true I sometimes obtainError: Promise was collected

This is thrown byRuntime.evaluate when the browser-side promise getscollected by the Chrome's garbage collector, this happens when the wholeJavaScript execution environment is invalidated, e.g., a when page is navigatedor reloaded while a promise is still waiting to be resolved.

Here is an example:

$ chrome-remote-interface inspect>>> Runtime.evaluate({expression: `new Promise(() => {})`, awaitPromise: true})>>> Page.reload() // then wait several seconds{ result: {} }{ error: { code: -32000, message: 'Promise was collected' } }

To fix this, just make sure there are no pending promises before closing,reloading, etc. a page.

How does this compare to Puppeteer?

Puppeteer is an additional high-level API built upon theChrome DebuggingProtocol which, among the other things, may start and use a bundled version ofChromium instead of the one installed on your system. Use it if its API meetsyour needs as it would probably be easier to work with.

chrome-remote-interface instead is just a general purpose 1:1 Node.js bindingfor theChrome Debugging Protocol. Use it if you need all the power of the rawprotocol, e.g., to implement your own high-level API.

See#240 for a more thorough discussion.

Contributors

Resources


[8]ページ先頭

©2009-2025 Movatter.jp