書接上回,我們需要修改程序以達到連續抓取40個頁面的內容。也就是說我們需要輸出每篇文章的標題、鏈接、第一條評論、評論用戶和論壇積分。
如圖所示,$('.reply_author').eq(0).text().trim();
得到的值即為正確的第一條評論的用戶。
{<1>}
在eventproxy獲取評論及用戶名內容後,我們需要通過用戶名跳到用戶界面繼續抓取該用戶積分
代碼如下:
var $ = cheerio.load(topicHtml);
//此URL為下一步抓取目標URL
var userHref = 'https://cnodejs.org' + $('.reply_author').eq(0).attr('href');
userHref = url.resolve(tUrl, userHref);
var title = $('.topic_full_title').text().trim().replace(/\n/g,"");;
var href = topicUrl;
var comment1 = $('.reply_content').eq(0).text().trim();
var author1 = $('.reply_author').eq(0).text().trim();
//傳遞參數到下一次並發抓取
ep.emit('user_html', [userHref, title, href, comment1, author1]);
在eventproxy這一次中,我們要找到score是放在哪裡(class="big")。
{<2>}
找到classname就好辦了,我們先試著把結果輸出一下
代碼如下:
var outcome = superagent.get(userUrl)
.end(function (err, res) {
if (err) {
return console.error(err);
}
var $ = cheerio.load(res.text);
var score = $('.big').text().trim();
console.log(user[1]);
console.log(user[2]);
console.log(user[3]);
console.log(user[4]);
console.log($('.big').text().trim());
return ({
title: user[1],
href: user[2],
comment1: user[3],
author1: user[4],
score1: score
});
});
});
運行程序,這段代碼得到的結果。
{<3>}
但是問題來了,我們在.end()的回調函數中能正確輸出結果,但是不能正確的輸出outcome。仔細一看,需要輸出的outcome是一個Request對象。這是因為粗心犯的錯的,.end()函數並不會傳遞返回值給Request對象,需要將結果返回到上一層(users)。
代碼如下:
//find userDetails
ep.after('user_html', topicUrls.length, function(users){
users = users.map(function(user){
var userUrl = user[0];
var score;
superagent.get(userUrl)
.end(function (err, res) {
if (err) {
return console.error(err);
}
//console.log(res.text);
var $ = cheerio.load(res.text);
score = $('.big').text().trim();
});
return ({
title: user[1],
href: user[2],
comment1: user[3],
author1: user[4],
score1: score
});
});
把users好好地輸出發現除了score1其他是正確值。仔細調試發現,程序是先進行了console.log(),然後再進行.map()。更准確地說,在.map()函數內,.get()的回調函數並沒有執行完賦值score,return 返回值就進行了。這就是回調函數的異步,而外層的同步操作是不會等待回調函數做完操作的。
{<4>}
我的做法就是eventproxy再emit一層消息,伴隨著消息把需要的數據一起傳遞給接收消息操作.after(),只有當消息全部接收完畢,再打印出傳遞的參數(結果)。
代碼如下:
score = $('.big')text().trim();
//新添加
ep.emit('got_score', [user[1], user[2], user[3], user[4], score]);
.....
ep.after('got_score', 10, function(users){
console.log(users);
});
{<6>}
這個問題解決了,但score1的數值好像太大了點吧。再一看,原來class='big'有兩個,用戶的話題收藏也是屬於這個class。我們得通過cheerio的.slice( start, [end] )來切取第一個元素,即將score 修改為 score = $('.big').slice(0).eq(0).text().trim();。正確結果如圖。
{<7>}