因為一些業務需求需要采集淘寶店鋪商品的銷售價格,但是淘寶詳情頁面的價格顯示是通過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
