首页 > 解决方案 > 将在 jsdom 承诺中生成的字符串分配给变量

问题描述

我正在使用 jsdom 来解析谷歌购物的结果。以下代码获取一个 google 购物链接,对其进行解析,并提取包含所有结果的表:

const jsdom = require('jsdom').JSDOM;

function parseSite() {
const url = "https://www.google.com/shopping/product/8352592323560827089/online";
let trimmedTable = "";

jsdom.fromURL(url).then(function (dom) {
    let innerHtml = dom.window.document.querySelector('html').innerHTML;
    let tableStartIndex = innerHtml.search("<tbody><tr ");
    let nonTrimmedTable = innerHtml.substr(tableStartIndex + 7, innerHtml.length);
    let tableEndIndex = nonTrimmedTable.search("</tbody></table>");
    trimmedTable = nonTrimmedTable.substr(0, tableEndIndex);
});
}

parseSite();

我意识到 Promise 是异步的,似乎我正在尝试以同步方式使用它,但 jsdom 是我能找到的唯一可以加载整个网页的东西,就好像它是一个网络浏览器一样。我不想使用硒,因为性能会受到影响。代码本身完全按照我的意愿工作,我只需要得到trimmedTable承诺之外的结果。

我的问题:有没有比 jsdom 更好的东西来从网页加载和提取数据,就好像它们被加载到浏览器中一样?(可以完成我在提供的代码中尝试做的事情)如果没有,我该如何编写我的代码,以便我可以获得trimmedTable分配给承诺之外的变量的结果?

标签: javascriptnode.jsweb-scrapingpromisejsdom

解决方案


我能够通过使用结合 Promise.all() 的异步函数来解决我的问题。

使用 Promise.all() 的好处是我可以创建多个异步函数,然后将这些函数中的 Promise 返回的所有值放入一个函数中。然后,我可以将这些值分配给一个变量并根据需要处理它们。这是我现在的代码:

let retailers = async function parseRetailers() {
    const webPage = await jsdom.fromURL("https://www.google.com/shopping/product/8352592323560827089");

    let innerHtml = webPage.window.document.querySelector('html').innerHTML;
    let tableStartIndex = innerHtml.search("<tbody><tr "); //len=7
    let nonTrimmedTable = innerHtml.substr(tableStartIndex + 7, innerHtml.length);
    let tableEndIndex = nonTrimmedTable.search("</tbody></table>");

    return nonTrimmedTable.substr(0, tableEndIndex);
}

let allRetailers = [];

Promise.all([retailers()])
    .then(values => {
        allRetailers = values;
});

推荐阅读