Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

概要

  • 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してください。

以上

junara
10年間医療の研究していたが、Webサービス作りたくて、エンジニアへ。 Rails, Javascritptのエンジニアとして働きながら、生命科学学会検索サービスを作りました。 https://www.dokode.work
bldt
「つくる、はたらく、おもしろい」をキャッチフレーズに、自社事業やシステム開発サービスを提供しています
https://bldt.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした