Perl で Google Sheet API をつかってタイトルを変更する
なんか、適当に文言を入れ替えて自動生成したみたいなタイトルになってきたなぁ・・・
それはそれとして、Google Drive API に引き続き、Google Sheet API を使ってホゲホゲするってやつです。
以前、モジュールを使ってやってみたんですが、せっかく Web API 投げる方法もわかったことだし、この方法でやってみよう!ってことで。
使う都度 Any::Moose の警告が出るのが気に食わないってのもあります。
Google Sheet API の許可とアクセストークン が必要です
かつての記事で書いてます・・・なんか、遠い昔の気がする
タイトルを変更する
まずはジャブから・・・早速、公式のリファレンスを確認します。
おぉ、わかりやすい。もっと他の言語での実装例を参考にして回るかと思ってた。あっさり。
リファレンスにあるリクエストボディ は json にしておく必要があります。
これは先のページには書いてないんですが、正しい構造のJSON 送らないとエラーで「まともな JSON で送って〜」と言われます。
今回は好みで HTTP::Tiny 使いました。
リクエストボディを設定するときは公式リファレンスの \%options
のところで content
をキーにする必要があるので注意です。
エラーメッセージを見て直しつつ完成したのが以下スクリプトです。
#!/usr/bin/env perl use strict; use warnings; use HTTP::Tiny; use JSON; use URI; use utf8; my $SPREADSHEET_ID = '1sVNSpvtWPPkv5Qnb0tifYHpKMxaehxj5ChAeQ1G1kgA'; my $ACCESS_TOKEN = ''; my $GOOGLE_SHEET_API = "https://sheets.googleapis.com/v4/spreadsheets/"; my $bearer = join " ", ( 'Bearer', $ACCESS_TOKEN ); my $ht = HTTP::Tiny->new( default_headers => { Authorization => $bearer, } ); my $url = URI->new( join "", ( $GOOGLE_SHEET_API . $SPREADSHEET_ID . ':batchUpdate' ) ); my $response = $ht->request( 'POST', $url, { content => encode_json { requests => [ { updateSpreadsheetProperties => { properties => { title => "Perl から API 叩いて変更したタイトル" }, fields => "title" } } ] } }, ); print $response->{status} . "\n"; print $response->{reason} . "\n";
ちなみに、タイトルを変えても更新日は変わらない模様。
Perl で Slack API を使ってユーザー一覧を取得する(追記あり)
Slack のユーザー一覧を取得せよ!
ってなお仕事が降ってきたものの、Slack のメニューとか探したど見当たらず。
これは API 使えってことなのかなぁ・・・使うんはいいけど、普通の非テックな会社だと厳しいんでは。
もっと高い料金プランだと出てくるのかな?
それとも、非テックでも Slack 使うような会社ならそれくらいいけるんだろうか。
API を使うそのまえに
ってわけで、いつも通り Perl でやります・・・が、やる前に API を利用できるようにする準備から。
こちらの記事が大変役に立つというか、そのまま進んでそのまま OAuth Token を入手することができました。
ありがたい。
WebService::Slack::WebApi
あとは、Perl の便利モジュールがうまいことやってくれます。
#!/usr/bin/env perl use strict; use warnings; binmode STDOUT, ":utf8"; use WebService::Slack::WebApi; my $ACCESS_TOKEN = 'xoxp-hogehogefugafuga'; my $slack = WebService::Slack::WebApi->new( token => $ACCESS_TOKEN ); my $users = $slack->users->list; # $users の中にユーザーの情報が入っているので、 # とりたい情報が気になる人は Data::Dumper で中を覗いてみる for my $member ( @{ $users->{members} } ) { # 削除済みユーザーや、bot も含まれているので除外する next if ( $member->{deleted} == 1 ) || ( $member->{is_bot} == 1 ); print "$member->{name}\t$member->{profile}->{display_name}\n"; }
あっさり。
2020-11-20 追記
依頼主もメンバー一覧とるのに API しかなさそうー、って言ってはいたんですが、slack のワークスペースの管理者であれば、確認方法があることを教えていただきました。
そりゃあるよなぁ!(テノヒラクルー
突然すみません。キーワード見てて見かけました。ワークスペースの管理者であれば、メンバーの管理画面から CSV 形式でユーザー一覧をダウンロードできますよー。あとはエクスポート機能の出力ファイルの中にも users.json というのが含まれます。
— Kazuhiro Sera (瀬良) (@seratch_ja) 2020年11月19日
ありがとうございます・・・って、bio 見たらこの方、slack のAPI SDK 作っておられるのですね・・・助かりました。
画面左上のワークスペース -> 設定と管理 -> メンバーを管理する、から確認することができました。
Perl で Google Drive API をつかって特定のファイルを削除する
ファイルの上書き終わったところでこのシリーズ(シリーズ?)終わらせようと思っておりました。
しかし CRAD:Create, Read, Add, Delete の一角たる Delete やらないっていうのはないんじゃないか?
どうせ後で必要になりそうだし・・・あぁ、でも面倒〜。
ってことでやりました。
うおお、DELETE メソッド初めて使う気がする。そして応答で返ってきた status code 204 も初めてみた。 / Files: delete | Google Drive API | Google Developers https://t.co/YehnNs0o2D
— sironekotoro (@sironekotoro) 2020年11月13日
いざ手をつけるとすぐでしたが、普段は色々なモジュールの裏に隠れている HTTP の DELETE メソッドを明示的に初めて使ったように思います。
情報処理試験の教本や問題集でしか見たことのなかった(そして問題には出そうにない) DELETE メソッド、本当にあって本当に使えるんや・・・という謎の感動がちょっとあります。
そして、削除が成功した時の HTTP ステータスコード 204 これも初見でした。
削除したら応答も何もないよねというのわかる。
はー!これで CRAD 全部揃ったーはずー!!
・・・しかし、なんか my
宣言が並んでてアレな感じのコードですね・・・
#!/usr/bin/env perl use strict; use warnings; binmode STDOUT, ":utf8"; use URI; use HTTP::Tiny; my $ACCESS_TOKEN = ""; my $GOOGLE_DRIVE_API = "https://www.googleapis.com/drive/v3/files/"; my $delete_fileid = "1SNmgEpX2xnFCbeRQWtGg4PdU0ic6h92IO-VuynVGli8"; my $bearer = join ' ', ( 'Bearer', $ACCESS_TOKEN ); my $uri = URI->new( $GOOGLE_DRIVE_API . $delete_fileid ); my $ht = HTTP::Tiny->new( default_headers => { Authorization => $bearer } ); my $response = $ht->delete($uri); print $response->{status} . "\n"; # 204
Perl入学式 オンライン 2020 第2回お疲れ様でした
受講された方、サポーターの方、お疲れ様でした。 講師をやったジャージの人です。
講義に利用したスライド・動画類は以下 Perl 入学式の公式サイトで公開しています。参加された方も、参加できなかった方も、ぜひ復習に使ってください。
また、復習問題を用意しています。
四則演算、文字列連結の問題にチャレンジしてみてください。私の回答例もこちらおいておきます。
問題の意味がわからない、とか、このような解答例はどうだろう?という方は Discord のPerl入学式チャンネル(招待コード)や、twitterでハッシュタグ #Perl入学式 をつけて聞いてみてください。
Perl入学式 オンライン 2020 第2回
今回は「四則演算」「文字列連結」「コマンドライン引数」を学習しました。次回は条件分岐、IF 文からとなります。
IF 文は変数に続くプログラミング独特、プログラミングらしい学習内容です。おたのしみに!
もちろん、待ち切れない方は資料やスライドツールから先に学習を進めていただいて大丈夫です。その上で、不明な点があれば Discord や twitter で聞いてください。
コマンドライン引数
昨年までの Perl 入学式 ではコマンドライン引数ではなく、標準入力を学習していました。
標準入力はコマンドライン引数と同様に、プログラムの外部から入力を与え、プログラムの挙動や表示を変える方法の一つです。
「コマンドライン引数」と「標準入力」、何が違うかというと、入力を行うタイミングです。
コマンドライン引数:実行前にあらかじめ引数という形で入力を与えておく。
標準入力:プログラムの実行中に、入力する。対話型のプログラムを作ることができる。
標準入力に興味のある方は昨年度のカリキュラムを見てみてください。
なお、Wandbox で標準入力の問題を実行してみる場合、対話型のプログラムとはならず、コマンドライン引数と同じような形であらかじめ入力しておく、という形になります。
標準入力の入力欄はコマンドライン引数のものとは異なります。
コードを書いているエディタ欄の下に Stdin というリンクがあります。このリンクをクリックして開くところにあらかじめ入力しておきます
・・・あらかじめ?
となると、Wandbox 上ではコマンドライン引数と同じ様な感じだよなぁ、ってことで、Wandbox を使った学習ではコマンドライン引数に変更しました。
以下に Wandbox で標準入力を使った場合のサンプルを置いておきます。
コマンドライン引数の実例
自作のツールでコマンドライン引数を使っています。
最初の引数に銀行名、次の引数に支店名を入力すると、その条件に該当する銀行コードと支店コードを表示してくれます。
もし、コマンドライン引数がないと、検索する都度、コードの一部を書き換えてから実行という手順になります。
それは面倒ですよね。
こういう時、コマンドライン引数でちゃちゃっと条件を変えて実行結果を変えていけると、とても楽です。
第3回の開催について
次回は12月を予定しています。年末にかからないところ、初旬から中旬での開催を予定しています。
次回の参加、お待ちしております!
Perl で Google Drive API をつかってフォルダーを作成する
はい、慣れてきました。
API の URL と mimeType 以外はそのまんまです。
my $GOOGLE_DRIVE_API = "https://www.googleapis.com/upload/drive/v3/files?create"; # (中略) `mimeType => 'application/vnd.google-apps.folder',`
To create a folder, use the files.create method with the application/vnd.google-apps.folder MIME type and a title.
(DeepL翻訳)フォルダを作成するには、files.create メソッドを使用して、application/vnd.google-apps.folder MIME タイプとタイトルを指定します。
#!/usr/bin/env perl use strict; use warnings; binmode STDOUT, ":utf8"; use HTTP::Request::Common; use JSON qw/encode_json/; use LWP::UserAgent; my $GOOGLE_DRIVE_API = "https://www.googleapis.com/upload/drive/v3/files?create"; my $ACCESS_TOKEN = ""; my $bearer = join ' ', ('Bearer', $ACCESS_TOKEN); my $ua = LWP::UserAgent->new; my $res = $ua->request( POST $GOOGLE_DRIVE_API, 'Content-Type' => 'multipart/form-data', Authorization => $bearer, Content => [ metadata => [ undef, undef, 'Content-Type' => 'application/json;charset=UTF-8', 'Content' => encode_json( { name => 'create_folder_test', mimeType => 'application/vnd.google-apps.folder', parents => ['10kCqEUmWsWlqMdP_vF9pDGrQXFVZ-Lvr'], }, ), ], ], ); print $res->code . "\n"; print $res->content . "\n"; # 200 # { # "kind": "drive#file", # "id": "1cJ1jQOQ9KAqxVPJwIWNhGuXH1BBA9k2M", # "name": "create_folder_test", # "mimeType": "application/vnd.google-apps.folder" # }
Perl で Google Drive API をつかって特定のファイルを更新する
特定のファイルを更新する
ちょっと前、ファイルを Google Drive にアップロードした時は、同名のファイルがある場合でもアップロードが可能でした。
・・・可能でした、っていうか完全に不意打ちでしたが・・・
しかし、ファイルを更新したい時はどうすれば良いのでしょう?ってわけで、やりました。人生で初めて PATCH メソッド使いました。
URI のパラメータにファイル ID を利用していますが、だいたいはアップロードの時と同じ感じですね。
$target_fileid
で指定したファイルが更新されます。metadata の値を変えることで、ファイル名やmimeType を更新することも可能です。
#!/usr/bin/env perl use strict; use warnings; use HTTP::Request::Common; use JSON qw/encode_json/; use LWP::UserAgent; use URI::QueryParam; use URI; my $target_fileid = '1dZU7-4d52U2pRWsmMLhMEuh8Cpa0m8sI'; my $GOOGLE_DRIVE_UPLOAD_API = "https://www.googleapis.com/upload/drive/v3/files/"; my $ACCESS_TOKEN = ""; my $bearer = join ' ', ( 'Bearer', $ACCESS_TOKEN ); my $URI = URI->new( $GOOGLE_DRIVE_UPLOAD_API . $target_fileid ); $URI->query_param( uploadType => 'multipart' ); my $ua = LWP::UserAgent->new; my $res = $ua->request( PATCH $URI, 'Content-Type' => 'multipart/form-data', Authorization => $bearer, Content => [ metadata => [ undef, undef, 'Content-Type' => 'application/json;charset=UTF-8', 'Content' => encode_json( { # name => 'hogefuga.txt', # mimeType => 'plain/text', # parents => ['10kCqEUmWsWlqMdP_vF9pDGrQXFVZ-Lvr'], # id => $target_fileid, }, ), ], file => ["./hoge.txt"], ], ); print $res->code . "\n"; print $res->content . "\n"; # 200 # { # "kind": "drive#file", # "id": "19f2RrocH4I3Mdig0LkmNPghJDZnmq35f", # "name": "hoge.txt", # "mimeType": "plain/text" # }
Perl で Google Drive API をつかって特定フォルダ配下のファイル一覧を取得する
特定のフォルダ配下にあるファイル一覧を表示する
こちらは GET アクセスなので簡単だろう〜・・・とナメてかかって、割と引っかかりました。
url でパラメータを組み立てる時に 2 回 URL エンコードしてしまったというもの。
Google Drive API v3 で特定のフォルダ配下にあるファイルを引っ掛けるってのやってて、フォルダの中に一つしかファイルがないのに複数引っかかって???ってなってた。$uri->query_param( 'q' => "'$folder_id' in parents" );
— sironekotoro (@sironekotoro) 2020年11月11日ほんで、ググって見つけた C# のコード参考にしてみたら検索結果が1つだけと望んだ結果になった。$uri->query_param( 'q' => "'$folder_id' in parents and trashed = false" );
— sironekotoro (@sironekotoro) 2020年11月11日
ゴミ箱の中にあるファイルも、元どこのフォルダにあったかを記録しており、検索結果で明示的に除外する必要があると
つまり、「特定のフォルダの中にある」って条件だけじゃなくて「ゴミ箱の中にはない」とかちゃんと指定しようねというお話。まぁ、確かにね。
$folder_id
の中にあるファイル・フォルダの ID が表示されます。
#!/usr/bin/env perl use strict; use warnings; use HTTP::Tiny; use URI::QueryParam; use URI; my $ACCESS_TOKEN = ''; my $folder_id = '10kCqEUmWsWlqMdP_vF9pDGrQXFVZ-Lvr'; my $uri = URI->new('https://www.googleapis.com/drive/v3/files'); $uri->query_param( 'q' => "'$folder_id' in parents and trashed = false" ); my $bearer = join ' ', ( 'Bearer', $ACCESS_TOKEN ); my $ht = HTTP::Tiny->new( default_headers => { Authorization => $bearer } ); my $res = $ht->get($uri); print $res->{content}; # { # "kind": "drive#fileList", # "incompleteSearch": false, # "files": [ # { # "kind": "drive#file", # "id": "1dZU7-4d52U2pRWsmMLhMEuh8Cpa0m8sI", # "name": "hogefuga.txt", # "mimeType": "text/plain" # } # ] # }
query_param で組み立てている検索条件を名前での検索にする時はこんな感じ。クォーテーションの位置とかでわりと試行錯誤しました。
$uri->query_param( 'q' => "name = 'hogefuga.txt'" );
他の検索条件を使いたい人はこちら