UnhandledPromiseRejectionWarning: TypeError: Невозможно прочитать свойство 'map' из неопределенного - PullRequest
0 голосов
/ 28 марта 2020

Я здесь делаю скребок, используя node.js запрос и запрос-обещание, cheerio.

Мой код:

const request = require("request");
const cheerio = require("cheerio");
const rp = require("request-promise");

const url = "https://singapore.craigslist.org/d/automotive-services/search/aos"

const scrapeResults = [];

async function scrapeJobHeader() {

    try {

        const htmResult = await rp.get(url);
        const $ = await cheerio.load(htmResult);
        $(".result-info").each((index, element) => {

        const resultTitle = $(element).children(".result-title");
        title = resultTitle.text();
        link = resultTitle.attr("href");
        const datePosted = $(element).children("time").attr("datetime");


        const scrapResult = {title, link, datePosted};
        scrapeResults.push(scrapResult);
        return scrapeResults;

        });

    } catch (err) {

        console.error(err);
    }
}

async function scrapeDescription(jobWithHeaders) {

    return await Promise.all(
        jobWithHeaders.map(async job => {

        const htmResult = await rp.get(job.url);
        const $ = await cheerio.load(htmResult);
        $(".print-qrcode-container").remove();
        job.description = $("#postingbody").text();

    })
    );

}

async function scrapeCraigslist() {

    const jobWithHeaders = await scrapeJobHeader();
    const jobsFullData = await scrapeDescription();
    console.log(jobFullData);
}
scrapeCraigslist();

Когда я запускаю код, я получаю ошибку вроде:


C:\Users\Ahmed-PC\craigslist>node index.js
(node:19808) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'map' of undefined
    at scrapeDescription (C:\Users\Ahmed-PC\craigslist\index.js:42:24) 
    at scrapeCraigslist (C:\Users\Ahmed-PC\craigslist\index.js:62:32)  

Как я могу исправить эту ошибку и что неправильно я здесь делаю?

1 Ответ

0 голосов
/ 28 марта 2020

Вы делаете это await scrapeDescription();, но вы не можете вызвать эту функцию, не передав ей массив.

Когда вы это сделаете, тогда ваш аргумент jobWithheaders будет undefined, а затем вы попытаетесь сделать undefined.map(), который выдает ошибку, которую вы видите.

Похоже, вам просто нужно чтобы изменить это:

async function scrapeCraigslist() {

    const jobWithHeaders = await scrapeJobHeader();
    const jobsFullData = await scrapeDescription();
    console.log(jobFullData);
}

на это:

async function scrapeCraigslist() {

    const jobWithHeaders = await scrapeJobHeader();
    const jobsFullData = await scrapeDescription(jobWithHeaders);   // <===
    console.log(jobFullData);
}

Кроме того, нет причин делать:

return await Promise.all(...)

Изменить это на:

return Promise.all(...)

В любом случае вы возвращаете обещание с тем же значением. По сути, внутри функции async нет никаких причин делать return await somePromise. Просто верните обещание напрямую без await. Все, что делает await (если он не оптимизирован интерпретатором), - это ожидание разрешения обещания, получение значения из него, а затем получение обещания, уже возвращенного функцией async, и преобразование этого значения в разрешенное значение. этого обещания. Что дает тот же результат, что и возвращение обещания, которое у вас уже было, без await.


Измените это:

const scrapeResults = [];

async function scrapeJobHeader() {

    try {

        const htmResult = await rp.get(url);
        const $ = await cheerio.load(htmResult);
        $(".result-info").each((index, element) => {

        const resultTitle = $(element).children(".result-title");
        title = resultTitle.text();
        link = resultTitle.attr("href");
        const datePosted = $(element).children("time").attr("datetime");


        const scrapResult = {title, link, datePosted};
        scrapeResults.push(scrapResult);
        return scrapeResults;

        });

    } catch (err) {

        console.error(err);
    }
}

на следующее:

async function scrapeJobHeader() {
    const scrapeResults = [];
    const htmResult = await rp.get(url);
    const $ = await cheerio.load(htmResult);
    $(".result-info").each((index, element) => {
        const resultTitle = $(element).children(".result-title");
        const title = resultTitle.text();
        const link = resultTitle.attr("href");
        const datePosted = $(element).children("time").attr("datetime");

        const scrapResult = {title, link, datePosted};
        scrapeResults.push(scrapResult);
    });
    return scrapeResults;
}

И затем измените это:

scrapeCraigslist();

на это:

scrapeCraigslist().then(results => {
    // use the results in here only
    console.log(results);
}).catch(err => {
    console.log(err);
});

Затем измените это:

async function scrapeDescription(jobWithHeaders) {

    return await Promise.all(
        jobWithHeaders.map(async job => {

        const htmResult = await rp.get(job.url);
        const $ = await cheerio.load(htmResult);
        $(".print-qrcode-container").remove();
        job.description = $("#postingbody").text();

    })
    );

}

на это:

function scrapeDescription(jobWithHeaders) {

    return Promise.all(
        jobWithHeaders.map(async job => {
            const htmResult = await rp.get(job.url);
            const $ = await cheerio.load(htmResult);
            $(".print-qrcode-container").remove();
            job.description = $("#postingbody").text();
            return job;
        });
    );
}
...