How to get console.log output in Terminal via Headless Chrome Runtime.evaluate

吃可爱长大的小学妹 提交于 2019-12-04 22:37:34

问题


I am following this issue post here:

https://github.com/cyrus-and/chrome-remote-interface/issues/105

But I cannot seem to get console.log output in the Mac Terminal. It's probably inside the Chrome Devtools window which I don't see.

So how do I get console.log output in Mac Terminal via Runtime.evaluate expression?

My code below:

const chromeLauncher = require('chrome-launcher');
const CDP = require('chrome-remote-interface');
const file = require('fs');

(async function() {
  async function launchChrome() {
    return await chromeLauncher.launch({
      chromeFlags: [
        '--headless',
        '--disable-gpu'
      ]
    });
  }
  const chrome = await launchChrome();
  const protocol = await CDP({
    port: chrome.port
  });

  const {
    DOM,
    Network,
    Page,
    Emulation,
    Runtime
  } = protocol;

  await Promise.all([Network.enable(), Page.enable(), Runtime.enable(), DOM.enable()]);

  Page.navigate({url: 'https://www.chromestatus.com/'});

  Page.loadEventFired(async () => {
    const result = await Runtime.evaluate({expression: 'console.log(\'aaa\')'});

    protocol.close();
    chrome.kill(); 
  });

})();

回答1:


I've been doing some research on this; below are some of my findings:

When evaluating:

const result = await Runtime.evaluate({ expression: 'console.log("aaa")' });

Result is always:

{ result: { type: 'undefined' } }

However, the following expression:

const result = await Runtime.evaluate({expression: 'window.location.toString()'});

Returns:

{ result: { type: 'string', value: 'https://www.chromestatus.com/features' } }

Now if I evaluate the function without invoking it:

const result = await Runtime.evaluate({ expression: 'console.log' });

Result is set to:

{ result: { type: 'function', className: 'Function', description: 'function log() { [native code] }', objectId: '{"injectedScriptId":2,"id":1}' } }

So I did some more digging, and found that every time console.log is invoked when evaluated, the messageAdded event on the Console object is always fired.

So I went ahead and enabled the Console object and added a listener to the messageAdded event, and now I can successfully capture the console entry as expected.

This is what I did:

const chromeLauncher = require('chrome-launcher');
const CDP = require('chrome-remote-interface');
const file = require('fs');

(async function() {
  async function launchChrome() {
    return await chromeLauncher.launch({
      chromeFlags: [
        '--headless',
        '--disable-gpu'
      ]
    });
  }
  const chrome = await launchChrome();
  const protocol = await CDP({
    port: chrome.port
  });

  const {
    DOM,
    Network,
    Page,
    Emulation,
    Runtime,
    Console
  } = protocol;

  await Promise.all([Network.enable(), Page.enable(), DOM.enable(), Runtime.enable(), Console.enable()]);

  await Page.navigate({url: 'https://www.chromestatus.com/'});

  // REMARKS: messageAdded is fired every time a new console message is added
  Console.messageAdded((result) => {
    console.log(result);
  });

  Page.loadEventFired(async () => {
    const result = await Runtime.evaluate({ expression: 'console.log("aaa")' });

    // REMARKS: When evaluating console.log, result.result.value is undefined.
    console.log(result);

    protocol.close();
    chrome.kill(); 
  });

})();

/* Output from listening on messageAdded:
{ message: 
   { source: 'console-api',
     level: 'log',
     text: 'aaa',
     url: '',
     line: 1,
     column: 9 } }
*/

I got the details from Chrome DevTools Protocol Viewer - Console

From the documentation:

Console.messageAdded

Issued when new console message is added.

Hope this helps!




回答2:


For those who want a less complicated way to get data from a page I'd recommend puppeteer. It has a much clearer higher-level API than chrome-remote-interface. The best feature in my opinion is its ability to accept javascript functions instead of strings for evaluation.

Let's say we want to fetch some data from API in context of a given page.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com/');

  let result = await page.evaluate(async () => {
    // here comes the code which gets executed in browser
    return await fetch('index.html').then(response => response.text());
  });

  console.log(result);

  await browser.close();
})();


来源:https://stackoverflow.com/questions/45621694/how-to-get-console-log-output-in-terminal-via-headless-chrome-runtime-evaluate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!