目前的想法如下:1.取得分類下所有的標籤頁面url,2.循環抓取頁面中抓取目前標籤頁取得json的api位址,3.抓取目前標籤的商品列表,4.抓取目前標籤的分頁載入中的商品。
但現在做到的是,第二步開始,未等到2-4執行完畢再循環下一個,有嘗試用async/await,但是未實現流程控制。此處求教。
var http = require('http');
var fs = require("fs");
var superagent = require('superagent');
var urls = [];
var pageIndex = 1;
var xlsxData = '';
getGoodsUrl(urls);
function getGoodsUrl(urls){
superagent
.post('http://bravetime.davdian.com/index.php?c=Index&a=getCatNavList')
.type('text/html; charset=utf-8')
.set('Accept','application/json, text/javascript, */*; q=0.01')
.end(function(err, res) {
if (err) {
console.log('分类数据请求失败');
} else {
console.log('分类数据请求成功');
var resData = res.text;
var resData = JSON.parse(resData);
if(resData.data.length > 0){
resData.data.forEach(function(item){
var rowObj = [];
var title = item.title;
var category = item.content.category;
category.forEach(function(item){
var text = [];
text.push(title+ '--' + item.text);
text.push(item.link);
rowObj.push(text);
});
urls.push(rowObj);
});
loopUrls(urls);
} else {
console.log('分类数据为空');
}
// saveInfo(xlsxData);
}
})
}
function loopUrls(urls){
urls.forEach(function(item){
var row = item;
row.forEach(function(item){
var tagTitie = item[0];
var tegUrl = item[1];
getApiUrl(tagTitie,tegUrl);
});
});
}
function getApiUrl(title,url){
var realUrl = 'http://bravetime.davdian.com' + url;
http.get(realUrl,function(res){
var html = '';
res.on('data',function(data){
html += data;
});
res.on('end',function(){
console.log('正在获取' + title + '页面数据');
var reg = /goodsUrl = "(.+)"/;
var apiUrl = reg.exec(html);
getGoodsJson(apiUrl[1],pageIndex);
});
}).on('error',function(){
console.log('获取html出错!!');
});
}
function getGoodsJson(url,pageIndex){
superagent
.post('http://bravetime.davdian.com/' + url + 'page_size=10&rp=catergory_search&rl=list')
.send({page:pageIndex})
.type('application/x-www-form-urlencoded; charset=UTF-8')
.set('Accept','application/json, text/javascript, */*; q=0.01')
.end(function(err, res) {
if (err) {
console.log('第' + pageIndex + '页请求失败');
} else {
console.log('第' + pageIndex + '页请求成功');
var resData = res.text;
var resData = JSON.parse(resData);
if(resData.data.length > 0){
resData.data.forEach(function(item){
xlsxData = xlsxData + item.goods_name + ' ' + item.shop_price + ' ' + item.goods_number + '\r\n';
});
pageIndex = parseInt(pageIndex) + 1;
setTimeout(function(){
getGoodsJson(url,pageIndex);
},200);
} else {
console.log('数据已加载完毕');
saveTxt(xlsxData);
pageIndex = 1;
return false;
}
// saveInfo(xlsxData);
}
})
}
function saveTxt(data){
fs.writeFile("create.txt",data,function (err) {
if (err) throw err ;
console.log("File Saved !"); //文件被保存
}) ;
}
function saveInfo(data){
var buffer = xlsx.build([{name: "mySheetName", data: data}]);
fs.writeFileSync("myFile.xlsx", buffer, 'binary');
console.log('excel保存成功');
}
以下是結果圖示及程式碼執行順序:
##
生成器
非同步
承諾
你這整個過程都是非同步的,沒看出一點同步的意思。我覺得你可能沒有理解什麼是異步。
Async/await 是建立在 Promise 基礎上的,而 Superagent 本身是支援 Promise 的,你可以直接用 async/await。
http://visionmedia.github.io/...
http://www.ruanyifeng.com/blo...
然後你需要的就是把
http.get()
換成superagent.get()
。一般他人的業務邏輯都沒什麼耐性能看下去。
如樓上所言,Async/await 是建立在Promise 基礎上,如果你調用的第三方庫的API接口沒有返回promise對象的話,想用Async/await 你只能自己每一步都新建一個promise對象,這樣其實寫起來也很麻煩,當然如果能回傳promise物件的話就很方便。
以下不用promise 用node核心模組event寫的,供你參考:
可以使用 Node8 的
util.promisify
,或 Bluebird 等把 Node 回呼形式的函數改成 Promise 風格的函數,然後就可以使用async/await
來寫程式碼。程式碼本身還是非同步調用,只是寫法看起來像是同步的。所以寫的時候還是要注意流程結構,尤其是寫循環的時候。代的程式碼太長,所以我寫個小例子來說明