高木のブログ

PuppeteerをRubyから操作する

2021/04/27

PuppeteerをRubyから操作できるGem(puppeteer-ruby)を見つけたのでやってみた

このブログをスクレイピングをして、タイトル5件だけ出力してみる

手順

Docker環境の準備

Dockerfile

公式でDockerで動かすサンプルが用意されていたの拝借した
Rubyバージョンだけ2.7.3に変更している

puppeteer-ruby-example/Dockerfile

Dockerfile
FROM ruby:2.7.3-alpine

WORKDIR /app

COPY Gemfile /app/Gemfile

RUN apk update \
    && apk add --no-cache --virtual build-deps \
    build-base \
    && bundle install \
    && apk del build-deps

RUN apk update \
    && apk add --no-cache \
    chromium \
    font-noto \
    fontconfig \
    && wget https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \
    && mkdir -p /usr/share/fonts/NotoSansCJKjp \
    && unzip NotoSansCJKjp-hinted.zip -d /usr/share/fonts/NotoSansCJKjp/ \
    && rm NotoSansCJKjp-hinted.zip \
    && fc-cache -fv

ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser

Gemfile

Gemfile
# frozen_string_literal: true

source 'https://rubygems.org'

gem 'puppeteer-ruby'

ビルド

$ docker build -t puppeteer_ruby_sample .

コード

app.rb
# frozen_string_literal: true

require 'puppeteer'

launch_options = {
  executable_path: ENV['PUPPETEER_EXECUTABLE_PATH'],
  args: ['--no-sandbox']
}
Puppeteer.launch(**launch_options) do |browser|
  page = browser.pages.first || browser.new_page
  page.goto('https://takagi.blog/')
  articles = page.query_selector_all('main article').take(5)
  articles.each do |article|
    date = article.query_selector('header small')['innerText'].json_value
    title = article.query_selector('a')['innerText'].json_value
    puts "#{date}: #{title}"
  end
end

実行

$ docker run --rm -it -v ${PWD}:/app puppeteer_ruby_sample ruby app.rb
2021/04/23: Docker環境でgruffのサンプルコードを動かす
2021/04/19: IOSTの価格を取得するワンライナーバッチ
2021/04/16: Ubuntu + RMagickでフォントが無くて画像の出力ができない
2021/04/13: 【Docker】コンテナ内のファイルをホストにコピーする
2021/04/09: SBI証券のポートフォリオのCSVファイルの文字コードをUTF-8に変換する

リポジトリ

ytkg/puppeteer_ruby_sample - GitHub

クラス拡張

テキストを取得するのに、['innerText'].json_valueを書くのはあまり気持ちよくないので、クラス拡張でinner_textメソッドを追加してみた
本家?(JavaScript)でもinnerTextでテキスト取得できたはず

class Puppeteer::ElementHandle
  def inner_text
    self['innerText'].json_value
  end
end
article.query_selector('header small').inner_text
#=> Docker環境でgruffのサンプルコードを動かす

Written by ytkg, Twitter, GitHub

Pixela