ElementHandle。$ eval pageFunction未执行

时间:2018-07-14 20:40:37

标签: javascript puppeteer

我正在使用Puppeteer 1.6.0版解析html表

// inside the rowMarket variable I store all the rows of a table
rowMarket = await.page.$$('#searchTextResults > tbody > tr');

现在,我想遍历所有这些,并获取每一行的某些td列的文本。

如果我使用以下代码,一切正常。

for(i=0<rowMarket.length;i++){
  nameComponent = await rowMarket[i].$('td:nth-child(1) > a');
  iT = await nameComponent .getProperty('innerText');
  json = await iT.jsonValue();

  otherComponent = await rowMarket[i].$(' ... ');
  // ... I repeat the same stuff for every column.
}

为了重用一些代码而不大量复制和粘贴,我定义了下一个函数

async function getContent(element){
  innerText = await element.getProperty('innerText');
  json = await innerText.jsonValue();
  return json;  
}

所以我可以通过这种方式重构之前的代码

for(i=0<rowMarket.length;i++){
  nameComponent = await rowMarket[i].$('td:nth-child(1) > a');
  nameText = getContent(nameComponent);

  otherComponent = await rowMarket[i].$(' ... ');
  otherText = getContent(otherComponent);

  // ...
}

但是深入研究文档时,我发现$eval function似乎与我手工完成的工作完美结合。

我以另一种方式重构代码。我认为它非常干净紧凑。

for(i=0<rowMarket.length;i++){
  nameText = await rowMarket[i].$eval('td:nth-child(1) > a', getContent);
  otherText = await rowMarket[i].$eval(' ...', getContent);
  // ...
}

但是我遇到下一个错误

(node:8056) UnhandledPromiseRejectionWarning: Error: Evaluation failed: TypeError: elemento.getProperty is not a function
    at dentroElemento (__puppeteer_evaluation_script__:2:30)
    at ExecutionContext.evaluateHandle (c:\webscraping\node_modules\puppeteer\lib\ExecutionContext.js:97:13)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

我真的不明白该错误,因为如果在“独立”模式下调用该函数,该函数可以正常运行。

我也尝试过

for(i=0<rowMarket.length;i++){
  nameText = await rowMarket[i].$eval('td:nth-child(1) > a', e => console.log('hello?'));
}

但是hello String永远不会登录到控制台。所以我认为问题是没有调用pageFunction函数。也许我的代码做错了。

1 个答案:

答案 0 :(得分:1)

此:await rowMarket[i].$('td:nth-child(1) > a');返回一个 elementHandle 。 elementHandle具有函数.getProperty()。 因此,这就是您的第一个代码起作用的原因:

async function getContent(elementHandle){
  innerText = await elementHandle.getProperty('innerText');
  ...

但是.$eval传递 Element 作为函数的第一个参数。这与 elementHandle 不同。

如果要执行此操作:nameText = await rowMarket[i].$eval('td:nth-child(1) > a', getContent); 然后,您应该重写您的 getContent 函数以在这样的Element上工作(因为 Element 没有.getProperty()函数):

async function getContent(element){
  innerText = await element.innerText;