這篇文章將為大家詳細講解有關(guān)Chrome+Puppeteer+Node.js爬取網(wǎng)站的方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
成都創(chuàng)新互聯(lián)專注于企業(yè)營銷型網(wǎng)站建設(shè)、網(wǎng)站重做改版、伊吾網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、H5高端網(wǎng)站建設(shè)、電子商務(wù)商城網(wǎng)站建設(shè)、集團公司官網(wǎng)建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為伊吾等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
在本教程中,您將學習如何使用 JavaScript 自動化和清理 web 。要做到這一點,我們將使用 Puppeteer 。Puppeteer是一個允許我們控制無頭Chrome 的 Node 庫 API。Headless Chrome是一種在不真實運行 Chrome 的情況下運行 Chrome 瀏覽器的方法。
【視頻教程推薦:nodejs視頻教程 】
如果這一切都沒有意義,您真正需要知道的是,我們將編寫 JavaScript 代碼,使 Google Chrome 實現(xiàn)自動化。
開始之前,您需要在計算機上安裝 Node 8+。您可以在此處進行安裝。確保選擇「當前」版本 8+ 版本。
如果您以前從未使用過 Node 并想學習,請查看:學習 Node JS 3 種最佳在線 Node JS 課程。
安裝完 Node 后,創(chuàng)建一個新的項目文件夾并安裝 Puppeteer。 Puppeteer 附帶了 Chromium 的最新版本,該版本可以與 API 一起使用:
npm install --save puppeteer
安裝完 Puppeteer 之后,我們將首先介紹一個簡單的示例。此示例來自Puppeteer 文檔(進行了少量更改)。我們將通過代碼逐步介紹對您訪問的網(wǎng)站如何截圖。
首先,創(chuàng)建一個名為test.js
的文件,然后復制以下代碼:
const puppeteer = require('puppeteer'); async function getPic() { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://google.com'); await page.screenshot({path: 'google.png'}); await browser.close(); } getPic();
讓我們逐行瀏覽這個例子。
getPic()
。該函數(shù)將保存我們所有的自動化代碼。getPic()
函數(shù)。需要注意的是,getPic()
函數(shù)是一個異步
函數(shù),并利用了新的ES 2017async/await
功能。由于這個函數(shù)是異步的,所以當調(diào)用時它返回一個Promise
。當Async
函數(shù)最終返回值時,Promise
將被解析(如果存在錯誤,則Reject
)。
由于我們使用的是async
函數(shù),因此我們可以使用await
表達式,該表達式將暫停函數(shù)執(zhí)行并等待Promise
解析后再繼續(xù)。 如果現(xiàn)在所有這些都沒有意義,那也沒關(guān)系。隨著我們繼續(xù)學習教程,它將變得更加清晰。
現(xiàn)在,我們概述了主函數(shù),讓我們深入了解其內(nèi)部功能:
const browser = await puppeteer.launch();
這是我們實際啟動 puppeteer 的地方。實際上,我們正在啟動 Chrome 實例,并將其設(shè)置為等于我們新創(chuàng)建的browser
變量。由于我們使用了await
關(guān)鍵字,因此該函數(shù)將在此處暫停,直到Promise
解析(直到我們成功創(chuàng)建 Chrome 實例或出錯)為止。
const page = await browser.newPage();
在這里,我們在自動瀏覽器中創(chuàng)建一個新頁面。我們等待新頁面打開并將其保存到我們的page
變量中。
await page.goto('https://google.com');
使用我們在代碼的最后一行中創(chuàng)建的page
,現(xiàn)在可以告訴page
導航到URL。在此示例中,導航到 google。我們的代碼將暫停,直到頁面加載完畢。
await page.screenshot({path: 'google.png'});
現(xiàn)在,我們告訴 Puppeteer 截取當前頁面
的屏幕。screenshot()
方法將自定義的.png
屏幕截圖的保存位置的對象作為參數(shù)。同樣,我們使用了await
關(guān)鍵字,因此在執(zhí)行操作時我們的代碼會暫停。
await browser.close();
最后,我們到了getPic()
函數(shù)的結(jié)尾,并且關(guān)閉了browser
。
您可以使用 Node 運行上面的示例代碼:
node test.js
這是生成的屏幕截圖:
太棒了!為了增加樂趣(并簡化調(diào)試),我們可以不以無頭方式運行代碼。
這到底是什么意思?自己嘗試一下,看看吧。更改代碼的第4行從:
const browser = await puppeteer.launch();
改為:
const browser = await puppeteer.launch({headless: false});
然后使用 Node 再次運行:
node test.js
太酷了吧?當我們使用{headless:false}
運行時,您可以真實看到 Google Chrome 按照您的代碼工作。
在繼續(xù)之前,我們將對這段代碼做最后一件事。還記得我們的屏幕截圖有點偏離中心嗎?那是因為我們的頁面有點小。我們可以通過添加以下代碼行來更改頁面的大小:
await page.setViewport({width: 1000, height: 500})
這個屏幕截圖更好看點:
這是本示例的最終代碼:
const puppeteer = require('puppeteer'); async function getPic() { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); await page.goto('https://google.com'); await page.setViewport({width: 1000, height: 500}) await page.screenshot({path: 'google.png'}); await browser.close(); } getPic();
既然您已經(jīng)了解了 Headless Chrome 和 Puppeteer 的工作原理,那么讓我們看一個更復雜的示例,在該示例中我們事實上可以抓取一些數(shù)據(jù)。
首先, 在此處查看 Puppeteer 的 API 文檔。 如您所見,我們有很多方法可以使用, 不僅可以點擊網(wǎng)站,還可以填寫表格,輸入內(nèi)容和讀取數(shù)據(jù)。
在本教程中,我們將抓取 Books To Scrape ,這是一家專門設(shè)置的假書店,旨在幫助人們練習抓取。
在同一目錄中,創(chuàng)建一個名為scrape.js
的文件,并插入以下樣板代碼:
const puppeteer = require('puppeteer'); let scrape = async () => { // 實際的抓取從這里開始... // 返回值 }; scrape().then((value) => { console.log(value); // 成功! });
理想情況下,在看完第一個示例之后,上面的代碼對您有意義。如果沒有,那沒關(guān)系!
我們上面所做的需要以前安裝的puppeteer
依賴關(guān)系。然后我們有scraping()
函數(shù),我們將在其中填入抓取代碼。此函數(shù)將返回值。最后,我們調(diào)用scraping
函數(shù)并處理返回值(將其記錄到控制臺)。
我們可以通過在scrape
函數(shù)中添加一行代碼來測試以上代碼。試試看:
let scrape = async () => { return 'test'; };
現(xiàn)在,在控制臺中運行node scrape.js
。您應(yīng)該返回test
!完美,我們返回的值正在記錄到控制臺?,F(xiàn)在我們可以開始補充我們的scrape
函數(shù)。
步驟1:設(shè)置
我們需要做的第一件事是創(chuàng)建瀏覽器實例,打開一個新頁面,然后導航到URL。我們的操作方法如下:
let scrape = async () => { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); await page.goto('http://books.toscrape.com/'); await page.waitFor(1000); // Scrape browser.close(); return result;};
太棒了!讓我們逐行學習它:
首先,我們創(chuàng)建瀏覽器,并將headless
模式設(shè)置為false
。這使我們可以準確地觀察發(fā)生了什么:
const browser = await puppeteer.launch({headless: false});
然后,我們在瀏覽器中創(chuàng)建一個新頁面:
const page = await browser.newPage();
接下來,我們轉(zhuǎn)到books.toscrape.com
URL:
await page.goto('http://books.toscrape.com/');
我選擇性地添加了1000
毫秒的延遲。盡管通常沒有必要,但這將確保頁面上的所有內(nèi)容都加載:
await page.waitFor(1000);
最后,完成所有操作后,我們將關(guān)閉瀏覽器并返回結(jié)果。
browser.close(); return result;
步驟2:抓取
正如您現(xiàn)在可能已經(jīng)確定的那樣,Books to Scrape 擁有大量的真實書籍和這些書籍的偽造數(shù)據(jù)。我們要做的是選擇頁面上的第一本書,然后返回該書的標題和價格。這是要抓取的圖書的主頁。我有興趣點第一本書(下面紅色標記)
查看 Puppeteer API,我們可以找到單擊頁面的方法:
page.click(selector[, options])
selector
用于選擇要單擊的元素的選擇器,如果有多個滿足選擇器的元素,則將單擊第一個。幸運的是,使用 Google Chrome 開發(fā)者工具可以非常輕松地確定特定元素的選擇器。只需右鍵單擊圖像并選擇檢查:
這將打開元素面板,突出顯示該元素?,F(xiàn)在,您可以單擊左側(cè)的三個點,選擇復制,然后選擇復制選擇器:
太棒了!現(xiàn)在,我們復制了選擇器,并且可以將click
方法插入程序。像這樣:
await page.click('#default > p > p > p > p > section > p:nth-child(2) > ol > li:nth-child(1) > article > p.image_container > a > img');
我們的窗口將單擊第一個產(chǎn)品圖像并導航到該產(chǎn)品頁面!
在新頁面上,我們對商品名稱和商品價格均感興趣(以下以紅色概述)
為了檢索這些值,我們將使用page.evaluate()
方法。此方法使我們可以使用內(nèi)置的 DOM 選擇器,例如querySelector()
。
我們要做的第一件事是創(chuàng)建page.evaluate()
函數(shù),并將返回值保存到變量result
中:
const result = await page.evaluate(() => {// return something});
在函數(shù)里,我們可以選擇所需的元素。我們將使用 Google Developers 工具再次解決這一問題。右鍵單擊標題,然后選擇檢查:
正如您將在 elements 面板中看到的那樣,標題只是一個h2
元素。我們可以使用以下代碼選擇此元素:
let title = document.querySelector('h2');
由于我們希望文本包含在此元素中,因此我們需要添加.innerText
-最終代碼如下所示:
let title = document.querySelector('h2').innerText;
同樣,我們可以通過單擊右鍵檢查元素來選擇價格:
如您所見,我們的價格有price_color
類,我們可以使用此類選擇元素及其內(nèi)部文本。這是代碼:
let price = document.querySelector('.price_color').innerText;
現(xiàn)在我們有了所需的文本,可以將其返回到一個對象中:
return { title, price }
太棒了!我們選擇標題和價格,將其保存到一個對象中,然后將該對象的值返回給result
變量。放在一起是這樣的:
const result = await page.evaluate(() => { let title = document.querySelector('h2').innerText; let price = document.querySelector('.price_color').innerText; return { title, price }});
剩下要做的唯一一件事就是返回result
,以便可以將其記錄到控制臺:
return result;
您的最終代碼應(yīng)如下所示:
const puppeteer = require('puppeteer'); let scrape = async () => { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); await page.goto('http://books.toscrape.com/'); await page.click('#default > p > p > p > p > section > p:nth-child(2) > ol > li:nth-child(1) > article > p.image_container > a > img'); await page.waitFor(1000); const result = await page.evaluate(() => { let title = document.querySelector('h2').innerText; let price = document.querySelector('.price_color').innerText; return { title, price } }); browser.close(); return result; }; scrape().then((value) => { console.log(value); // 成功! });
您可以通過在控制臺中鍵入以下內(nèi)容來運行 Node 文件:
node scrape.js // { 書名: 'A Light in the Attic', 價格: '£51.77' }
您應(yīng)該看到所選圖書的標題和價格返回到屏幕上!您剛剛抓取了網(wǎng)頁!
現(xiàn)在您可能會問自己,當標題和價格都顯示在主頁上時,為什么我們要點擊書?為什么不從那里抓取呢?而在我們嘗試時,為什么不抓緊所有書籍的標題和價格呢?
因為有很多方法可以抓取網(wǎng)站! (此外,如果我們留在首頁上,我們的標題將被刪掉)。但是,這為您提供了練習新的抓取技能的絕好機會!
挑戰(zhàn)
目標 ——從首頁抓取所有書名和價格,并以數(shù)組形式返回。這是我最終的輸出結(jié)果:
開始!看看您是否可以自己完成此任務(wù)。與我們剛創(chuàng)建的上述程序非常相似,如果卡住,請向下滾動…
GO! See if you can accomplish this on your own. It’s very similar to the above program we just created. Scroll down if you get stuck…
提示:
此挑戰(zhàn)與上一個示例之間的主要區(qū)別是需要遍歷大量結(jié)果。您可以按照以下方法設(shè)置代碼來做到這一點:
const result = await page.evaluate(() => { let data = []; // 創(chuàng)建一個空數(shù)組 let elements = document.querySelectorAll('xxx'); // 選擇全部 // 遍歷每一個產(chǎn)品 // 選擇標題 // 選擇價格 data.push({title, price}); // 將數(shù)據(jù)放到數(shù)組里, 返回數(shù)據(jù); // 返回數(shù)據(jù)數(shù)組 });
如果您不明白,沒事!這是一個棘手的問題…… 這是一種可能的解決方案。在以后的文章中,我將深入研究此代碼及其工作方式,我們還將介紹更高級的抓取技術(shù)。如果您想收到通知,請務(wù)必 在此處輸入您的電子郵件。
方案:
const puppeteer = require('puppeteer'); let scrape = async () => { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); await page.goto('http://books.toscrape.com/'); const result = await page.evaluate(() => { let data = []; // 創(chuàng)建一個空數(shù)組, 用來存儲數(shù)據(jù) let elements = document.querySelectorAll('.product_pod'); // 選擇所有產(chǎn)品 for (var element of elements){ // 遍歷每個產(chǎn)品 let title = element.childNodes[5].innerText; // 選擇標題 let price = element.childNodes[7].children[0].innerText; // 選擇價格 data.push({title, price}); // 將對象放進數(shù)組 data } return data; // 返回數(shù)組 data }); browser.close(); return result; // 返回數(shù)據(jù) }; scrape().then((value) => { console.log(value); // 成功! });
關(guān)于Chrome+Puppeteer+Node.js爬取網(wǎng)站的方法就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。