Estoy tratando de usar Titiritero para raspar este elemento de eBay:
Sin embargo, cuando ejecuto mi código, aparece un error que dice "No se pueden leer las propiedades de nulo (leyendo 'textContent')". Este es mi código:
async function scrape() { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.goto('https://www.ebay.com/sch/i.html?_from=R40&_nkw=Blastoise+%282%2F102%29+%5BCelebrations%3A+Classic+Collection%5D&_sacat=0&Graded=No&_dcat=183454&rt=nc&LH_Sold=1&LH_Complete=1'); await page.waitForSelector('.s-item'); let cards = await page.evaluate(() => { let cardElement = document.body.querySelectorAll('.s-item') let cards = Object.values(cardElement).map(x => { return { date: x.querySelector('.s-item__title--tagblock span.POSITIVE').textContent ? ? null } }) return cards }) console.log(cards) })()¿Como puedo resolver esto?
El primer elemento en la lista de resultados es una especie de nodo ficticio/plantilla/marcador de posición que no contiene datos. Puede usar .slice(1) o .s-item:not(:first-child) para omitir ese primer nodo.
Mientras lo hace, también puede hacer que su waitForSelector más preciso para que coincida con el elemento que está a punto de seleccionar (aunque esta línea no es necesaria, como explicaré a continuación), use domcontentloaded para acelerar goto y use ?.textContent para que pueda ver undefined en lugar de un bloqueo, que es como depuré el problema. .textContent ?? null no funciona porque el lanzamiento ocurre antes ?? null tiene la oportunidad de evaluar.
const puppeteer = require("puppeteer"); // ^14.1.1 let browser; (async () => { browser = await puppeteer.launch({headless: true}); const [page] = await browser.pages(); const url = "https://www.ebay.com/sch/i.html?_from=R40&_nkw=Blastoise+%282%2F102%29+%5BCelebrations%3A+Classic+Collection%5D&_sacat=0&Graded=No&_dcat=183454&rt=nc&LH_Sold=1&LH_Complete=1"; await page.goto(url, {waitUntil: "domcontentloaded"}); await page.waitForSelector(".s-item .s-item__title--tagblock span.POSITIVE"); const cards = await page.evaluate(() => [...document.querySelectorAll(".s-item:not(:first-child)")].map(x => ({ date: x .querySelector(".s-item__title--tagblock span.POSITIVE") ?.textContent })) ); console.log(cards); })() .catch(err => console.error(err)) .finally(() => browser?.close()) ;Mejor aún, omita Puppeteer por completo y realice una solicitud HTTP con Axios o fetch, luego use Cheerio para analizar el HTML estático, que ya tiene los datos que necesita:
const axios = require("axios"); const cheerio = require("cheerio"); const url = "https://www.ebay.com/sch/i.html?_from=R40&_nkw=Blastoise+%282%2F102%29+%5BCelebrations%3A+Classic+Collection%5D&_sacat=0&Graded=No&_dcat=183454&rt=nc&LH_Sold=1&LH_Complete=1"; axios.get(url).then(({data}) => { const $ = cheerio.load(data); const cards = []; $(".s-item:not(:first-child)").each(function (i, e) { $(this).find(".s-item__title--tagblock .POSITIVE").each(function (i, e) { cards.push($(this).text().trim()); }); }); console.log(cards); }) .catch(err => console.error(err)) ;