Puppeteer querySelector не может прочитать свойство ‘textContent’ Null

#javascript #puppeteer #chromium

#javascript #puppeteer #chromium

Вопрос:

Пытаясь очистить некоторые данные об уязвимостях с помощью Nodejs и Puppeteer, столкнулся с проблемой, из-за которой некоторые свойства отображаются как null или empty, но запуск запроса SelectorQuery в браузере работает (версия 87.0.4280.88 (x86_64)). ниже приведен фрагмент, который вызывает проблемы.

Селекторы относятся к дате исправления уязвимости, где путь к селектору ‘div.patched’. Проблема, похоже, также возникает с разделом программного обеспечения со следующим селектором ‘spec-title for-l’.

 const puppeteer = require('puppeteer');
const url = 'https://www.zero-day.cz/database/';
const selector = '.issue.col-md-6';
(async function(){
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    const version = await page.browser().version();
    console.log(version);
    await page.goto(url);
    const articles = await page.$eval(selector, nodes => {
        return nodes.map(node => {
            let timePatched = node.querySelectorAll('div.patched').textContent;
            {};
            return {
                timePatched
            }
        })
    });
    console.log(articles);
    await browser.close();
})();
 

Вывод

 [
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
  {}, {}, {}, {},
  ... 374 more items
]
 
  • HeadlessChrome/88.0.4298.0
  • Npm версии 7.3
  • Версия Puppeteer 5.5

Ответ №1:

Не усложняйте ситуацию, сделайте ее как можно более простой. Например, чтобы получить доступ к датам исправлений, вы можете использовать .patched только селектор, он дает вам то же количество элементов, что и при использовании его в сочетании с .issue.col-md-6 .

Другое дело, что у вас есть 3 уровня отступов page.$$eval() , которые не очень удобочитаемы. Постарайтесь упростить ситуацию настолько, насколько это возможно.

Вот код, который дает мне массив дат исправлений (450 из них):

 const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://www.zero-day.cz/database/');    
    
    const patchedTexts = await page.evaluate(() => {
        const nodes = document.querySelectorAll('.patched');
        return [...nodes].map(e => e.textContent);
    });

    console.log(patchedTexts);
    await browser.close();
})();
 

На выходе получается:

 [
  '2021-01-12', '2020-12-15', '2020-12-14', '2020-12-07', '2020-11-11',
  '2020-11-11', '2020-11-06', '2020-11-06', '2020-11-06', '2020-11-03',
  '2020-11-03', '2020-11-10', '2020-10-20', '2020-10-20', '2020-09-01',
  ...
]
 

Комментарии:

1. Большое вам спасибо, это работает. но как я могу расширить его, чтобы также добавить заголовок, описание и дату обнаружения?

Ответ №2:

Предполагая, что все, что вы ищете, это время, когда дата была исправлена, вот что я создал на основе вашего кода

 const puppeteer = require("puppeteer");
const url = "https://www.zero-day.cz/database/";

(async function () {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  const version = await page.browser().version();
  console.log(version);
  await page.goto(url);
  const patchTimes = await page.$eval(
    ".issue.col-md-6 div.patched",
    (patches) => patches.map((patch) => patch.textContent)
  );
  console.log(patchTimes);
  await browser.close();
})(); 

Добавление нового фрагмента, который захватывает заголовок / описание / статус проблемы / исправлен

 const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto("https://www.zero-day.cz/database/");

  const patched_texts = await page.evaluate(() => {
    const nodes = document.querySelectorAll(".patched");
    return [...nodes].map((e) => e.textContent);
  });
  const issue_title = await page.evaluate(() => {
    const nodes = document.querySelectorAll(".issue-title");
    return [...nodes].map((e) => e.textContent);
  });
  const desc = await page.evaluate(() => {
    const nodes = document.querySelectorAll(".description");
    return [...nodes].map((e) => e.textContent);
  });
  const issue_status = await page.evaluate(() => {
    const nodes = document.querySelectorAll(".issue-status");
    return [...nodes].map((e) => e.textContent);
  });
  console.log(issue_title);
  console.log(desc);
  console.log(issue_status);
  console.log(patched_texts);

  console.log(patchedTexts);
  await browser.close();
})();
 

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

Комментарии:

1. Большое вам спасибо, это работает. но как я могу расширить его, чтобы также добавить заголовок, описание и дату обнаружения?

2. Я жду ответа от Павла, потому что мне очень нравится, как он пишет свой js-код, и я тоже хочу учиться у него. Если в течение двух дней ответа не будет, я подключусь и помогу, обещаю

3. Привет, Кайл, еще раз спасибо за вашу помощь. Я изо всех сил пытаюсь расширить его, чтобы включить в него все, и мне нужно как можно скорее закончить работу, поэтому приношу извинения за спешку. Если у вас есть какие-либо идеи, пожалуйста, дайте мне знать. Еще раз спасибо вам.

4. Привет, Мэтт, завтра я работаю, сначала я расставлю приоритеты в этом скрипте 🙂

5. Внесены некоторые дополнения