LoginSignup
9
7

More than 5 years have passed since last update.

Herokuのrailsアプリでheadless chromeを使ってwebページのスクリーンショットをとる

Last updated at Posted at 2018-08-05

概要

  • headless chromeを使えるdocker環境を作って
  • webページをheadless chromeでスクリーンショットをとる機能を実装して
  • herokuにデプロイした

完成品

環境

  • Rails 5.2

手順

開発環境構築

ベースとなるdocker環境はこちら DockerでRails+Webpackerの開発環境を構築するテンプレート を使って作りました。そこに、
Headless chrome の導入をこちらDockerで日本語対応のHeadless Chrome + puppeteerを立ち上げを参照しておこない、chrome driveはこちらを参照しました。docker-chromedriver/Dockerfile

コード

スクリーンショットを撮るモジュールを作る

Seleniumでスクリーンショットを撮りたいurlにnavigateして、screenshot_asでスクリーンショットを撮ります。
ちなみに、driver.quit をしないとchromeが閉じないでずーっと残るのでみるみる残存メモリが減って行きます・・・

  • include ActiveModel::Attributes を使っているのでrails 5.2必須。(参考)、attribute :height, :integer を使うと気兼ねなく数値を渡せるので便利
lib/screenshot_capture.rb
  include ActiveModel::Attributes

  attribute :url, :string
  attribute :height, :integer
  attribute :width, :integer
  • ココでpng imageを作る。
lib/screenshot_capture.rb
  def png_image
    nil unless valid?
    driver = Selenium::WebDriver.for :chrome, options: headless_chrome_options
    driver.navigate.to url
    driver.manage.window.resize_to(DESKTOP_WINDOW_WIDTH, height && width ? DESKTOP_WINDOW_WIDTH * image_height / image_width : DESKTOP_WINDOW_WIDTH)
    image = driver.screenshot_as(:png)
    driver.close
    driver.quit
    image
  end
  • chromeをheadlessで動かす設定は下記参照。
lib/screenshot_capture.rb
  def headless_chrome_options
    options = Selenium::WebDriver::Chrome::Options.new
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-gpu')
    options.add_argument('--hide-scrollbars')
    options.binary = '/app/.apt/usr/bin/google-chrome' if heroku?
    options
  end
  • 最終的に出力する画像イメージの変換はminimagickを使いました。 png_image からバイナリで書き出して、それをそのまま受け取ってイメージ変換後バイナリを出力しましす。
  def resized_image
    nil unless png_image
    image = MiniMagick::Image.read(png_image)
    image.resize "#{image_width}x#{image_height}"
    image.to_blob
  end

スクリーンショットを出力するコントローラ

スクリーンショットは /screenshot?url:ウェブページのURL&height=イメージ高さ&width=イメージ幅
のurlをGETリクエストすることで取得することができます。それを表現したのは下記のコード。

ScreenshotCaptureモジュールで作ったイメージのバイナリをそのまま、 send_data に渡すだけです。

app/controllers/home_controller.rb
class HomeController < ApplicationController
  def screenshot
    # url = URI.encode_www_form_component('https://yahoo.co.jp')
    screen_capture = ScreenshotCapture.new(screenshot_params)
    send_data screen_capture.resized_image, type: 'image/png', disposition: 'inline'
  end

  private

  def screenshot_params
    url = URI.decode_www_form_component(params[:url])
    height = params[:height]
    width = params[:width]
    { url: url, height: height, width: width }
  end
end

Heroku対応&deploy

herrokuでheadless chromeを使う設定はHerokuを使ってchromeでwebページのスクリーンショットをとるを参照してかきました。

重要なのはココoptions.binary = '/app/.apt/usr/bin/google-chrome' if heroku?。binaryの場所を指定してます。

lib/screenshot_capture.rb
  def headless_chrome_options
    options = Selenium::WebDriver::Chrome::Options.new
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-gpu')
    options.add_argument('--hide-scrollbars')
    options.binary = '/app/.apt/usr/bin/google-chrome' if heroku?
    options
  end

  def heroku?
    Rails.env.production?
  end
  • .fonts フォルダに日本語フォントをいれます。今回は、IPA ゴシックをつかっています。

  • heroku deployする前に、こちらを参考に、buildpackを追加して下さい。

あとは、herokuにdeployしてください。

以上

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7