puppeteer page.evaluate-获得进展

时间:2019-03-28 08:08:05

标签: javascript puppeteer

我有以下代码尝试从puppeteer的当前页面获取数组缓冲区:

await page.evaluate(cb => {

    var x = new XMLHttpRequest();
    var url = location.href;
    x.onreadystatechange = function(){
        console.log((x.response));
    }
    x.responseType="arraybuffer";
    x.open("GET",url,true);
    x.send("");
});

当前,我正在尝试捕获console.log以获取响应:

page.on("console", c => {
    console.log("Consoling", c._args[0]._remoteObject); //thought this would get the arraybuffer
});

尽管它没有给我实际的arraybuffer对象,但是(如果我只是这样做的话)就是这样:

Consoling [ JSHandle {
    _context:
     ExecutionContext { _client: [CDPSession], _world: [DOMWorld], _contextId: 3 },
    _client:
     CDPSession {
       _events: [Object],
       _eventsCount: 27,
       _maxListeners: undefined,
       _callbacks: Map {},
       _connection: [Connection],
       _targetType: 'page',
       _sessionId: '817AEFBC94D1B52BC15559269CB67A61' },
    _remoteObject:
     { type: 'object',
       subtype: 'arraybuffer',
       className: 'ArrayBuffer',
       description: 'ArrayBuffer(40285)',
       objectId: '{"injectedScriptId":3,"id":1}',
       preview: [Object] },
    _disposed: false } ]

以及当前console.log(c [0] ._ remoteObject)的以下内容:

Consoling { type: 'object',
  subtype: 'arraybuffer',
  className: 'ArrayBuffer',
  description: 'ArrayBuffer(40285)',
  objectId: '{"injectedScriptId":3,"id":1}',
  preview:
   { type: 'object',
     subtype: 'arraybuffer',
     description: 'ArrayBuffer(40285)',
     overflow: false,
     properties: [] } }

这给了我一些我可能在控制台中看到的arrabuffer liek的漂亮描述(在扩展对象之前),但是我猜想它在整个过程中都运行JSON.stringify,所以我猜到了arraybuffer数据丢失了吗?

是否有任何其他方法可以从page.evaluate中获取页面数据,而不只是在解析结束时进行评估?如何获得在页面上生成的arraybuffer对象?我是否只需将其通过另一个XMLHTTPRequest或websocket发送回服务器?

1 个答案:

答案 0 :(得分:0)

类型化数组

rsp摘录自this answer

  

没有JSON格式的ArrayBuffer(只有字符串,数字,布尔值,null,对象和数组),因此,如果要以JSON保存ArrayBuffer,则必须以其中一种类型表示(可能字符串或数字数组。

     

然后,当您读取JSON时,必须将其转换回ArrayBuffer,并逆转之前所做的转换。

在puppeteer中,所有内容都被序列化,因此上下文丢失。您不能在节点和浏览器中共享相同的引用。

因此,我们可以将类型化的数组转换为字符串(或base64字符串),然后将其传递给我们,只要我们获得该值,就可以将其简单地转换回去。

如您所见,这会将您的字符串转换为Uint8Array。但是,要转换为其他类型,很遗憾,您将不得不自己编写代码,因为只有您知道响应的结构。

const stringToArray = (str) => new Uint8Array([...str].map(char => char.charCodeAt(0)));

所以您可以这样登录

await page.evaluate(() => {
    var typedArrayExample = new Uint8Array(2);
    typedArrayExample[0] = 15;
    typedArrayExample[1] = 20;
    // typedArrayExample should be Uint8Array(2) [15, 20]
    // typeof typedArrayExample === "object"
    // typedArrayExample.constructor === Uint8Array

    if (typedArrayExample.constructor === Uint8Array) {
      console.log(String.fromCharCode(...typedArrayExample))
    }
})

page.on('console')事件,

page.on("console", c => {
    console.log(c.args())
    const {
      value
    } = c._args[0]._remoteObject;
    // convert the string back
    console.log("Consoling", stringToArray(value));
});

现在运行此命令将导致

Consoling Uint8Array [ 15, 20 ]

Websocket / Ajax请求

您可以使用ws软件包创建一个websocket服务器,

const WebSocket = require("ws");

const wss = new WebSocket.Server({
  port: 8081
});

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: ', new Uint8Array(message));
  });
});

然后将页面中的二进制数据发送到该websocket,

await page.evaluate(() => {
    const ws = new WebSocket('ws://localhost:8081');

    ws.onopen = function open() {
      const array = new Uint8Array(2);
      array[0] = 15;
      array[1] = 20;

      ws.send(array);
    }
})

结果:

received:  Uint8Array [ 15, 20 ]

确保随后关闭连接。您还可以利用多个chrome标签页/页面来避免与cors相关的问题。 :)

您将收到一个缓冲区,可以将其转换为