Не удается найти узел в документе с помощью querySelector - PullRequest
1 голос
/ 06 мая 2020

The Elusive NodeList


Я застрял на этом 3 недели . Я испробовал буквально сотни попыток заставить это работать. Я просто не могу понять, что происходит не так. У меня закончились возможные решения, чтобы попробовать.

При этом ...

Краткое описание приложения

Я недавно согласился на подработку по разработке приложения, которое будет уведомлять клиента всякий раз, когда новый Jeep Wrangler публикуется на Facebook Marketplace. Это звучало довольно просто, и я согласился на эту работу. Я оценил завершение максимум за три дня. Это было в прошлом месяце. Ниже приведена блок-схема работы приложения:

Facebook Marketplace Scraper Flowchart

Технология

После некоторого исследования, я решил go с NodeJs и Puppeteer для разработки приложения.

Шаг 1: Скрип

Мне пришлось ознакомиться со страницей, содержащей необходимую информацию. Это страница результатов поиска:

https://www.facebook.com/marketplace/tampa/search/?query=jeep%20wrangler&sortBy=creation_time_descend&exact=false

Как вы увидите, результаты перечислены в формате сетки. Поэтому мне нужно взять контейнер со списком элементов ...

Facebook Search Results Container

<!-- This is the DIV that is the container nodelist -->
<div class="bq4bzpyk j83agx80 btwxx1t3 lhclo0ds jifvfom9 muag1w35 dlv3wnog enqfppq2 rl04r1d5">

Я нашел это, проверив консоль:

Inspecting

Я использовал тот же метод, чтобы найти элементы, содержащие заголовок , цена и изображение . Эта информация является дочерним узлом содержащего выше элемента.

Sample Listing

Шаг 2: Код

После большого количества проб и ошибок я смог получить минимальную рабочую версию, которая будет парсить в поисках «iPhone X» в качестве поискового запроса. Отлично работает! Но когда я попытался адаптировать этот код, просто изменив ключевое слово поиска на «Jeep Wrangler», это не удалось. Вот суть рабочего кода:

https://gist.github.com/johnsdeveloper/1a7d02554dbfd682ee274b2ef0696f00

Мой код

Взяв этот рабочий код, я придумал мой исходный код ниже. Это не работает. Я получаю эту ошибку каждый раз:

(узел: 4928) UnhandledPromiseRejectionWarning: TypeError: Невозможно прочитать свойство length для undefined в removeDupes (C: \ wamp64 \ www\puppeteer \ index. js: 56: 32) в initScraper (C: \ wamp64 \ www\puppeteer \ index. js: 86: 27) (узел: 4928) UnhandledPromiseRejectionWarning: необработанное отклонение обещания.

Похоже, новые результаты листинга возвращаются пустыми, что означает, что «очистка» не сработала.

Вот мой полный код:

const puppeteer = require('puppeteer');
const jsonfile = require("jsonfile");
var fileName = "./public/data/newjeeps.json";
var changed = false;
var browser;

const getItems = async searchTerm => {
    //{headless: false, defaultViewport: null} --> put this in launch() method below as parameter for developtment purposes --> opens up browser window
    //const browser = await puppeteer.launch({headless: false, defaultViewport: null});

     browser = await puppeteer.launch({
      headless: true,
      args: ["--no-sandbox"]

    });

    const page = await browser.newPage();

    await page.goto(`https://www.facebook.com/marketplace/tampa/search/?query=jeep%20wrangler&sortBy=creation_time_descend&exact=false`);
    await autoScroll(page);

    const itemList = await page.waitForSelector('#mount_0_0 > div > div > div.rq0escxv.l9j0dhe7.du4w35lb > div > div > div.j83agx80.cbu4d94t.d6urw2fd.dp1hu0rb.l9j0dhe7.du4w35lb > div > div.rq0escxv.l9j0dhe7.du4w35lb.j83agx80.cbu4d94t.d2edcug0.rj1gh0hx.buofh1pr.g5gj957u.hpfvmrgz.dp1hu0rb > div')
    .then(() => page.evaluate(() => {
        const itemArray = [];
        const itemNodeList = document.querySelectorAll('#mount_0_0 > div > div > div.rq0escxv.l9j0dhe7.du4w35lb > div > div > div.j83agx80.cbu4d94t.d6urw2fd.dp1hu0rb.l9j0dhe7.du4w35lb > div > div.rq0escxv.l9j0dhe7.du4w35lb.j83agx80.cbu4d94t.d2edcug0.rj1gh0hx.buofh1pr.g5gj957u.hpfvmrgz.dp1hu0rb > div > div > div > div > div > div > span > div > a');

        itemNodeList.forEach(item => {
            console.log(item);
        });
        return itemArray;
    }))
    .catch(() => console.log("Selector error."));

    return itemList;

}

/**
 * Remove any duplicates from JSON files
 *
 * @param {*} existingResults
 * @param {*} newResults
 * @returns array Returns new array of unique listings
 */
const removeDupes = async function (existingResults, newResults) {

  var existingTitle;
  var newTitle;
var newResults;

  /* Loop through EXISTING (marketplacebot.json) */
  for (var i = 0; i < existingResults.length; i++) {
    /* Existing Title & Price TODO*/
    existingTitle = existingResults[i].itemTitle;
    /* Loop through NEW data */
    for (y = 0; y < newResults.length; y++) {
      /* New Title */
      newTitle = newResults[y].itemTitle;
      /* Do we have a match? */
      if (existingTitle == newTitle) {

console.log("match");
        // Remove from new results
        newResults.splice(y, 1);

        // Change detected?
        changed = true;

      }
    }
  }

  return newResults;
}

const initScraper = async() => {

    // Get currently listed items on Marketplace
    const items = await getItems('Jeep Wrangler');
    //items.sort(function(a, b){return a.itemPrice - b.itemPrice});

    // Get existing JSON from file
    const existing = await jsonfile.readFile(fileName);

    // Compare the two, save only the differences
    const results = await removeDupes(existing,items);
    //console.log(results);

   // Now save the differences back to the JSON files, the
   // web page will pick up and display.
   var success = await jsonfile.writeFile(fileName, results);

    // If there were any differences, notify me
    if(changed == true){
      const page2 = await browser.newPage();
      await page2.goto('http://sendmail.com/mail.php');
    }

}

initScraper();





 // This takes care of the auto scrolling problem
 async function autoScroll(page) {
  await page.evaluate(async () => {
    await new Promise(resolve => {
      var totalHeight = 0;
      var distance = 100;
      var timer = setInterval(() => {
        var scrollHeight = document.body.scrollHeight;
        window.scrollBy(0, distance);
        totalHeight += distance;

        if (totalHeight >= scrollHeight || scrollHeight>7000) {
          clearInterval(timer);
          resolve();
        }
      }, 100);
    });
  });
}





1 Ответ

0 голосов
/ 10 мая 2020

Эти классы - динамические c. Вы хотите go по другим атрибутам или тексту на странице.

Например, получить эти элементы a с помощью: a[href*="/item/"]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...