Go言語で YouTube Data API を叩いて概要欄を一括 Update する方法
1. やろうとしたこと
YouTube の概要欄に書かれている URL が古くなっていて、すべて更新したかった。
出来るだけカンタンに CLI で解決したいな、と思ったので、
最初は書き慣れてる Ruby にしようかと思ったが、
公式のサンプルコードが googleauth
gem を使わない古い書き方だし、
https://github.com/googleapis/google-api-ruby-client/tree/master/samples/cli も3年前の更新だしで、嫌な思いをしそうだったので途中でやめた。
数ヶ月くらい書いていなかった Golang を、腕がなまらないよう使うことにした。
2. 特に参考になったもの
- 公式のサンプルコード https://developers.google.com/youtube/v3/quickstart/go
- RubyからGoogle APIにアクセスするのは半端なくめんどくさい - Qiita
今回 client_secret.json
が必要になるのだが、その取得方法を上の記事ではわかりやすく説明してくれている。
3. どんなコードになるか
軽く書きたかったのできれいなコードでなくて申し訳ないが、おおむねこんなふうになった。
追記:その後リポジトリとして公開しました ↓
3-1. 認証部分
認証部分は公式のサンプルコードのやり方を拝借しつつ、
サンプルコードで使われている New メソッドは deprecated であったので
NewService メソッドを使うように変更をおこなった。
認証部分はおおまかに言うと、
実行ディレクトリと同じディレクトリに格納した client_secret.json
をもとに URL が発行され、
実行者はその URL に Web ブラウザでアクセス。
OAuth2 認証が終わるとトークン文字列が発行されるので、
その文字列をコンソールに貼り付けて Enter。
すると、それを元にして token.json
が作られて、以降の実行ではその token.json
が使われるようになる。
逆に言えば、別ユーザー(別チャンネル)で認証をやり直したい場合は token.json
を一度消してから
再び go run main.go
をやってあげる必要があるということだ。
3-2. Search:list でチャンネルの動画ID一覧を取得
Search:list API を使っている110行目について。
ここでは .ForMine(true)
というメソッドを使っている。
これにより、自分が管理する動画だけが対象となる。
.ChannelId("UCxxxxxxxxxxxxxxxxx")
のようにすればいいのでは?
と思われるかもしれないが、単純なチャンネル検索だとアップしたての動画や古い動画が引っかからないという罠があるので、
ForMine でおこなっている。
なお、このコードでは問題ないが、ForMine を使うには OAuth 認証でないといけなく、
youtubeService, err := youtube.NewService(context.Background(), option.WithAPIKey("AIza..."))
のようにAPIキーで初期化をおこなった場合には、権限不足で失敗するので注意。
ここで書かれているところの『非公開のユーザー情報』にあたるものの閲覧なのであろう。
3-3. Video:update で概要欄の更新
この Update の部分の情報が少なかったのが今回の記事を書いたきっかけだ。
139〜140行目を見てもらえばわかる通りに、
video.Snippet.Description の値を更新したあとで、Update メソッドの引数には
「snippet」パートを更新するよ、って宣言と Video 構造体を丸ごと渡してあげている。
至って単純なものなのだが、同じことをやっている人が見つからず、
失敗した場合にどの項目が初期化されてしまうかが恐ろしかったので、
新たにチャンネルを作って数秒のスクリーンレコーディングの動画をアップするなどしていた。
4. 問題点
Update 処理は Quota の消費が激しく、Quota を 50以上消費する。
https://developers.google.com/youtube/v3/getting-started?hl=ja#quota
1日の Quota の制限は申請を出していない限り 10,000 なので、
(たいていの人は大丈夫だが)200件以上の動画をすでに投稿している場合、1日で処理を追えることが出来ない。
まあ、最新の動画から順次変えていけば充分だと思うので大きな問題ではないが、
動画数が多い人は大変だなぁ……という印象を受けた。
Quota の上限アップの申請もっとカンタンにしてほしい。システム仕様書を提出しないといけないとか大変すぎ……。
それか、投稿動画で共通のテンプレートを概要欄に設定できれば、
こんな地道な書き換えも発生しないのになー。
がんばれYouTube! その機能が欲しいYouTuberさんは多いと思うぞ!!
3文字マーケティング用語辞典
Webマーケの人と話すときに、何度聞いても「その言葉ってどういう意味でしたっけ?」と聞いている自分が嫌になってきたので、
覚えるのが苦手な3文字言葉のまとめ。時々3文字じゃないのもある。
自分が覚えていない、もしくは突然アルファベットで言われると思い出せないものをまとめたので、
CVR など、自分がすぐに思い出せる単語は載せていません。
ABCDEFGHI
ASO - アプリストアオプティマイゼーション
意味:SEOのアプリストア版。iOS の App Store や Android の Play Store で、検索に引っかかりやすかったり上位に来たりするために巡らす施策のこと
用例:「検索に引っかかりやすい言葉をアプリ名に入れるのはASO対策のひとつだったが、今ではアプリ名は30文字以内という制限がかかってしまった」
ARPU - アベレージレベニューパーユーザー
読み:アープ
意味:売り上げ ÷ ユーザー数。1ユーザーにどれだけのお金を使わせているか
用例:「無料プランで利用できる機能が多すぎて、ユーザー数は増えたがARPUが上がらない。有料プランに目を惹く機能を追加するか、無料プランの使用できる機能を制限するか迷いどころだ……」
ARPPU - アベレージレベニューパーペイドユーザー
意味:売り上げ ÷ 課金ユーザー数。課金ユーザーがどれだけお金を出してくれているか
用例:「ソシャゲは射幸心を煽るガチャでARPPUを上げていくのが大事。とは言え、あからさますぎると無課金ユーザーが離れてMAU(月間アクティブユーザー)・DAU(日間アクティブユーザー)が落ち込んで、サービスが盛り下がり、最終的には課金ユーザーも離れてしまう」
CPA - コストパーアクイジション (Acquisition)
意味:広告費用 ÷ コンバージョン。顧客獲得単価
用例:「CPAがマーケで予定していた目標より大きく上回ってしまい、今回のプロモーションは大失敗だ」
CPC - コストパークリック
意味:1クリックのコンバージョンを得るためにかけている費用
用例:「Google AdWords は基本的にディスプレイ広告は見られていない、という前提のもと、上限CPCを設定して、クリックに応じて Google へ報酬を支払う仕組みだ」
CPM - コストパーミル (Mille)
意味:広告1000回の表示にかかる費用。mille はラテン語で「1000」
用例:「CTR(クリック率)が 1%、CPCが300円なので、CPMに見立てると、1000回のビューで10クリックとなるので、3000円が費用(=CPM)となっている計算だ。このCPMをeCPM(effective Cost Per Mille)とも言う」
JKLMNOPQR
KGI - キーゴールインディケーター
意味:最終目標に対しての進捗。例としては、最終目標「上半期の営業売上2000万円」という数値に対して、毎週の営業売上がいくらか、というのがKGI。
最終目標に到達するための重要な目標として分解されたものが、KPI(キーパフォーマンスインディケーター)として設定される。例えば「顧客アポイントメント数500件」「新規顧客獲得数200人」といった重要目標を設定し、その数値目標に対する毎週の進捗度合いが KPI となる。
用例:「達成できなかったKPIはいくらかあるが、大口案件の獲得に成功しKGIは達成できたため、社長はご満悦だ」
LTV - ライフタイムバリュー
意味:会員が退会するまでに払ってくれるお金
用例:「弊社は6ヵ月で英語を完璧にするというパッケージモデルだから、Netflix などとは異なり、会員費の値上げをしないことにはLTVを高めづらいという特徴がある」
ROI - リターンオンインベストメント
意味:利益 ÷ 広告費用。マーケティング施策がすぐに効いてくるわけでもないので、これの数値を追うというよりは、「投資に対するリターンの大きさ=ROI」という言葉の定義だけ覚えておくのが良さそう
用例:「広告予算を会社から出してもらうぶん、ROIを高めることは常に意識しないといけない」
STUVWXYZ
SEM - サーチエンジンマーケティング
意味:SEO(サーチエンジンのための最適化)をおこないサイト流入を増やすマーケ施策
用例:
「このたびSEMのプロフェッショナルとして田中さんに参画してもらうことになりました」 「どうも、業務委託の田中です。現状のCPC(1クリックを得るのにかかっている費用)をざっくり計算したんですが、他社と比較すると広告予算を浪費しすぎている印象がありました。リスティング広告に関してはよりユーザーフィットの強く、かつ穴場のワードを狙うことで、CPM(広告1000回の表示に必要な費用)を下げつつCTR(クリック率)を高められるのではと考えています」
TOFU - トップオブファネル
意味:潜在顧客層。購買意欲が上がっていくに連れ、MOFU(Middle)、BOFU(Bottom)と呼び方が変わる。雲の上にいる神様(お客様)がだんだんと地上の商品に近付いていくさまをイメージすると、Top→Middle→Bottomの順を覚えやすい。
ファネルは「漏斗(ろうと)」のこと。参照: https://www.leadplus.net/blog/marketing-funnel.html
用例:「TOFUに対して商品の良さをわかりやすく伝えるために、LPO(ランディングページの最適化)をおこないCVR(サイトを訪れた人の会員登録率)を上げる必要がある」
Upselling - アップセリング(アップセル)
意味:より高いプランを勧めて買ってもらうこと
用例:「アップセルなりクロスセル(他の商品も買ってもらうこと)なりを狙ってARPU(1ユーザーあたりから得られる売り上げ)を上げていくためにも、まずは現在の1プランしかない状況からは脱却したほうがいい」
UU - ユニークユーザー
意味:ユニークユーザー。UUって言われるとわからなくなりがち
用例:「30,000PV(ページビュー=閲覧数)達成したのはいいとして、その中でUUはどのくらい増えてるの?」
参考文献
jQuery の ajax の書き方を Pure JS の fetch で書き直す
最近(遅いんですけど) querySelector メソッド知ったんですよ。
今までは、jQuery を使わない JavaScript だと
getElementById
か getElementsByClassName
使ってじゃないと DOM 要素を取れないと思っていたので、
jQuery はその点強いよな〜と思っていたんですが、jQuery 使わなくてもいけるぞ、と。
const inputElement = $('input[name="user_name"]');
じゃなくて
const inputElement = document.querySelector('input[name="user_name"]');
のように書けるわけですね。
Internet Explorer 8 にも対応してるそうですから、私が知らないだけで、昔からあったのでしょうね。
で、思ったのがよくある jQuery のファイルを素の JavaScript で書いたら?という話。*1
やってみた
APIサーバーを用意して、JSFiddle で書いてみました。
- jQuery を使ったもの: https://jsfiddle.net/nekonenene/pbszvtk3/
- 素のJavaScriptで書いたもの: https://jsfiddle.net/nekonenene/cpq965j4/
ポイント1: DOMContentLoaded
jQuery
$(function () { });
JavaScript
document.addEventListener('DOMContentLoaded', () => { });
load に対するイベントリスナーを昔は書いてたけど DOMContentLoaded でいいらしい。
参考: DOMContentLoadedイベントとloadイベントの違い[タイミング]
DOMツリーが読み込めた段階で発火して普通は影響ないもんな、なるほどね。
そもそも最近の主流通り、JavaScript ファイルを HTML の head タグ内で読み込まず、
body タグ内の最後で読み込んでいるならこのイベントリスナー必要ないんだけど、
まあ、 jQuery 使ってるような昔ながらのサイトなら head 内で JS を読み込んでるでしょう? ということで。
ポイント2: querySelector
jQuery
$('#displayListButton').click(function() { $('#debug').html('Show Items ボタンが押されたよ'); });
JavaScript
document.querySelector('#displayListButton').addEventListener('click', () => { document.querySelector('#debug').innerHTML = 'Show Items ボタンが押されたよ'; });
最初に話した querySelector 。
いや〜、やっぱ jQuery の方がスッキリは書けますね。
あと、アロー関数( () => {
の部分)を使っているけれど、
これは Internet Explorer だと動かないので、Internet Explorer にも対応させる場合はこうです。
document.querySelector('#displayListButton').addEventListener('click', function() { document.querySelector('#debug').innerHTML = 'Show Items ボタンが押されたよ'; });
ポイント3: fetch
jQuery
$.ajax({ method: 'POST', url: 'https://example.com/api/third-power', data: { number: 22 }, }) .done(function(data) { $('#output').html(data.result); }) .fail(function(error) { console.error(error); });
JavaScript
fetch('https://example.com/api/third-power', { method: 'POST', body: JSON.stringify({ number: 18 }), headers: { 'Content-Type': 'application/json' }, }) .then(res => res.json()) .then(jsonData => { document.querySelector('#output').innerHTML = jsonData.result; }) .catch(error => { console.error(error); });
Internet Explorer 以外では動く fetch メソッドは超便利。
モダンな JavaScript なら、fetch と、Promise によるメソッドチェーンで普通に jQuery っぽく楽に書けるようになってていいですね。
Internet Explorer でも動かしたい場合は、XMLHttpRequests のラッパーである
axios というライブラリを使えばいいと思います。
Vue.js さわってる人たちの中ではおなじみのライブラリですね。
というわけで
jQuery オワコン言われながらも、
Bootstrap だとデフォルトで jQuery 読み込んでるし、つい便利メソッドあるから使っちゃうな〜、
って状態だったんですが、特によく使う便利メソッドの代替が存在していたのでまとめました。
Bootstrap 5 では jQuery 依存から脱却しますし、
今のうちにできれば jQuery 依存のコードを書かないようにしておきたい思いです。
*1:素のJavaScript: jQueryやKnockoutJSなどのラッパーライブラリを使わないで書くJavaScript