10
6

GooglePlacesAPIで取得したデータをデータベースへ保存する

Last updated at Posted at 2023-10-06

初めに

初めまして。Jintaと申します。
個人開発をするにあたって、GooglePlacesAPIから取得したデータをデータベースに保存することがあったので、同じような状況の方のために、記録として残します。

テーブルの作成

まず、取得したデータを保存するテーブルを作成します。
GooglePlacesAPIから取得できるデータは、一部ですが記事にまとめたのでこちらをご覧ください。
Google Places APIを使用して情報を取得(Rails)

テーブルの作成(マイグレーションファイル)

2023083120000_create_shops.rb
class CreateShops < ActiveRecord::Migration[7.0]
  def change
    create_table :shops do |t|
      t.string :name, null: false #店名
      t.string :postal_code       #郵便番号
      t.string :address           #住所
      t.string :phone_number      #電話番号
      t.string :opening_hours     #営業時間
      t.string :web_site          #ウェブサイト
      t.decimal :latitude, precision: 10, scale: 7, null: false #緯度
      t.decimal :longitude, precision: 10, scale: 7, null: false #経度
      t.string :place_id, null: false #プレイスID

      t.timestamps
    end
  end
end

bin/rails db:migrate

取得したいデータの情報をcsvファイルに書き出す

情報を取得する流れとして、
取得したいショップの電話番号(国際番号)をcsvファイルにまとめる→電話番号(国際番号)からplace_idを取得する→取得したplace_idから必要な詳細情報を取得する。
なので、csvファイルに取得したいショップの電話番号を書き出します。
csvファイルは以下の通り

lib/cafe.csv
都道府県,店名,電話番号
東京,STARBUCKS RESERVE® ROASTERY TOKYO,+81 3-6417-0202

rakeタスクでデータベースへの保存処理を実行する

lib/tasks/get_cafe_shop_details.rake
require 'csv' #csvファイルを操作するライブラリの読み込み
require 'open-uri' #open-uriライブラリを読み込んでいる
API_KEY = ENV['API_KEY'] #.envに記述しているAPIキーを代入

namespace :Cafe do
  desc 'Fetch and save shop details'
  task :get_and_save_details => :environment do
    #電話番号からplace_idを取得するメソッド
    def get_place_id(phone_number)
      client = GooglePlaces::Client.new(API_KEY)
      spot = client.spots_by_query(phone_number).first
      spot.place_id if spot
    end

    #place_idから詳細情報を取得するメソッド
    def get_detail_data(shop)
      place_id = get_place_id(shop['電話番号'])

      if place_id
        #クエリーパラメータの作成
        place_detail_query = URI.encode_www_form(
          place_id: place_id,
          language: 'ja',
          key: API_KEY
        )
        #PlacesAPIのエンドポイントの作成
        place_detail_url = "https://maps.googleapis.com/maps/api/place/details/json?#{place_detail_query}"
        #APIから取得したデータをテキストデータ(JSON形式)で取得し、変数に格納
        place_detail_page = URI.open(place_detail_url).read
        #JSON形式のデータを、Rubyオブジェクトに変換
        place_detail_data = JSON.parse(place_detail_page)

        #取得したデータを保存するカラム名と同じキー名で、ハッシュ(result)に保存
        result = {}
        result[:name] = shop['店名']
        result[:postal_code] = place_detail_data['result']['address_components'].find { |c| c['types'].include?('postal_code') }&.fetch('long_name', nil)

        full_address = place_detail_data['result']['formatted_address']
        result[:address] = full_address.sub(/\A[^ ]+/, '')

        result[:phone_number] = place_detail_data['result']['formatted_phone_number']
        result[:opening_hours] = place_detail_data['result']['opening_hours']['weekday_text'].join("\n") if place_detail_data['result']['opening_hours'].present?
        result[:web_site] = place_details_data['result']['website']
        result[:latitude] = place_detail_data['result']['geometry']['location']['lat']
        result[:longitude] = place_detail_data['result']['geometry']['location']['lng']
        result[:place_id] = place_id
        result[:web_site] = place_detail_data['result']['website']

        result
      else
        puts "詳細情報が見つかりませんでした。"
        nil
      end
    end

    #csvファイルを読み込む
    csv_file = 'lib/cafe.csv'
    #csvファイルの繰り返し処理で実行しデータベースへ保存
    CSV.foreach(csv_file, headers: true) do |row|
      shop_data = get_detail_data(row)
      if shop_data
        shop = Shop.create!(shop_data)
        puts "#{row['店名']}を保存しました"
        puts "----------"
      else
        puts "#{row['店名']}の保存に失敗しました"
      end
    end
  end
end

終わりに

初めてAPIを使用したので、割と時間がかかってしまいましたが、正常に保存ができて良かったです。
個人開発で発見のあった事は、なるべく記事にしていきたいと思います。
最後までご覧いただきありがとうございました。

10
6
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
10
6