スクレイピングしたくてやっぱスクレイピングといえばPythonかなーと思ったけど、Node.js今自分の中で熱いからライブラリーー探したらあったよってこと🤭
読み方はパペッティア
Chromeの操作を自動化できるライブラリ
色々な操作をする時の参考になればいいなとおもう。
使ってみた感想はNode.js慣れしている人ならかなり簡単にスクレイピングできるなって感じです。
よく操作するクラスの種類
・Browser
ブラウザの生成、終了のときくらいしかつかわない
・Page
最も利用するクラス。ページの移動、formへの入力、Elementの取得などができる
・ElementHandle
Pageクラスの「.$()
, .$$()
, .$eval()
, .$$eval()
」などを利用してElementを取得したときに返されたりする。指定したElementに直接click()やhover()をさせたりできる。
【操作するブラウザを生成】
constbrowser=awaitpuppeteer.launch({headless:false//falseにしておくとBrowserが表示されて動くslowMo:50//ブラウザ操作のスピード調整ができる})constpage=awaitbrowser.newPage()awaitpage.setViewport({//ブラウザ幅、高さの設定width:1200,height:800,})
【指定したURLにログイン】
// LOGIN_URL = formのあるページ// LOGIN_USER_SELECTOR = input[type=text]// LOGIN_USER = username// LOGIN_PASS_SELECTOR = input[type=password]// LOGIN_PASS = password// LOGIN_SUBMIT_SELECTOR = input[type=submit]// TARGET_URL = login後開きたいページawaitpage.goto(LOGIN_URL,{waitUntil:'domcontentloaded'})awaitpage.waitForTimeout(2000)awaitpage.type(LOGIN_USER_SELECTOR,LOGIN_USER)awaitpage.type(LOGIN_PASS_SELECTOR,LOGIN_PASS)awaitPromise.all([// ログインボタンクリックpage.waitForNavigation({waitUntil:'networkidle0'}),page.click(LOGIN_SUBMIT_SELECTOR),])awaitpage.goto(TARGET_URL)
・{ waitUntil: load
, domcontentloaded
, networkidle0
, networkidle2
} の4つのoptionがあり、ページ遷移が終わったことを決定するタイミングの違いがある。
・page.waitForTimeout(2000)
指定したミリ秒で処理を一時停止する。
→ goto()
の後は数秒待たせないとtype()
によるform入力がうまく行かない確率が高まる。
・click()
とwaitForNavigation()
を同時に行うのは、click後のページ遷移が完了する前に次の処理を行ってエラーになるのを防ぐため。
【別ウィンドウ、サブウィンドウ、ポップアップへの対処法】
const[popup]=awaitPromise.all([newPromise(resolve=>page.once('popup',resolve)),page.click('a[target=_blank]'),])
・click()
で開かれたサブウィンドウなどは[popup]
に入る。サブウィンドウやポップアップを操作するにはこの[popup]
を操作する。
【要素を取得するよく使う4つの方法+1】
constelement=awaitpage.$("#name")constelements=awaitpage.$$(".names")constvalue=awaitpage.$eval("#name",el=>el.value)constvalues=awaitpage.$$eval(".names",el=>el.value)constnameArray=document.querySelectorAll('.names')
・$(), $$(), は引数のセレクタでElementHandleクラスを生成する。
内部的に、document.querySelector()
とdocument.querySelectorAll()
が行われている。
・$eval(), $$eval()は第2引数に関数をセットすることで引数に指定した要素を操作した値を取得したりできる。
・ElementHandleクラスは、forEachなどができなくて不便なことがある。そういうときは、
document.querySelectorAll()
で要素を取得すれば普通にforEachなどを適用させられる。
【タブ切り替え】
awaitpage.bringToFront()// page.に指定したページを操作できるように切り替える
【実際に使うときの流れ】
ログイン→ログイン後画面でクリック→出てきたサブウィンドウ操作→元画面に戻る→終了
constpuppeteer=require('puppeteer')require('dotenv').config()constenv=process.env(async()=>{//ブラウザ生成constbrowser=awaitpuppeteer.launch({headless:false//falseにしておくとBrowserが表示されて動くslowMo:50})constpage=awaitbrowser.newPage()awaitpage.setViewport({width:1200,height:800,})//form入力&submitでログインawaitpage.goto(env.LOGIN_URL,{waitUntil:'domcontentloaded'})awaitpage.waitForTimeout(2000)//少し待たせないと入力ミスが起きやすいawaitpage.type(env.LOGIN_USER_SELECTOR,env.LOGIN_USER)awaitpage.type(env.LOGIN_PASS_SELECTOR,env.LOGIN_PASS)awaitPromise.all([// ログインボタンクリックpage.waitForNavigation({waitUntil:'networkidle0'}),page.click(env.LOGIN_SUBMIT_SELECTOR),])//ログイン後ページへ飛ぶawaitpage.goto(env.TARGET_URL)//clickによって表示されたpopup取得const[popup]=awaitPromise.all([newPromise(resolve=>page.once('popup',resolve)),page.click('input[value="~"]'),])//もとのページへbackawaitpage.goBack({waitUntil:'networkidle0'})//ブラウザ終了awaitbrowser.close()})()
・dotenvモジュールで定数管理している
puppeteerを使う上での注意点
ページロードが終わるタイミングと要素取得のタイミングがズレると要素の取得ができなかったり、ページ遷移が終わる前に次の処理に行ってしまっていたりするので、常にタイミングには気をつけないといけない。