はじめに
あーあ、スクレイピングしたいな。
ということで Nuxt on Docker でスクレイピングします。
node系だとpuppeteerというライブラリがスクレイピングするのにおすすめっぽかったので、NuxtのserverMiddlewareからサクッとスクレイピングします。
あまり人に迷惑をかけてはいけないと言われて育ったので、スクレイピングは自分のサイトにします。(ログイン不要だよ。ぜひ使ってみてね♪)
toribure | ひとりでもチームでも使えるシンプルイズベストなブレストツール
やや宣伝ですね。トップページにかわいい鳥(いらすとや)の画像があります。今回はこれをスクレイピングで取ってきて表示させようと思います。
Nuxt on Dockerの準備
このあたりは他にも記事がいっぱいあると思うのでさらーっと。
ちなみに環境は
$ docker -v
Docker version 19.03.13-beta2, build ff3fbc9d55
$ docker-compose -v
docker-compose version 1.26.2, build eefe0d31
でした。
Nuxtアプリを作る
$ docker run --rm -it -w /app -v `pwd`:/app node yarn create nuxt-app scraping
? Project name: scraping
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: None
? Nuxt.js modules: Axios
? Linting tools:
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools:
axios
だけ後で使うので意識的に入れておきます。
ちなみに記事作成時点でnode:latest
イメージのバージョンは14.9.0、create-nuxt-app
のバージョンはv3.2.0で、nuxt
は2.14.0が入りました。
Dockerfile, docker-compose.ymlを準備する
ここからは今できたばかりのscraping/
ディレクトリが作業ディレクトリです。
$ cd scraping
FROM nodeENV HOME=/app \
LANG=C.UTF-8 \
TZ=Asia/Tokyo \
HOST=0.0.0.0
WORKDIR ${HOME}RUN apt-get update \
&& apt-get install-y wget gnupg \
&& wget -q-O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'\
&& apt-get update \
&& apt-get install-y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
--no-install-recommends\
&&rm-rf /var/lib/apt/lists/*COPY package.json ${HOME}COPY yarn.lock ${HOME}RUN yarn installCOPY . ${HOME}EXPOSE 3000CMD ["yarn", "run", "dev"]
RUN apt-get ...
あたりはpuppeteerのトラブルシューティングに詳細があります。ブラウザやフォントがコンテナ内に用意されていないとエラーになるってことです。
version:"3"services:nuxt:build:.volumes:-.:/appports:-3000:3000
ここまで終わったら一度コンテナをビルドしておきます。
$ docker-compose build
スクレイピングアプリを作るぞ
puppeteer導入
yarnでいれちゃいます。
$ docker-compose run --rm nuxt yarn add puppeteer
APIを作る
serverMiddlewareを使っていきます。公式でも紹介されているexpress-templateを参考にserverMiddlewareをAPIとして通してスクレイピングしていきます。
exportdefault{...,serverMiddleware:{'/api':'~/api'}}
これで/api
のアクセスを~/api/index.js
に流します。のでファイル作ります。
$ mkdir api
$ touch api/index.js api/scraping.js
ファイルを2つ作りましたがindex.js
が受け口になっていて実処理はscraping.js
にやらせようと思います。
constapp=require('express')()constscraping=require('./scraping')app.get('/get_image',async(req,res)=>{constimage=awaitscraping.getImage()res.send(image)})module.exports={path:'/api',handler:app}
こちらは/api/get_image
にアクセスがあったらscraping.js
のget_image()
メソッドを呼び出すようにしてます。
constpuppeteer=require('puppeteer')asyncfunctiongetImage(){constbrowser=awaitpuppeteer.launch({args:['--no-sandbox','--disable-dev-shm-usage']})constpage=awaitbrowser.newPage()awaitpage.goto("https://toribure.herokuapp.com/")constimage=awaitpage.evaluate(()=>{returndocument.getElementsByTagName("main")[0].getElementsByTagName("img")[0].src})returnimage}module.exports={getImage}
ほぼpuppeteer公式のREADMEに則ってます。page.evaluate
を使うことで要素を取得したり操作したりできるんですね。
今回のスクレイピング先(https://toribure.herokuapp.com/)のHTML構造をDeveloper toolなどで見ると分かる通り、全体で1つしかないmain
要素配下に1つしかないimg
要素がターゲットとしてる鳥さんの画像です。(汚い構造してますがご愛嬌です)
そこまでわかれば通常のjsと同じように要素を取得するだけです。
ここまででAPIサイドはコーディング終了です。
フロントはさっくりと
もう疲れてきたのでフロントはボタン押したら画像表示されるくらいで。
<template><div><button@click="showBird">Scraping!!</button><br><imgv-if="src":src="src"></div></template><script>exportdefault{data(){return{src:""}},methods:{asyncshowBird(){this.src=awaitthis.$axios.$get("/api/get_image")}}}</script>
完成!!
動作確認
かわいい鳥が出てきました♪
さいごに
ここまでできれば、あとはDOM操作の世界なので、対象のページの構造を理解してjsを書けば何でもスクレイピングできますね。
スクレイピングは禁止しているサイトもあるのでその点は注意しながらいろんなアイデアを実現できればいいですね!