本日のBGM
以下本題です。
動機
中古の商品を探す際、メル◯リの様に指定の検索条件に対して入荷があった場合に通知を受け取れると
便利ですが、愛する駿河屋では商品単位でしか通知を受け取ることができず、駿河屋の登録履歴にない
新規入荷した商品の有無は都度検索してチェックする必要がありました。
先日puppeteer(Chromiumのヘッドレスブラウザを実行するためのnodeライブラリ)を知り、
検索行為を自動化して商品情報を取得できるか試してみました。
※puppeteerの概要やセットアップ手順などの詳細はリンクの公式サイトを参照下さい。
結果
結論だけ、書く。
以下のスクリプトを作成しました。
const puppeteer = require('puppeteer');
const TARGET_URL = 'https://www.suruga-ya.jp/';
const SEARCH_WORDS = process.argv[2];
async function getScrapingData(search_word) {
const browser = await puppeteer.launch({headless:true})
const page = await browser.newPage()
await page.goto(TARGET_URL, {waitUntil: 'networkidle2'})
await page.type('input[name=search_word]', search_word)
const searchElement = await page.$('input[id=btn]')
await Promise.all([
page.waitForNavigation({waitUntil: "domcontentloaded"}),
searchElement.click()
])
const scrapingData = await page.evaluate(() => {
const dataList = []
const itemList = Array.from(document.querySelectorAll("div.item"))
for (let i = 0; i < itemList.length; i++) {
let item = itemList[i].children[1].children[1].children[0]
// 商品価格はタイムセールなどで子要素が可変になるため判定
let priceList = itemList[i].children[2]
let price = null
for (let j = 0; j < priceList.children.length; j++) {
if (priceList.children[j].className == "price_teika") {
price = priceList.children[j]
break
}
}
let data = {
url: item.href,
title: item.textContent,
price: price.textContent
}
dataList.push(data)
}
return dataList
})
const result = []
result.push({[search_word]: scrapingData})
const json = JSON.stringify(result, null, " ")
await browser.close()
console.log(json)
}
getScrapingData(SEARCH_WORDS)
実行してみる
~/Desktop/puppeteer via ⬢ v10.7.0
➜ node surugaya_search.js marisada
取れた!!
~/Desktop/puppeteer via ⬢ v10.7.0 took 2s
➜ node surugaya_search.js marisada
[
{
"marisada": [
{
"url": "https://www.suruga-ya.jp/product/detail/186129095001",
"title": "wijnruit / Marisada",
"price": "¥250 税込"
}
]
}
]
TODO
- 現状の作りだと引数を1つしか渡せないので、検索条件1件の結果しか受けられない。
複数の検索条件を渡した場合それぞれ非同期で検索し、待ち合わせてまとめて結果が返る様にしたい。 - 前回実行結果を保持して、実行時に取得結果と比較して差分を検知した場合メール等で通知を送れる様にしたい。
結び
puppeteer便利!