最近看到一篇關於爬蟲的文章,而自己又正好在爬蟲,於是就想寫一篇分享下, 讓我們一步一步來,
第一步:安裝核心爬蟲依賴puppeteer,
如果你開啟googole.com是404,執行npm i puppeteer
前,先執行set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
;
ok,如果沒有問題,我們可以在專案根目錄(下文簡稱根目錄)下新建index.js
;
//index.js
const puppeteer=require('puppeteer');
複製程式碼
第二步:選擇一個你需要爬取資源的站點, 作為一個b站使用者,拿b站作為舉例吧,我經常會看排行榜,於是今天我們就爬爬排行榜,地址(www.bilibili.com/ranking/all…
第三步:分析如何爬取站點內容,
開啟chrome瀏覽器,按f12
,按ctrl+shift+c
,你首先就會看到排行榜每個條目對應的一些資訊,如果你有過簡單的爬蟲經驗,你大概可能會直接獲取頁面內容再做提取,當然不是不行,但這種方法一般最後才採取。更優雅的方法是去爬api,要爬api,我們需要將剛剛開啟的除錯工具切換到network介面,在頁面點一點連結跳轉,你會發現一些請求記錄,自己點開看看,那些是載入這個網頁所需要的資源,其中可能就有我們需要的資源,一般來說,xhr選項卡會對應資料內容,但比較神奇,經過除錯發現,資料再js選項卡中找到。
第四步:寫爬取程式碼,
回到我們的index.js
;
//index.js
const puppeteer=require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPad = devices['iPad landscape'];//https://github.com/GoogleChrome/puppeteer/blob/master/DeviceDescriptors.js
const program = require('commander');
//定義一些命令
program
.version('0.0.1')
.option('-t, --top_10','show top 10')
.parse(process.argv);
//記錄結果,如果想寫到資料庫,自行對接即可
const log4js = require('log4js');
log4js.configure({
appenders: { log: { type: 'file', filename: './log/log.log' } },
categories: { default: { appenders: ['log'], level: 'info' } }
});
const logger = log4js.getLogger('log');
const ifOpenBrowser=false;
const lanchConf={
headless:!ifOpenBrowser,
// executablePath: 'C:/Users/xxx/Downloads/chromium/chrome-win32/chrome.exe',//mac使用者自行檢視文件更改
};
const sleep=(time)=>{
return new Promise(resolve=>setTimeout(resolve,time))
};
async function repeat(time,fn,gapTime=500){
if(time>0){
// console.log('do fn',time);
await fn();
await sleep(gapTime);
return repeat(--time,fn,gapTime)
}
// console.log('final');
return {msg:'done'}
}
const banList=['.png','.jpg'];
puppeteer.launch(lanchConf).then(async browser => {
//開啟一個新的頁面
const page = await browser.newPage();
//更改瀏覽器外觀,寬高等
await page.emulate(iPad);
//啟用請求攔截
await page.setRequestInterception(true);
//攔截無用請求
page.on('request', interceptedRequest => {
//遮蔽字尾為.png或.jpg的請求;減少資源消耗
if (banList.some(val=>interceptedRequest.url().match(val))){
interceptedRequest.continue();
//本來是要遮蔽的,但圖片地址在遮蔽的情況下不能獲取,故開啟
} else{
interceptedRequest.continue();
}
});
//跳轉到我們的目標頁面
await page.goto('https://www.bilibili.com/ranking/all/0/0/3',{
waitUntil:'networkidle0'//頁面完全載入
});
// 圖片實現了懶載入,頁面需要滾動到底部,連續點選翻頁鍵一定次數,否則圖片地址可能不能拿到
await repeat(20,async ()=>{
await page.keyboard.press('PageDown',200);
},200);
//通過選擇器找到目標,如果覺得api難懂,建議使用cheerio輔助
const listHandle = await page.$('.rank-list');
//處理子節點內容,難點在選擇器的處理,部分反爬蟲的頁面不會提供一直不變的選擇器
const titles=await listHandle.$$eval('.info .title', nodes => nodes.map(n => n.innerText));
const authors=await listHandle.$$eval('.detail>a>.data-box', nodes => nodes.map(n => n.innerText));
const pts=await listHandle.$$eval('.pts div', nodes => nodes.map(n => n.innerText));
const links=await listHandle.$$eval('.title', nodes => nodes.map(n => n.getAttribute('href')));
const views=await listHandle.$$eval('.detail>.data-box', nodes => nodes.map(n => n.innerText));
const images=await listHandle.$$eval('img', nodes => nodes.map(n => n.getAttribute('src')));
//序列化結果
const res=[];
for(let i=0;i<100;i++){
res[i]={
rank:i+1,
title:titles[i],
author:authors[i],
pts:pts[i],
link:links[i],
view:views[i],
image:images[i]
}
}
//根據命令列輸出資料
if (program.top_10) console.log(res.slice(0,10));
//寫入資料
logger.info(res);
//關閉瀏覽器
await browser.close();
});
複製程式碼
寫入上面的內容,認真瀏覽閱讀相關配置選項,然後補全相關依賴npm i commander log4js
;
開啟當前專案所在位置的命令列介面,輸入node .
程式執行的結果就會輸出到根目錄下的log目錄中,如果想在命令列檢視前10條資料,可以執行node . -t
或node . -top_10
即可,
第五步,上傳程式碼到github,
ps:如果執行了set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
,需設定本地chromium路徑。另外,如果使用cnpm安裝依賴,chromium似乎能正常下載下來,不妨試試