Install Git and Node, then type in terminal:
$ git clone https://github.com/rayc2045/ghibli-crawler
$ cd ghibli-crawler
$ sh download.sh
If you don't use Brave browser, remember to change the executablePath
in index.js to your Chromium browser file path, or directly replace the npm package "puppeteer-core" with "puppeteer" and remove the executablePath
in index.js:
$ npm i puppeteer
// index.js
const puppeteer = require('puppeteer-core'); // Replace "puppeteer-core" with "puppeteer"
(async () => {
const browser = await puppeteer.launch({
executablePath: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser', // Remove this line
Awhile after running $ node index.js
, all photos will be saved in the "img" folder. (321.9 MB)
最近對爬蟲感到興趣,幾天的研究發現 Puppeteer 這套由 Google 開源、使用無介面操作 Chrome 做自動化測試的 Node.js 函式庫也能用來爬取資料,因此決定使用 Node.js 搭配 Puppeteer 和 Axios (基於 promise 的 HTTP 庫),自動化將先前作品「吉卜力相簿」 上的一千多張作品劇照下載下來。
Puppeteer 可由 npm 進行安裝,如果電腦中有基於 Chromium 的瀏覽器,可下載容量較小的核心版本,之後再將啟動路徑設置為應用程式路徑即可 (範例使用 Brave 瀏覽器):
$ npm i puppeteer-core
const puppeteer = require('puppeteer-core');
(async () => {
const browser = await puppeteer.launch({
executablePath: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser'
});
})();
Puppeteer 的語法並不難,在官方文件中可找到許多範例;而其中因為大多自動化操作屬於非同步行為,需要另外使用 async/await 語法確保程式依序執行,算是比較需要注意的部分,較常用到的指令有:
const page = await browser.newPage();
const cookies = await page.cookies([...urls]); // 獲取此頁 cookies
await page.setCookie(cookieObject1, cookieObject2); // 設定 cookie
await page.setUserAgent(userAgent); // 設定 userAgent
const navbar = await page.$('.nav'); // 抓取單一元素
const links = await page.$$('a'); // 抓取複數元素
const title = await page.evaluate(() =>
document.querySelector('#title').textContent.trim()); // 取得 title
const imageLinks = await page.evaluate(() =>
[...document.querySelectorAll('img')].map(img => img.src)); // 取得圖片網址
await page.type('#email', 'example@gmail.com'); // 輸入
await page.click('.loginBtn'); // 點擊
// 單一元素截圖
const target = await page.$('img');
await target.screenshot({ path: `./img/example.png` });
// 整頁截圖
await page.screenshot({
path: './img/screenshot.png',
type: 'png',
fullPage: true
// clip: { x: 0, y: 0, width: 1920, height: 800 }
});
const url = await page.url(); // 當前網址
await page.reload(); // 重整頁面
await page.goBack(); // 上一頁
await page.goForward(); // 下一頁
await page.waitForNavigation(); // 等待頁面跳轉
await page.waitForSelector('.navSubmenu'); // 等待當前頁面 AJAX 元素
await page.waitForResponse(res =>
res.url().match(encodeURIComponent(name)) && response.ok()); // 等待資料回應完成
await page.waitForFunction(() =>
[...document.querySelectorAll('div[class="asset"]')].some(el =>
el.textContent.includes('Assets Folder'))); // 等待功能完成
這次實作中遇到最大的問題是在大量下載圖片時,Node 端遇到的錯誤,原因由短時間內發出過多請求導致圖片下載失敗,透過加上 slowMo
參數,將自動化操作的速度減慢得以解決:
(node:15319) UnhandledPromiseRejectionWarning: Error: getaddrinfo ENOTFOUND www.ghibli.jp
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26)
(Use `node --trace-warnings ...` to show where the warning was created)
const browser = await puppeteer.launch({
executablePath: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser',
slowMo: 1200
});
完成初次爬蟲和自動化程序的過程中小有成就感,如果未來有需求,也許還會使用類似的方式做網頁轉 PDF、自動化登入操作,又或是定時爬完資料後結合寄信功能做 Email 通知吧!
文章同步刊載於 Medium。