如何在Node.js中有效地进行网页抓取?

时间:2013-01-31 07:24:42

标签: node.js web-scraping jsdom cheerio

我正试图从购物网站Express.com上搜集一些数据。以下是许多产品中的一种,其中包含图片价格标题颜色

  <div class="cat-thu-product cat-thu-product-all item-1">
<div class="cat-thu-p-cont reg-thumb" id="p-50715" style="position: relative;"><a href="/rocco-slim-fit-skinny-leg-corduroy-jean-50715-647/control/show/3/index.pro" onclick="var x=&quot;.tl(&quot;;s_objectID=&quot;http://www.express.com/rocco-slim-fit-skinny-leg-corduroy-jean-50715-647/control/show/3/index.pro_1&quot;;return this.s_oc?this.s_oc(e):true"><img class="cat-thu-p-ima widget-app-quickview" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_900/i81?$dcat191$" alt="ROCCO SLIM FIT SKINNY LEG CORDUROY JEAN"></a><a href="#jsLink"><img id="widget-quickview-but" class="widget-ie6png glo-but-css-off2" src="/assets/images/but/cat/but-cat-quickview.png" alt="Express View" style="position: absolute; left: 50px;"></a></div>
  <ul>
    <li class="cat-cat-more-colors">
      <div class="productId-50715">
        <img class="js-swatchLinkQuickview" title="INK BLUE" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_900_s/i81?$swatch$" width="16" height="6" alt="INK BLUE">
        <img class="js-swatchLinkQuickview" title="GRAPHITE" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_924_s/i81?$swatch$" width="16" height="6" alt="GRAPHITE">
        <img class="js-swatchLinkQuickview" title="MERCURY GRAY" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_930_s/i81?$swatch$" width="16" height="6" alt="MERCURY GRAY">
        <img class="js-swatchLinkQuickview" title="HARVARD RED" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_853_s/i81?$swatch$" width="16" height="6" alt="HARVARD RED">
      </div>
    </li>
    <li class="cat-thu-name"><a href="/rocco-slim-fit-skinny-leg-corduroy-jean-50715-647/control/show/3/index.pro" onclick="var x=&quot;.tl(&quot;;s_objectID=&quot;http://www.express.com/rocco-slim-fit-skinny-leg-corduroy-jean-50715-647/control/show/3/index.pro_2&quot;;return this.s_oc?this.s_oc(e):true">ROCCO SLIM FIT SKINNY LEG CORDUROY JEAN
    </a></li>
    <li>
      <strong>$88.00</strong>
    </li>
  <li class="cat-thu-promo-text"><font color="BLACK" style="font-weight:normal">Buy 1, Get 1 50% Off</font>
  </li>
</ul>

我所做的非常天真且可能容易出错的方法是首先获取所有价格,图片,标题和颜色:

var price_objects = $('.cat-thu-product li strong');
var image_objects = $('.cat-thu-p-ima');
var name_objects = $('.cat-thu-name a');
var color_objects = $('.cat-cat-more-colors div');

接下来,我使用 jsdom cheerio 为node.js抓取来自DOM的数据填充数组。 (在这种情况下,Cheerio)。

  // price info
  for (var i = 0; i < price_objects.length; i++) {
    prices.push(price_objects[i].children[0].data);
  }
  // image links
  for (var i = 0; i < image_objects.length; i++) {
    images.push(image_objects[i].attribs.src.slice(0, -10));
  }
  // name info
  for (var i = 0; i < name_objects.length; i++) {
    names.push(name_objects[i].children[0].data);
  }
  // color info
  for (var i = 0; i < color_objects.length; i++) {
    colors.push(color_objects[i].attribs.src);
  }

最后,根据价格,标题,图片和颜色匹配的假设创建产品对象:

for (var i = 0; i < images.length; i++) {
  items.push({
    id: i,
    name: names[i],
    price: prices[i],
    image: images[i],
    colors: colors[i]
  });
}

这种方法很慢,容易出错,而且非常反干。我认为如果我们能够抓住$('.cat-thu-product')并使用单个for循环从单个产品中提取相关信息,那将会很好。

但你有没有试过在 jsdom cheerio 中遍历DOM?我不确定任何人都能理解它。有人可以通过抓取包含所有相关信息的$('.cat-thu-product') div元素然后提取必要的数据来展示我将如何使用这种提议的抓取方法?

或许有更好的方法可以做到这一点?

3 个答案:

答案 0 :(得分:2)

我建议仍然使用jQuery(因为它简单,快速和安全),只需一个.each示例:

var items = [];
$('div.cat-thu-product').each(function(index, productElement) {
  var product = {
    id: $('div.cat-thu-p-cont', productElement).attr('id'),
    name: $('li.cat-thu-name a', productElement).text().trim(),
    price: $('ul li strong', productElement).text(),
    image: $('.cat-thu-p-ima', productElement).attr('src'),
    colors: []
  };
  // Adding colors array
  $('.cat-cat-more-colors div img', productElement).each(function(index, colorElement) {
    product.colors.push({name: $(colorElement).attr('alt'), imageUrl: $(colorElement).attr('src')});
  });

  items.push(product);
});

console.log(items);

要验证您是否拥有所有必填字段,您可以编写easilly验证器或测试。但是如果你使用不同的库,你仍然应该遍历“div.cat-thu-product”元素。

答案 1 :(得分:2)

尝试node.io https://github.com/chriso/node.io/wiki

这是做你想做的事情的好方法。

答案 2 :(得分:0)

使用https://github.com/rc0x03/node-promise-parser

products = []; 
pp('website.com/products')
 .find('div.cat-thu-product')
 .set({
     'id':       'div.cat-thu-p-cont @id',
     'name':     'li.cat-thu-name a',
     'price':    'ul li strong',
     'image':    '.cat-thu-p-ima',
     'colors[]': '.cat-cat-more-colors div img @alt',
 })
 .get(function(product) {
    console.log(product);
    products.push(product);
 })