Puppeteer爬取單頁面網站的資料示例
阿新 • • 發佈:2020-08-11
場景
- 昨天試了一下爬取根據網頁查詢引數的不同而變化的頁面,今天來試試爬取單頁面應用,url不發生變化,只是頁面內的按鈕點選導致資料的重新請求。
主要實現思路
- 利用Puppeteer可以模擬使用者點選操作,等待介面返回等各種優秀的API,可以保證在資料結束後完成頁面資料提取。
程式碼實現,以開源眾包的頁面為例
- 開源眾包這個頁面挺適合用來做示例,因為通過下一頁的按鈕去呼叫ajax請求,當到達最後一頁時,下一頁按鈕會自動有一個disabled屬性,我們就可以根據這個disabled屬性來判斷是否還有下一頁。
const common = async (workFunc) => { const startTime = +new Date(); console.log(`進入方法`); const browser = await puppeteer.launch(); const page = await browser.newPage(); typeof workFunc === 'function' && await workFunc(page); await page.close(); await browser.close(); console.log('方法結束,耗費時長:', +new Date() - startTime); }; const crawler = async (url, selectors) => { const list = []; await common(async (page) => { await page.goto(url); async function runOnce() { const result = await page.evaluate((selectors) => { const res = []; selectors.forEach(selector => { const { key, value, field } = selector; const domList = document.querySelectorAll(value); Array.prototype.slice.apply(domList).forEach((dom, index) => { const newVal = dom[field] || dom.innerText; res[index] = res[index] || {}; res[index][key] = newVal; }) }) return res; }, selectors); list.push(...result); const disabled = await page.$eval('.btn-next', el => el.disabled); console.log('一頁資料已獲取,當前下一頁按鈕狀態:', result[0], disabled); if (!disabled) { // 觸發按鈕點選,使用page.click就是不能觸發按鈕的點選,只能用這個騷操作 await page.$eval('.btn-next', el => el.click()); // 等待介面完成 await page.waitForResponse(response => { return response.url().includes('contractor-browse-project-and-reward') && response.status() === 200; }) await runOnce(); } } await runOnce(); }) return list; } // 使用 const url = 'https://zb.oschina.net/projects/list.html'; const selectors = [ { key: 'title', value: '.el-row .title', field: 'innerText' }, { key: 'tags', value: '.el-row .tags', field: 'innerText' }, { key: 'money', value: '.el-row .money', field: 'innerText' }, { key: 'skills', value: '.el-row .skills', field: 'innerText' }, { key: 'bidding', value: '.el-row .bidding', field: 'innerText' }, { key: 'pubtime', value: '.el-row .pubtime', field: 'innerText' } ]; crawler(url, selectors).then(result => { console.log(result); fs.writeFile('專案.json', JSON.stringify(result), 'utf-8', err => { if(err) { console.log(err); return; } }); })
結果展示
-
小結
- 不得不承認,Puppeteer對於爬取這種以前很難爬取的單頁面應用來說,確實提供了不少便利。