質問

I am trying to scrape some data from a shopping site Express.com. Here's 1 of many products that contains image, price, title, color(s).

  <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>

The very naive and possibly error-prone approach I've done is to first to grab all prices, images, titles and colors:

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');

Next, I populate arrays with the data from DOM extracted using jsdom or cheerio scraping libraries for node.js. (Cheerio in this case).

  // 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);
  }

Lastly, based on the assumption that price, title, image and colors will match up create a product object:

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

This method is slow, error-prone, and very anti-DRY. I was thinking it would be nice if we could grab $('.cat-thu-product') and using a single for-loop extract relevant information from a single product a time.

But have you ever tried traversing the DOM in jsdom or cheerio? I am not sure how anyone can even comprehend it. Could someone show how would I use this proposed method of scraping, by grabbing $('.cat-thu-product') div element containing all relevant information and then extract necessary data?

Or perhaps there is a better way to do this?

役に立ちましたか?

解決

I would suggest still using jQuery (because it's easy, fast and secure) with one .each example:

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);

And to validate that you have all the required fields, you can write easilly validator or test. But if you are using different library, you still should loop through "div.cat-thu-product" elements.

他のヒント

Try node.io https://github.com/chriso/node.io/wiki

This will be a good approach of doing what you are trying to do.

using 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);
 })
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top