こんにちは。セプテーニオリジナルの池田です。
直近のプロジェクトで、Google Sheets APIを使う機会があったのですが、 公式サイトにScalaのサンプルがなかったので 今回ScalaでのGoogle スプレッドシートの読み込みと書き込みについて紹介します。
目次
環境
下記の環境で動作確認を行いました。
- macOS
- Scala 2.12
- google-api-client 1.23.0
- google-oauth-client-jetty 1.23.0
- google-api-services-sheets v4-rev486-1.23.0
1.GoogleスプレッドシートAPIをオンにして、認証情報を設定
手順は公式サイトのJava Quickstartを参考をしてください。
Java Quickstart | Sheets API | Google Developers
以下リンク先の日本語訳です。
- このウィザード を使用 して、Google Developers Consoleでプロジェクトを作成または選択し、APIを自動的にオンにします。 [ 続行]、[ 資格情報に移動]の順にクリックします。
- 上のプロジェクトに資格情報を追加、ページをクリックし、キャンセルボタンを押します。
- ページの上部にある[ OAuth同意画面 ]タブを選択します。電子メールアドレスを選択し、 まだ設定されていない場合は製品名を入力し、[ 保存 ]ボタンをクリックし ます。
- [ 認証情報 ]タブを選択し、[ 認証情報の作成 ]ボタンをクリックし、[ OAuthクライアントID ]を選択します。
- アプリケーションタイプを[ その他]に選択し、[ Google Sheets API Quickstart]という名前を入力して[ 作成 ]ボタンをクリックします。
- 「OK」をクリックしてダイアログを終了します。
- クライアントIDの右側にあるfile_download(JSONのダウンロード)ボタンをクリックします。
- このファイルを作業ディレクトリに移動し、名前を変更しclient_secret.jsonます。
今回ローカル環境で実行するためAPI を呼び出す場所を『その他の非UI(cronジョブ、デーモンなど)』に指定します。
※ローカル環境ではなくアプリケーションに組み込む場合は、oauth2callbackを用意する必要があります。
ここで登録した認証情報のキー(json形式)は、getResourceAsStream
で呼び出すので、resources
配下に置いてください。
ここではclient_secret.json
という名称でresources
配下に保存します。
2.build.sbtにライブラリを追加
build.sbt
name := "GoogleSheetsAPISample" version := "1.0" scalaVersion := "2.12.0" libraryDependencies ++= Seq( "com.google.api-client" % "google-api-client" % "1.23.0", "com.google.oauth-client" % "google-oauth-client-jetty" % "1.23.0", "com.google.apis" % "google-api-services-sheets" % "v4-rev486-1.23.0" )
今回使用するライブラリはこちらです。
- GitHub - google/google-api-java-client: Google APIs Client Library for Java
- google-oauth-java-client/google-oauth-client-jetty at dev · google/google-oauth-java-client · GitHub
- com.google.api.services.sheets.v4 (Google Sheets API v4 (Rev. 491) 1.23.0)
現在Scala用のAPIClientがないのでJava用のAPIClientを使います。
3.スプレッドシート読み込みのサンプル
今回以下のスプレッドシートにデータを読み込みます。
読み込むスプレッドシートの内容
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
1 | 順位 | 都市 | 国 | 人工 | 面積(㎢) | |
2 | 1位 | 東京=横浜 | 日本 | 37,843,000 | 8,547 | |
3 | 2位 | ジャカルタ | インドネシア | 30,539,000 | 3,225 | |
4 | 3位 | デリー | インド | 24,998,000 | 2,072 | |
5 | 4位 | マニラ | フィリピン | 24,123,000 | 1,580 | |
6 |
Google Sheets APIではスプレッドシートIDと対象のシートの情報が必要になります。スプレッドシートIDはスプレッドシートを開いているURLに記載されています。
URL:https://docs.google.com/spreadsheets/d/スプレッドシートID/edit
それでは、Quickstartというクラスを作成します。
- Quickstart.scala
import java.io.{File, IOException, InputStreamReader} import java.util import com.google.api.client.auth.oauth2.Credential import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver import com.google.api.client.googleapis.auth.oauth2.{GoogleAuthorizationCodeFlow, GoogleClientSecrets} import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport import com.google.api.client.json.jackson2.JacksonFactory import com.google.api.client.util.store.FileDataStoreFactory import com.google.api.services.sheets.v4.{Sheets, SheetsScopes} import scala.collection.JavaConverters._ object Quickstart { private val applicationName = "Google Sheets API Scala Quickstart" // ローカル環境で実行する場合、user.home配下に.credentials/sheets.googleapis.com-scala-quickstartのディレクトリを用意してください private val dataStoreDir = new File(System.getProperty("user.home"), ".credentials/sheets.googleapis.com-scala-quickstart") private val dataStoreFactory = new FileDataStoreFactory(dataStoreDir) private val jsonFactory = JacksonFactory.getDefaultInstance private val httpTransport = GoogleNetHttpTransport.newTrustedTransport() /** アプリケーションに必要な権限のスコープ。アプリケーション実行後、 * スコープを変更する際には,dataStoreDirのcredentialsを削除する必要がある。 */ private val scopes = util.Arrays.asList(SheetsScopes.SPREADSHEETS) /** 認証されたクレデンシャルを作成 */ @throws[IOException] private def authorize: Credential = { //resourcesディレクトリ配下に認証情報のキー(client_secret.json)を置く val in = classOf[Nothing] getResourceAsStream "/client_secret.json" val clientSecrets = GoogleClientSecrets.load(jsonFactory, new InputStreamReader(in)) val flow = new GoogleAuthorizationCodeFlow.Builder( httpTransport, jsonFactory, clientSecrets, scopes ).setDataStoreFactory(dataStoreFactory).setAccessType("offline").build new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver).authorize("user") } /** * APIクライアントサービスをビルドする */ @throws[IOException] private def getSheetsService: Sheets = { val credential = authorize new Sheets.Builder(httpTransport, jsonFactory, credential).setApplicationName(applicationName).build } @throws[IOException] def main(args: Array[String]): Unit = { val service = getSheetsService val spreadsheetId: String = "スプレッドシートIDを指定" //rangeはシート名とセルの範囲を指定します。 val range = "シート1!A1:E" val response = service.spreadsheets.values.get(spreadsheetId, range).execute val values = response.getValues //javaのList型で返ってくるので、scala のコレクションに変換します。 for {row <- values.asScala columnA = row.get(0) columnB = row.get(1) columnC = row.get(2) columnD = row.get(3) columnE = row.get(4) } yield { println(s"$columnA $columnB $columnC $columnD $columnE") } } }
実行結果
順位 都市 国 人工 面積(㎢) 1位 東京=横浜 日本 37,843,000 8,547 2位 ジャカルタ インドネシア 30,539,000 3,225 3位 デリー インド 24,998,000 2,072 4位 マニラ フィリピン 24,123,000 1,580
上記のような読み込みができました。
またシートの最終列のcellに値が入っていない場合、row
をget
すると IndexOutOfBoundsException
が返ってきますのでご注意ください。
4.スプレッドシート書き込みのサンプル
F列に人口密度のカラム行を追加したいと思います。
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
1 | 順位 | 都市 | 国 | 人工 | 面積(㎢) | |
2 | 1位 | 東京=横浜 | 日本 | 37,843,000 | 8,547 | |
3 | 2位 | ジャカルタ | インドネシア | 30,539,000 | 3,225 | |
4 | 3位 | デリー | インド | 24,998,000 | 2,072 | |
5 | 4位 | マニラ | フィリピン | 24,123,000 | 1,580 | |
6 |
先ほどの読み込みのサンプルに必要なimport文を追記し、main関数を書き換えます。
import com.google.api.services.sheets.v4.model.ValueRange ・・・ @throws[IOException] def main(args: Array[String]): Unit = { val service = getSheetsService //書き込む対象のセルの範囲 val targetCell = "F1:F5" //rangeにはシート名と書き込むセルを指定 val range = s"${sheet}!${targetCell}" //JavaのList[List[Object]]に変換する必要がある val values = List( List("人口密度(人/k㎡)").asJava, List("4,400").asJava, List("9,500").asJava, List("12,100").asJava, List("15,300").asJava ).asJava val body = new ValueRange val requestBody = body.set("values", values) val request = service.spreadsheets.values .update(spreadsheetId, range, requestBody) .setValueInputOption("USER_ENTERED") request.execute }
実行後
まとめ
このように、Google Sheets APIではScalaでも手軽にgoogleシートの読み込み、書き込みができます。
注意事項として、JavaのGoogle Sheets APIを使っているので、APIから返ってくる型やリクエスト型が JavaのList型になります。そのため返ってきたデータをScalaのfor文で回したいときは Scalaのコレクションに変換する必要がありまし、リクエストをpostするときは、JavaのList型にする必要があります。
もっと手軽に実際にGoogleのAPIにリクエストしたい場合はOAuth 2.0 Playgroundを使うと良いです。
参考にしたサイト