• 利用nodejs+phantomjs+casperjs采集淘宝商品的价格


    因为一些业务需求需要采集淘宝店铺商品的销售价格,但是淘宝详情页面的价格显示是通过js动态调用显示的.所以就没法通过普通的获取页面html然后通过正则或者xpath的方式获取到想到的信息了.

    所幸我们现在有了casperjs.这个是一个基于Phantomjs的库,而Phantomjs则是一个服务器端的js api的webkit浏览器.是不是很神奇?真的是.net的以外的世界很神奇,我们要多走去看看.

    好了,现在废话不多说,开始切入正题.

    首先就是就是几个相关库的安装.安装过程很简单,相关内容大家百度即可.在文章的底部我也会列出参考链接.

    我们先进行下简要的分析:

    具体的操作流程就是利用casperjs模拟鼠标点击商品的图片,然后网页显示对应的价格.

    默认情况是这样的,如果不点击颜色分类下的图片,则对应的促销价格也只是会显示一个区间.

    而只要我们点击了颜色分类对应的图片之后,则会是下面的效果

    那么我们具体的操作步骤应该是:

    1)打开具体的商品详情页

    2)获取到颜色分类下图片个数,然后依次模拟鼠标点击

    3)每点击一次图片,然后获取对应的促销价格

    4)保存每次操作后的结果到数据库或者本地文件中待下一步处理

    下面我们就来具体的一步步实现上面分析后所需要的步骤:

    1.初始化casperjs

    var casper = require('casper').create({
      clientScripts: ["jquery.js"],
      verbose: false,
      logLevel: 'debug',
      pageSettings: {
        loadImages: false, // The WebPage instance used by Casper will
        loadPlugins: false // use these settings
      }
    });

    phantom.outputEncoding = "gbk";//解决乱码问题

    2.打开具体的url

    /*
    获取需要采集的url列表
    */
    casper.start(url, function() {
      casper.GetDetailUrl(url);
    });
    
    /*
    打开具体url
    */
    casper.GetDetailUrl = function(detailUrl) {
      casper.thenOpen(detailUrl, function() {
      console.log(this.getCurrentUrl());
    });
    
    };
    

      

    3.处理当前页面的所有sku价格与信息

    /*
    处理当前页面的所有sku价格与信息
    */
    casper.then(function getPic() {
    
      // console.log(this.getHTML());
    
      // fs.write('123', this.getHTML(), 'w');
    
      product = casper.evaluate(function getProductFromPage() {
        return $('ul[class*="tb-img"]').children().size();
      });
    
      console.log(product);
    
      var str = ''
      for (var i = 1; i <= product; i++) {
        str += casper.getPrice(i) + "|";
      }
    
      var item = new Object();
      item.price = str;
      item.numiid = this.getCurrentUrl();
    
      casper.PostData(item);
    
      // fs.write('myfile.html', str, 'w');
    
      //this.capture("4.png");   
    });

      

    /*
    获取商品的价格
    */
    casper.getPrice = function(index) {
    var dd = casper.clickByImg(index);
    if (dd == -1) {
    return '';
    }
    
    productPrice = casper.evaluate(function getPriceFromPage() {
    return $('.tm-price').first().text().trim();
    });
    
    return (dd + "_" + productPrice);
    
    };
    
    /*
    点击小图及获取此商品的data-value
    */
    casper.clickByImg = function(index) {
    
    var x = require('casper').selectXPath;
    // 如果此商品缺货则跳出
    var path = '//*[@id="J_DetailMeta"]/div[1]/div[1]/div/div[4]/div/div/dl[1]/dd/ul/li[' + index + ']';
    var outOfStock = this.getElementAttribute(x(path), 'class');
    if (outOfStock == 'tb-out-of-stock')
    return '-1';
    
    this.click(x('//*[@id="J_DetailMeta"]/div[1]/div[1]/div/div[4]/div/div/dl[1]/dd/ul/li[' + index + ']/a'));
    
    return this.getElementAttribute(x(path), 'data-value'); // "data-value"
    };
    

      

    4.将最后处理后得到的结果提交到服务器上

    /*
    提交商品价格信息到服务器
    */
    casper.PostData = function(item) {
    
      casper.open('http://XXX/UpdateItemsPrice').then(function() {
    
        this.fill("form", {
          'numiid': item.numiid,
          'value': item.price
        }, false);
    
        this.capture('post.png');
        this.click("#btnSave");
    
        this.echo('GOT it1.' + item.numiid);
      });
    
      this.echo('GOT it2.' + item.numiid);
    
      this.wait(2000, function() {
        this.echo("I've waited for a second.");
      });
    
    
    }
    

    最后run即可.

    casper.run();
    

    通过以上4个步骤我们就能获取到单个链接下,所有sku的促销价格了.

    现在还有个问题,就是我们的nodejs还没出场呢,不会把它忘记的,呵呵.

    为什么这里casperjs都搞定了,还需要nodejs呢?那就是因为casperjs只能处理单个链接,如果有多条链接处理的话,就需要启动多个casperjs的实例来完成.

    上面的所有代码都是casperjs的一个操作步骤,最后的一个run就是让这个实例按我们定义好的步骤来进行的一个完整的流程.

    那么既然如果,我们就请nodejs出场吧~

    var count = 0;
    console.log('主进程开启');
    var startTime = new Date().getTime();
    
    var https = require('http');
    
    /*
    获取需要采集的url列表
    */
    https.get('http://XXX/GetItemsList', function(res) {
      // console.log("statusCode: ", res.statusCode);
      // console.log("headers: ", res.headers);
    
      res.on('data', function(d) {
        // process.stdout.write(d);
    
        var obj = JSON.parse(d)
    
        for (var i = 0; i < obj.items.length; i++) {
          capture(obj.items[i].detail_url);
        }
        ;
    
      });
    
    }).on('error', function(e) {
      console.error(e);
    });
    
    /*
    启动casperjs读取单个url
    */
    function capture(url) {
      count++;
      var spawn = require('child_process').spawn,
        ls = spawn('casperjs', ['casperjs.js', url]);
    
      ls.on('close', function(code) {
        if (code == 1) {
          console.log('child process异常结束。目标:' + url);
        }
    
      });
    
    }
    

      当然,这里我们的casperjs需要进行模块化处理的,其实就是让casperjs可以获取调用的参数啦

    var system = require('system');
    var url = system.args[4];
    

      以上,就是所有采集需要使用到的代码了!怎么样,是不是非常的彪悍啊,整个处理流程只用了区区100来行的代码,就搞定了所有的采集流程.

    参考链接:

    http://www.open-open.com/lib/view/open1338375857589.html

    http://www.cnmiss.cn/?p=413

    http://blog.csdn.net/sagomilk/article/details/20800543

    http://www.cnblogs.com/zeusro/p/4188229.html

    http://casperjs.readthedocs.org/en/latest/modules/casper.html

  • 相关阅读:
    元素查找
    合并果子 2004年NOIP全国联赛普及组
    队列练习1,2,3
    山峰
    栈练习1,2,3
    天使之城
    括号序列
    布尔表达式
    逆波兰表达式
    旅行家的预算 1999年NOIP全国联赛普及组NOIP全国联赛提高组
  • 原文地址:https://www.cnblogs.com/xinzhyu/p/4214669.html
Copyright © 2020-2023  润新知