Неверный результат кукловода с использованием методаrate () и exposeFunction () - PullRequest
0 голосов
/ 27 июня 2019

Я запустил следующее, и, похоже, он собирает большое количество ссылок, однако при фактической проверке сайта с помощью collectLinks1 я получаю все действительные ссылки, но с collectLinks2 я получил 59 итераций http://pieroxy.net/blog/2014/11/18/[

Я новичок в Puppeteer и не могу понять, почему с collectLinks2 я не получаю ссылки.

const { parse, resolve } = require('url');
const trim = require('lodash/trim');
const startsWith = require('lodash/startsWith');
const includes = require('lodash/includes');


// https://github.com/GoogleChrome/puppeteer
const puppeteer = require('puppeteer');
// https://github.com/gwuhaolin/chrome-finder
const findChrome = require('chrome-finder'); 


function resolveUrl(url, baseUrl) {
  url = trim(url);
  if (!url) return null;
  if (startsWith(url, '#')) return null;
  const { protocol } = parse(url);
  if (includes(['http:', 'https:'], protocol)) {
    return url.split('#')[0];
  } if (!protocol) {
    return resolve(baseUrl, url).split('#')[0];
  }
  return null;
}

async function collectLinks1(htmlPage) {
  const baseUrl = htmlPage.url();
  const links = [];
  const assetUrls = await htmlPage.$$eval('a[href]', assetLinks => assetLinks.map(link => link.href));

  assetUrls.forEach(link => {
    const _link = resolveUrl(link, baseUrl);
    if (_link) links.push(_link);
  });

  return links;
}

async function collectLinks2(htmlPage) {
  const baseUrl = htmlPage.url();
  const links = [];

  await htmlPage.exposeFunction('pushToLinks', link => {
    const _link = resolveUrl(link, baseUrl);
    if (_link) links.push(_link);
  });

  await htmlPage.evaluate(() => {
    function findLinks(document) {
      document.querySelectorAll('a[href]')
        .forEach(link => {
          window.pushToLinks(link.href);
        });
    }
    findLinks(window.document);
  });

  return links;
}

const crawl = async url => {
  try {
    console.log(`Crawling ${url}`);

    const browser = await puppeteer.launch({
      headless: false,
      executablePath: findChrome(),
    });
    const page = await browser.newPage();

    await page.goto(url);

    // OK
    const links1 = await collectLinks1(page);
    links1.forEach(link => { console.log(link); });

    // KO
    const links2 = await collectLinks2(page);
    links2.forEach(link => { console.log(link); });

    await browser.close();
  } catch (err) {
    console.log(err);
  }
};

crawl('http://pieroxy.net/blog/2014/11/18/user_agent_detection_in_java.html');

1 Ответ

0 голосов
/ 27 июня 2019

Вам необходимо await функцию, определенную через page.exposeFunction, так как она возвращает Обещание. Поскольку вы только вызываете функцию, но не ожидаете ее результата, ваш вызов page.evaluate разрешится до того, как ваш скрипт завершит выполнение.

Решение

Вместо forEach вы должны использовать цикл для перебора всех элементов и передачи их на страницу один за другим.

async function collectLinks2(htmlPage) {
  // ...

  await htmlPage.evaluate(async () => {
    async function findLinks(document) {
      for (const link of document.querySelectorAll('a[href]')) {
        await window.pushToLinks(link.href);
      }
    }
    await findLinks(window.document);
  });
  return links;
}
...