再上一篇我們把資料擷取下來了
接下來我們把他分類與儲存吧
我們可以看到我們擷取下來的資料長這樣
這樣這資料完全沒有規律沒辦法分類
Go day 4 (variables)大家來排隊,一個一個串起來~超展開 – 深入冰山Day4 Hoisting & Scope ChainHow to install Solus OS Using VMware ?團隊建立AMP(Lession 4) - 字型03. ICO 網站多國語言功能JS30-Day44.繼承抽象類別,避免重複方法。
我們看到他一次抓到很多比資料他一定是某種集合
所以我們可以使用cheerio提供的each去跑一件一件
await $('div #ir-list div div ul.list-unstyled.ir-lists li.ir-list h3.ir-list__title a').each((i,el)=>{
console.log($(el).text())
})
把原本的改掉後儲存並執行
就可以看到結果變成這樣
每一筆資料都分別的出來了
Go day 4 (variables)
大家來排隊,一個一個串起來~
超展開 – 深入冰山
Day4 Hoisting & Scope Chain
How to install Solus OS Using VMware ?
團隊建立
AMP(Lession 4) - 字型
03. ICO 網站多國語言功能
JS30-Day4
4.繼承抽象類別,避免重複方法。
但抓到這樣我們忘了一個東西
就是瀏覽數
當然我們可以跑一次迴圈再抓一次資料
但這樣是比較沒有效率的
所以我們又要修改原本的程式
同時抓兩個資料
我們可以看到這頁我們要的資料都在這欄 li 底下
我們就把TAG往前推到 il 就好
並把程式改成這樣
//大家可以往下看留言
//感謝 marlin12 提供更好的解法
await $('div #ir-list div div ul.list-unstyled.ir-lists li.ir-list').each((i,el)=>{
//我們把裏面的el再用cheerio load給其他變數,方便拿取我們要的資料
let $2 = await cheerio.load($(el).html())
})
接這我們可以透過 $2 這個變數下去抓取我們要的更多資料
並把資料儲存起來
會長這樣
await $('div #ir-list div div ul.list-unstyled.ir-lists li.ir-list').each((i,el)=>{
let $2 = cheerio.load($(el).html())
let title = $2('h3.ir-list__title a').text().trim() //text是抓取文字, trim是去頭尾空字串
/**majo2013
於 2018-10-04 發表 | 39 次瀏覽*/
//原本我們的view會抓到像上面的一樣的文字,我們先去頭尾空字串,再用split去分割瀏覽前得特殊符號取得第一個元素
let view = $2('div.ir-list__info').text().trim().split('|')[1]
//順便把文章連結 類別抓下來吧
let category = $2('div a div.group-badge__name').text().trim()
let herf = $2('h3.ir-list__title a').attr('href') //attr是抓取 a 裏面的href元素
console.log('title '+ title +'\n view '+view+'\n category '+category+'\n href '+herf)
})
大家執行一遍後我們要的資料已經都抓下來了
接著我們要儲存資料
//先再外面建立陣列
let data = []
await $('div #ir-list div div ul.list-unstyled.ir-lists li.ir-list').each( (i, el) => {
let $2 = cheerio.load($(el).html())
//裏面建立一個物件並把資料都放進去
//這是物件 不了解的可以搜尋了解一下
let tmp = {
category: $2('div a div.group-badge__name').text().trim(),
title: $2('h3.ir-list__title a').text().trim(),
view: $2('div.ir-list__info').text().trim().split('|')[1],
herf: $2('h3.ir-list__title a').attr('href')
}
data.push(tmp)
})
console.log(data)
有人可能會有些疑問,為甚麼裏面不用async await
因為整個each包在一個await下 如果再放的話會產生非同步
還是不理解的話可以搜尋一下
或者再下面留言,讓我知道我需不需要再補一篇async await的解釋文章
如果要寫nodejs async await的概念一定要理解清楚,不然將來會吃很多虧(bugs)
接著我們把檔案透過node本身內建的fs儲存下來
今天程式碼就長這樣
const puppeteer = require('puppeteer');
const cheerio = require('cheerio');
(async () => {
const browser = await puppeteer.launch({
headless: true
});
const page = await browser.newPage();
await page.goto('https://ithelp.ithome.com.tw/ironman');
//先等待網頁載入到footer,不然有時候執行太快抓不到網頁
await page.waitForSelector('section')
//把網頁的body抓出來
let body = await page.content()
//接著我們把他丟給cheerio處理
let $ = await cheerio.load(body)
//先再外面建立陣列
let data = []
await $('div #ir-list div div ul.list-unstyled.ir-lists li.ir-list').each((i, el) => {
let $2 = cheerio.load($(el).html())
//裏面建立一個物件並把資料都放進去
//這是物件 不了解的可以搜尋了解一下
let tmp = {
category: $2('div a div.group-badge__name').text().trim(),
title: $2('h3.ir-list__title a').text().trim(),
view: $2('div.ir-list__info').text().trim().split('|')[1],
herf: $2('h3.ir-list__title a').attr('href')
}
data.push(tmp)
})
const fs = require('fs');
const content = JSON.stringify(data); //轉換成json格式
fs.writeFile("ithome.json", content, 'utf8', function (err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
await browser.close()
})();
大家在同個資料夾底下就可以看到我們抓下來的檔案
今天我們只抓到第1頁資料
下一篇
我們要把所有文章都抓下來
當然如果有興趣自己找方法也很快
cheerio.load($(el).html())會把整個el的html重新載入,拖慢速度。改用$(el).find()可以提速2至3倍。
let data = [];
$('ul.ir-lists li.ir-list').each((i, el) => {
const $el = $(el);
const info = {
category : $el.find('div.group-badge__name').text().trim(),
title : $el.find('h3.ir-list__title a').text().trim(),
view : $el.find('div.ir-list__info').text().split('|')[1].trim(),
href : $el.find('h3.ir-list__title a').attr('href')
};
data.push( info );
});