由於一些業務需求須要採集淘寶店鋪商品的銷售價格,可是淘寶詳情頁面的價格顯示是經過js動態調用顯示的.因此就無法經過普通的獲取頁面html而後經過正則或者xpath的方式獲取到想到的信息了.javascript
所幸咱們如今有了casperjs.這個是一個基於Phantomjs的庫,而Phantomjs則是一個服務器端的js api的webkit瀏覽器.是否是很神奇?真的是.net的之外的世界很神奇,咱們要多走去看看.html
好了,如今廢話很少說,開始切入正題.java
首先就是就是幾個相關庫的安裝.安裝過程很簡單,相關內容你們百度便可.在文章的底部我也會列出參考連接.node
咱們先進行下簡要的分析:jquery
具體的操做流程就是利用casperjs模擬鼠標點擊商品的圖片,而後網頁顯示對應的價格.web
默認狀況是這樣的,若是不點擊顏色分類下的圖片,則對應的促銷價格也只是會顯示一個區間.數據庫
而只要咱們點擊了顏色分類對應的圖片以後,則會是下面的效果api
那麼咱們具體的操做步驟應該是:瀏覽器
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