从网页获取所有图像并将其保存到磁盘中(NodeJS和Javascript)

时间:2019-01-30 14:31:00

标签: javascript node.js web-scraping

我需要从一些网站上获取大量图像并将它们下载到磁盘上,以便可以使用它们(将它们上传到Blob(azure),然后将链接保存到我的数据库中)。

获取图像

我知道如何使用JS从html获取图像,例如,其中一个我将进行for循环并执行:

document.getElementsByClassName('person')[i].querySelector('div').querySelector('img').getAttribute('src')

在那里,我将拥有所有图像的链接。

保存图像

我还看到我可以通过执行以下操作使用node和fs模块将文件保存到磁盘:

function saveImageToDisk(url, localPath) {var fullUrl = url;
var file = fs.createWriteStream(localPath);
var request = https.get(url, function(response) {
response.pipe(file);
});

}

如何将所有内容放在一起

这是我遇到的问题,我不知道如何确切地连接两个部分(脚本和nodejs代码),我想获取图像以及图像名称(在这种情况下为alt标记),然后在节点中使用它们将图像上传到Blob,并将它们的名称和图像Blob URL放入我的数据库中。

我以为我可以下载html页面,然后将JS脚本放在主体底部,但是后来我不知道如何将URL传递给nodejs代码。

我该怎么做?

我不太习惯使用脚本,我经常使用没有它们的节点,我对它们的交互以及如何将js脚本连接到我的代码感到困惑。

这也是解决此问题的最佳方法吗?还是我没有看到更简单/更好的方法?

谢谢

4 个答案:

答案 0 :(得分:1)

我建议您使用dom-parser模块。看到这里:https://www.npmjs.com/package/dom-parser

这样做,您可以使用http.get()下载整个html文件,并使用dom-parser对其进行解析。然后从HTML文件中提取您需要的所有信息。使用图片网址,使用您的saveImageToDisk()函数。

按照您的想法,您必须如上所述将JS脚本添加到html文件中。但除此之外,您还必须使用Ajax(xmlHttpRequest)将URL发布到nodeJS服务器。

答案 1 :(得分:1)

感觉您应该使用搜寻器。以下代码应该可以工作(使用npm模块crawler):

const Crawler = require("crawler")

const c = new Crawler({
    callback: function(error, res, done) {
        if (error) {
            console.log({error})
        } else {
            const images = res.$('.person div img')
            images.each(index => {
                // here you can save the file or save them in an array to download them later
                console.log({
                    src: images[index].attribs.src,
                    alt: images[index].attribs.alt,
                })
            })
        }
    }
})

c.queue('https://www.yoursite.com')

答案 2 :(得分:1)

您需要在Web API(用于DOM解析等)和Node.js API之间建立桥梁。例如,Node.js的一些无头浏览器管理工具。说,您可以在此脚本中使用puppeteer

'use strict';

const puppeteer = require('puppeteer');
const https = require('https');
const fs = require('fs');

(async function main() {
  try {
    const browser = await puppeteer.launch();
    const [page] = await browser.pages();

    await page.goto('https://en.wikipedia.org/wiki/Image');

    const imgURLs = await page.evaluate(() =>
      Array.from(
        document.querySelectorAll('#mw-content-text img.thumbimage'),
        ({ src }) => src,
      )
    );
    console.log(imgURLs);
    await browser.close();

    imgURLs.forEach((imgURL, i) => {
      https.get(imgURL, (response) => {
        response.pipe(fs.createWriteStream(`${i++}.${imgURL.slice(-3)}`));
      });
    });
  } catch (err) {
    console.error(err);
  }
})();

您甚至可以使用浏览器已经下载的图片下载一次图像。该脚本可保存相同的图像,但具有一个请求会话,而无需使用https Node.js模块(这样可以节省时间,网络流量和服务器工作量):

'use strict';

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

(async function main() {
  try {
    const browser = await puppeteer.launch();
    const [page] = await browser.pages();

    const allImgResponses = {};
    page.on('response', (response) => {
      if (response.request().resourceType() === 'image') {
        allImgResponses[response.url()] = response;
      }
    });

    await page.goto('https://en.wikipedia.org/wiki/Image');

    const selecedImgURLs = await page.evaluate(() =>
      Array.from(
        document.querySelectorAll('#mw-content-text img.thumbimage'),
        ({ src }) => src,
      )
    );
    console.log(selecedImgURLs);

    let i = 0;
    for (const imgURL of selecedImgURLs) {
      fs.writeFileSync(
        `${i++}.${imgURL.slice(-3)}`,
        await allImgResponses[imgURL].buffer(),
      );
    }

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

答案 3 :(得分:0)

您可以使用Promise并在其中执行获取所有图像并将图像url放入数组的工作。然后在then方法内可以迭代数组并调用saveImageToDisk每次,也可以通过修改幻灯片将数组发送到中间层。第二种方法更好,因为它只会打一个网络电话

function getImages() {
  return new Promise((resolve, reject) => {
     // Array.from will create an array
     // map will return a new array with all the image url
    let k = Array.from(document.getElementsByClassName('person')[0].querySelector('div')
        .querySelectorAll('img'))
      .map((item) => {
        return item.getAttribute('src')
      })
    resolve(k)
  })
}
getImages().then((d) => {
 // it will work only after the promise is resolved
  console.log('****', d);
  (item => {
    // call saveImageToDisk function

  })

})

function saveImageToDisk(url, localPath) {
  var fullUrl = url;
  var file = fs.createWriteStream(localPath);
  var request = https.get(url, function(response) {
    response.pipe(file);
  });
<div class='person'>
  <div>
    <img src='https://www.fast-growing-trees.com/images/P/Leyland-Cypress-450-MAIN.jpg'>
    <img src='http://cdn.shopify.com/s/files/1/2473/3486/products/Cypress_Leyland_2_Horticopia_d1b5b63a-8bf7-4897-96fb-05320bf3d81b_grande.jpg?v=1532991076'>
    <img src='https://www.fast-growing-trees.com/images/P/Live-Oak-Tree-450w.jpg'>
    <img src='https://www.greatgardenplants.com/images/uploads/452_1262_popup.jpg'>
    <img src='https://shop.arborday.org/data/default/images/catalog/600/Turnkey/1/Leyland-Cypress_3-828.jpg'>


    <img src='https://images-na.ssl-images-amazon.com/images/I/51RZkKnrlSL._SX425_.jpg'>

    <img src='https://thumbs-prod.si-cdn.com/Z3JYiuJ96ReLq04NCT1B94sTd4E=/800x600/filters:no_upscale()/https://public-media.si-cdn.com/filer/06/9c/069cfb16-c46c-4742-85f0-3c7e45fa139d/mar2018_a05_talkingtrees.jpg'>


  </div>