Как загрузить HTML, CSS и IMG с помощью Puppeteer и JSDOM

Я пытаюсь использовать Puppeteer для загрузки любой заданной веб-страницы. Я хотел бы загрузить файл HTML, исходники CSS и все изображения в локальную папку (чтобы иметь возможность читать страницы позже, без подключения к Интернету).

Проблемы следующие:

  • 1- Я не нашел, как разобрать HTML-файл для обнаружения источников CSS и изображений и как его загрузить.
  • 2- Я не понял, как изменить путь к этим ресурсам и убедиться, что он будет указывать на мою локальную папку.

Пока я не уверен, как лучше всего разбирать константное содержимое "html" (см. Ниже). Я не понял, как редактировать html с помощью JSDOM.

    const puppeteer = require('puppeteer');
    const jsdom = require('jsdom');

    const { JSDOM } = jsdom;


    (async () => {
      const url = 'https://stackoverflow.com/questions/54507560/how-to-download-html-css-and-imgs-using-puppeteer';
      const browser = await puppeteer.launch();
      const page = await browser.newPage();
      await page.goto(url, {waitUntil: 'load'});
      const html = await page.content();

      const dom = new JSDOM(html);

      // I'm trying to grab all the img and so to be able to edit the path
      console.log(dom.window.document.querySelectorAll("img"));


      // ^ this is not working it return the following object in my node shell : 
      // NodeList { '0': HTMLImageElement {}, '1': HTMLImageElement {} } 
      // I don't know how to process this object and to grab each image path and then to dl it. I don't know how to edit each path to make it relative to my local folder.

      browser.close();
    })();

Обновление: сейчас я пытаюсь разобрать HTML с помощью JSDOM.


person dvd    schedule 03.02.2019    source источник
comment
Как кажется невозможным анализировать HTML-контент? По какой причине вы не можете просто использовать такой модуль, как cheerio, вызвать var $ = cheerio.load(html) и использовать оттуда синтаксический анализ, подобный jquery? Расскажите немного подробнее о том, как вы не смогли разобрать html, включая вашу попытку сделать это.   -  person MadWard    schedule 04.02.2019
comment
@MadWard полезный комментарий, но разве JSDOM не лучший способ сделать это? Я только что сделал новую попытку, но понятия не имею, как обрабатывать dom и управлять им с помощью этого api.   -  person dvd    schedule 04.02.2019
comment
Хорошо, опубликовал ответ, в котором подробно описывается, как 1) заменить каждый URL ‹img src› в документе и 2) заменить URL-адрес каждого ресурса, который является изображением. Оба являются рабочими, протестированными сниппетами, вы можете использовать любой из них, если они подходят для вашей цели.   -  person MadWard    schedule 04.02.2019


Ответы (2)


Изменение всех тегов <img src> на активной странице

Чтобы изменить все теги img в документе, вам нужно будет запустить _ 2_ и используйте document.querySelectorAll() там, в браузере. Вот быстрый рабочий фрагмент, который удаляет домен из каждого источника изображения в документе:

(async () => {
  const browser = await puppeteer.launch();

  const url = 'https://stackoverflow.com/questions/54507560/how-to-download-html-css-and-imgs-using-puppeteer';
  const page = await browser.newPage();

  await page.goto(url, {waitUntil: 'load'});

  await page.evaluate(() => {
    var imgs = document.querySelectorAll('img');
    imgs.forEach(function(img){
      let imageSrc = img.getAttribute("src");
      img.setAttribute("src", imageSrc.replace(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img, ""));
      console.log(img.getAttribute("src"));
    });
  });  
})();

Изменение URL-адреса для каждого ресурса, который является изображением

Это немного сложнее. Короче говоря, вам нужно перехватывать каждый запрос, сделанный браузером, и continue() с измененным URL.

Опять же, рабочий фрагмент, который заменяет каждый URL ресурса изображения выбранным нами доменом:

var newDomain = "https://example.com";

(async () => {
  const browser = await puppeteer.launch({headless: false});

  const url = 'https://stackoverflow.com/questions/54507560/how-to-download-html-css-and-imgs-using-puppeteer';
  const page = await browser.newPage();
  await page.setRequestInterception(true);

  page.on('request', (interceptedRequest) => {
    // Continue if request URL is page URL
    if (interceptedRequest.url() == page.url()) {
      interceptedRequest.continue();
      return;
    }

    // Intercept if request resource is an Image
    if (interceptedRequest.resourceType() == "image") {
      // Replace target domain with the new domain we want
      let newUrl = interceptedRequest.url().replace(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img, newDomain);
      console.log(newUrl);
      interceptedRequest.continue({
        url: newUrl,
      });
      return;
    }

    // Continue any other requests
    interceptedRequest.continue();
  })

  await page.goto(url, {waitUntil: 'load'});

})();
person MadWard    schedule 04.02.2019
comment
Спасибо за это, MadWard. Я нашел встроенное решение, которое делает именно то, что я хотел - person dvd; 14.02.2019

Оп здесь. Вот встроенное решение, которое я нашел: https://github.com/website-scraper/website-scraper-puppeteer Итак, вот код в том виде, в каком он написан в репозитории. Кажется, это действительно хорошо работает!

const scrape = require('website-scraper');
const PuppeteerPlugin = require('website-scraper-puppeteer');

scrape({
    urls: ['https://www.instagram.com/gopro/'],
    directory: '/path/to/save',
    plugins: [ new PuppeteerPlugin() ]
});
person dvd    schedule 14.02.2019