はじめに
あるサイトから画像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