3
0

More than 3 years have passed since last update.

【Ruby・S3】画像 URL にアクセスし aws-sdk-s3 を使って S3 に画像を保存する

Last updated at Posted at 2020-04-24

はじめに

あるサイトから画像URLを収集してきてDBに保存し、画像ファイルをS3に送り、S3のパスをDBに保存すると言う作業をしたので、その時のメモです。

  • 環境
    • OS: Mac
    • 言語: Ruby
    • 使用 gem: open-uri, activerecord, aws-sdk-s
    • DB: MySQL

概要

1. まず画像 URL を収集して保存した DB を用意

以下のような感じです。今回はテーブル名は images としておきます。
Ruby でスクレイピングを行って集めました。

id image_url s3_path
1 http://~~~~~ NULL
2 http://***** NULL
3 http://[[[[[ NULL

2. DBの画像URLにアクセスし画像ファイルを読み込む

DBから画像URLを取り出して、開き、画像ファイルをフォルダに保存します。
open-uriというgemを使うと可能です。
拡張子(.jpgや.pngなど)もつけておくとわかりやすいでしょう。

3. 画像ファイルをS3にアップロードする

2で保存した画像ファイルをS3に送ります。
aws-sdk-s3というgemを使います。
以下当時のスクリプトのコピペです。

s3_uploader.rb

require 'open-uri'
require 'aws-sdk-s3'

# ActiveRecordの設定用ファイルを読み込んでいます。各自ご用意ください。
require_relative '../activerecord.rb'

# rubyでS3を扱えるようにする準備です。
s3 = Aws::S3::Resource.new(
      region: 'ap-northeast-1',
      #環境変数にAWSのアクセスキーとシークレットキーを設定しておいてください↓
      access_key_id: ENV['S3_ACCESS_KEY'], 
      secret_access_key: ENV['S3_SECRET_KEY'],
    )

# ファイルを保存するフォルダ名
folder_name = "sample_images"

# 拡張子識別メソッド
def image_type(file_path)
  File.open(file_path, "r") do |f|
    begin
      header = f.read(8)
      f.seek(-12, IO::SEEK_END)
      footer = f.read(12)
    rescue
      return ''
    end

    if header[0, 2].unpack('H*') == %w(ffd8) && footer[-2, 2].unpack('H*') == %w(ffd9)
      return '.jpg'
    elsif header[0, 3].unpack('A*') == %w(GIF) && footer[-1, 1].unpack('H*') == %w(3b)
      return '.gif'
    elsif header[0, 8].unpack('H*') == %w(89504e470d0a1a0a) && footer[-12,12].unpack('H*') == %w(0000000049454e44ae426082)
      return '.png'
    end
  end
  ''
end

#以下imagesテーブルから1個ずつレコードを取り出していく
Image.all.find_each(batch_size: 1) do |image|
  #画像URLにアクセスし、画像ファイルを読み込み
  file = open(image.image_url).read 

  #あまりに高頻度にアクセスすると迷惑なのでスリープを1秒挟みます
  sleep(1)

  #読み込んだファイルをフォルダに保存
  File.open("../#{folder_name}/#{image.id}","w"){|f| f.write(file)} 

  #拡張子を代入
  extension = image_type("../#{folder_name}/#{image.id}")

  #S3オブジェクトを作成
  obj = s3.bucket('バケット名').object("/#{image.id}#{extension}")

  #S3オブジェクトに画像ファイルをアップロード
  obj.upload_file("../#{folder_name}/#{image.id}")

  #フォルダに保存した画像ファイルはもう必要ないので削除
  File.delete("../#{folder_name}/#{image.id}")

  #S3のパスをレコードに書き込み
  image.update(s3_path: "s3://バケット名//#{folder_name}/#{image.id}#{extension}")
end

3
0
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
3
0