読者です 読者をやめる 読者になる 読者になる

PGに簡単なゲームのやり方を学習させる vol1 - まずはQ学習を理解する

社内勉強会用に資料つくったので、slideshareにあげた。

ただ、社内では speakerdeck の方がよいとの声が、、、関係ないけどどっちがよいんだ。

 

www.slideshare.net

Vagrant で 起動時にパスワードを聞かれる場合の対処方法 in Mac

自分のMacの環境でVagrantで起動時に以下のようにパスワードが聞かれてしまいいちいち起動の度にパスワードを入力する必要がありました。

==> default: Preparing to edit /etc/exports. Administrator privileges will be required...
Password:

以下ページで似たような質問していた人いたのでページを見てみると

askubuntu.com

macの場合は以下対応すればよいとのこと。

As of version 1.7.3, the sudoers file in OS X should have these entries: 
Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD = /sbin/nfsd restart
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -E -e /*/ d -ibak /etc/exports
%admin ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE

ようはmac上で visudo を行いファイル最後に追記(As of ... は除く)。 これでめでたくパスワードを聞かれなくなりました。

Google Spreadsheet から DBにデータ保存して参照する

Google Spreadsheet は シートに値を埋めていけば簡易DBになるんですが、多少データ量が増えてくると200万セル制限にひっかかったりして面倒なことになります。

hacknote.jp

このためDBにデータを保存しようとして、いろいろ探してみました。

Google Cloud SQL

f:id:shohu33:20160509174524j:plain

Google Cloud SQL を使えばGoogle Spreadsheetから簡単にMySQLにアクセスできるんですが、お金がかかるということで却下

JDBC  |  Apps Script  |  Google Developers

Fusion Tables

f:id:shohu33:20160509174818j:plain

Fusion Tables というDB(平たくいうとGoogleが提供している地図情報と連携できるデータベースのようなものだそうです)は無料で使えそうとのことで以下ページを参考に試してみました。

support.google.com

Googleドライブでデータベースが使えるという衝撃 | 非IT企業に勤める中年サラリーマンのIT日記

上記サイトでは select, insert は例がのっていましたが、update に関しては記載がなかったので試してみます。

Fusion Tables は上記サイトを参考に使える状態にしておきます。

Fusion Tables に update 文実行

Update する際にどうも ROWID という行番号以外は指定できないようです。 このため事前に以下のようなselect文でROWIDを取得してから

// Utilities.formatString でなぜかサーバーエラーがでるようになるため文字列連結
var sql = "SELECT ROWID FROM "
+ ファイルID + " "
+ "WHERE "
+ "AND PROJECTID = '12345' "
;
var rowid = FusionTables.Query.sql(sql).rows[0];

以下のようなUpdate文で更新する必要があります。

  • これ誰か他に良い方法が他にあれば教えてください。
var sql = "UPDATE "
+ ファイルID + " "
+ "SET value = 1 "
+ "WHERE ROWID = '12345'
;
FusionTables.Query.sql(sql); // UPDATEされるはず

Fusion Tables の1テーブルごとに最大行数ってあるの?

ドキュメントがまだ見つからない、、、

support.google.com

どこかに記載あるのだろうか。

以下記事の情報もガセネタっぽい。

productforums.google.com

Google Script Api で Webサイトスクレイピング

特定サイトページの商品金額を抜き出してgoogle spreadsheetに書き込むために、スクリプトエディタの Google Script Api で Webサイトスクレイピング やることになったのでいろいろ Google Spreadsheetと連携できるGoogle Script Api で Webサイトスクレイピングできる方法をさぐってみた

HTMLの一部分を抜き出せる

Easy data scraping with Google Apps Script in 5 minutes ~ kutil.org

これだと1ページで何箇所か金額部分だけ抜き出すときなど、苦労しそう。

正規表現でごりごりスクレイピング

GoogleAppsScriptでWebスクレイピング

正規表現マスターしてると楽なんでしょうが、DOM操作できるようなライブラリが欲しいな、と。

XML Service Service

googleが提供している XML Parserあるんですが、

XML Service Service  |  Apps Script  |  Google Developers

以下ページを見ると有効なXMLしか扱えないようで、使い勝手が悪いようです。 * 既存のHTMLベージはだいたい有効なXML形式になってないですからね、下記ページでもそのことに触れられています

stackoverflow.com

結局どの方法がいいんだ? -> Xml.parse で解析したデータに、XmlService.parse して解析する

stackoverflowでも取り上げられてました。

stackoverflow.com

Xml.parse で解析したデータに、XmlService.parse して解析すると良さそうとのこと。 Xml.parse で有効なXML形式に変えてくれるんですね。

var page = UrlFetchApp.fetch(contestURL);
var doc = Xml.parse(page, true);
var bodyHtml = doc.html.body.toXmlString();
doc = XmlService.parse(bodyHtml);
var root = doc.getRootElement();

試しに上記で実際にPGうごかしてもたら body が複数配列で取れてしまう場合もあるらしいのでその場合は

var bodyHtml = doc.html.body[1].toXmlString();

などして切り抜ける

さらにDom操作しやすくする

以下のページのソースを拝借するとDom操作しやすくなりますので、こちらも使用するとさらに使い勝手よくなります。これでしばらくいけるんじゃないか説。

yoshiyuki-hirano.hatenablog.jp

サンプル

function sample() {
  
  // dom取得
  var contestURLBase = "https://www.makuake.com/discover/projects/search/";
  var contestURL = contestURLBase + "1";
  var page = UrlFetchApp.fetch(contestURL),
      doc = Xml.parse(page, true),
      bodyHtml = doc.html.body[1].toXmlString(), // なぜかbodyが2つとれるので[1]の方のみ対象
      xmldoc = XmlService.parse(bodyHtml),
      xml   = xmldoc.getRootElement(),
      projects = getElementsByClassName(xml, 'projectBox');
  
  for (var i = 0; i < projects.length; i++) { 
    var project = projects[i];
    // タイトル取得
    var item = getElementsByTagName(project, 'h2');
      Logger.log(item[0].getValue()); 
  }
  
}

所有しているサイトの検索キーワード数を取得してGoogle Spreadsheetに値を記載する

はじめに

所有しているサイトが特定のキーワードでどれくらい検索されているかGoogle Search Consoleで調べてGoogle Spreadsheetに記載して日々計測する必要があったため、その際に行った手順を残しておきます。

f:id:shohu33:20160503135239j:plain

検索回数や表示回数を取得できる Google Search Console

Google Search Console(以前は Webmaster tool だった気がします)という以下のURLで、自分が所有しているサイトはどのようなキーワードで検索されたのか?また、そのキーワードで何回表示されて何回クリックされたなどの値が取れます。

www.google.com

以下のような感じで確認できます。

f:id:shohu33:20160503134402j:plain

こちらの値をなんとか Google Spreadsheetの方に引っ張ってきて、毎日記録させようと思います。

苦戦しながら Google OAuth2 でリフレッシュトークンなどを取得する

Google Search Console の値を取得するために、GoogleDevelopers の Search Console API(Webmaster Tools API)を使用します。

Search Analytics: query  |  Search Console API (Webmaster Tools API)  |  Google Developers

さらにAPIを使用するために、Google OAuthを利用する必要があるのですが、これがややこしい手順を踏む必要があるります。

ただ、そのややこしい手順をまとめてくれているサイトがあるので、以下ページを参考に リフレッシュトークンというやつを取ります。

qiita.com

端的にいうと、このリフレッシュトークンがないと長い間(たとえば3ヶ月など)、バッチなどでPGで自動実行してGoogle Search Consoleの値を取得することができなくなってしまいます。

詳しいトークンの説明は以下に譲ります

murashun.jp

上記ページに細くすると以下点に注意が必要です

それではGoogle Search Consoleの値にアクセスして値を取得してみます

Googleにログインして、Google Spreasheet で新しいドキュメントファイルを作成します。

f:id:shohu33:20160503135041j:plain

[ツール] - [スクリプトエディタ] を選択して、スクリプトエディタを開きます

f:id:shohu33:20160503140600j:plain

以下のソースベースにsite_urlなどをカスタマイズして実行すると

function myFunction() {
    var opt = {
        "method" : "POST",
        "payload" : {
            "client_id" : GS_CLIENT_ID, // 取得した クライアントID
            "client_secret" : GS_CLIENT_SECRET, // 取得した クライアントシークレット
            "refresh_token" : GS_OAUTH_REFRESH_TOKEN, // 取得したリフレッシュトークン
            "grant_type" : "refresh_token"
        },
        // "muteHttpExceptions" : true
    };
    var res = UrlFetchApp.fetch("https://accounts.google.com/o/oauth2/token", opt);
    var dat = JSON.parse(res.getContentText());
    var accessToken = dat["access_token"];
  
    var filters = [];
    filters.push({
        dimension: "query",
        operator: "contains",
        expression: "酒"
    })

    var params = {
      searchType: "web",
      startDate: "2016-04-17",
      endDate: "2016-04-17",
      dimensions: ["query"],
      dimensionFilterGroups:[
        {
          filters: filters
        },
      ],
    }
        
    var opt = {
      "method" : "POST",
      "payload" :JSON.stringify(params),
      "contentType": "application/json",
      "headers" : {
          "Authorization": "Bearer " + accessToken,
      },
    };
    var site_url = "http%3A%2F%2Fexmaple.com%2F";
    var res = UrlFetchApp.fetch("https://www.googleapis.com/webmasters/v3/sites/"+ site_url +"/searchAnalytics/query", opt);
    var content = JSON.parse(res.getContentText());
    Logger.log(content);
}

ログに以下のようなjson文字列が取得することができます。

{
 "rows": [
  {
   "keys": [
    "果実酒 飲み放題"
   ],
   "clicks": 5.0,
   "impressions": 26.0,
   "ctr": 0.19230769230769232,
   "position": 4.8076923076923075
  },

最後に取得した値をGoogle Spreadsheetに記載します。 先ほどのjsonの文字列からJSON.parseなどで必要な値を取得して以下ページを参考に必要な箇所に記載していきます。

[GAS][スプレッドシート]シートに値をセットするには : 逆引きGoogle Apps Script

スクリプトを自動化する

リフレッシュトークンを取得しているので、何度も認証する必要がないため、あとは定期的にトリガーで上記のPGを実行できるようにすれば、毎日値をGoogle Spreadsheetに追記していくことが可能です。

f:id:shohu33:20160503150947j:plain f:id:shohu33:20160503150952j:plain

Google Apps Script をトリガーから関数に引数がある場合、あるオブジェクトが渡される

最近、KPIをDBやらGoogle Analytics などから値を引っ張ってきて、Google Spreadsheetに値を入れるというお仕事をしている一環で、よく Google Apps Script のトリガーを触ります。

そのトリガーから起動される関数の引数に渡される値が、手動起動の場合と トリガー起動の場合で異なってややはまったのでその挙動の違いをブログに残しておきます。

手動起動

以下のようなPGを書いて、▶️ を押して実行すると

f:id:shohu33:20160418154144j:plain

引数は undefined ということがわかります。まぁ何も引数指定していないので当たり前ですね

f:id:shohu33:20160418154218j:plain

自動起動

ただ、以下のようなトリガーを設定して実行すると

f:id:shohu33:20160418154324j:plain

以下のようなオブジェクトが入っていることがわかります。

f:id:shohu33:20160418154736j:plain

この不思議なオブジェクトは

どうも Time-driven events というやつが入っているようで、トリガー実行時に勝手に渡されるようです。

f:id:shohu33:20160418154838j:plain

ちなみにトリガー実施日時は以下のようにとれるようです。もっと良い取り方ありそうな気もしますが、、、

targetDay = new Date(event['year'] + '/' + event['month'] + '/' + event['day-of-month']);

このような挙動の違いを把握して、トリガー実行する必要があるので気をつけてトリガー実行しましょう。

様々なブラウザへのPUSH(プッシュ)通知サービス「PushAssist」

一度自分のサイトに訪問したユーザーを、再び自分のサイトを思い出してもらってまた訪問してもらいたい!アプリのように通知できたら、、、と思っている人は結構いるんじゃないかと。

そのような中、ブラウザを開いているとPUSH通知してくれるサービスが最近、どんどん登場しています。

こういったサービスを選ぶときに対応できるブラウザ、端末が多いとより多くの人に通知できるサービスを選びたいものです。いくらブラウザでPUSH通知できるといっても、ChromeではできるけどSafariではできない、といったように限られたブラウザしかできないと威力も半減ですよね。

その中でも、様々な端末に対応可能な「PushAssist」を触ってみました。

 

f:id:shohu33:20160415195806j:plain

 

対応端末

PC, Mobileそれぞれの以下ブラウザに対応しているようです。 

Chrome 42以降

f:id:shohu33:20160415200129j:plain

 

Safari 

f:id:shohu33:20160415200153j:plain

 

Firefox 44以降

f:id:shohu33:20160415200243j:plain

 

アカウントの違い

特にMobileでのブラウザPushを見てみたいので、Premiumアカウントでトライアルできないか試してみることにした。「Mobile Website Notifications」というやつ。

f:id:shohu33:20160415202211j:plain

早速アカウントを作る

アカウントを作成しようとしたら以下エラーメッセージが表示。

Japan じゃダメなのか? とりあえず、よくわからないのでなぜ会員登録できないのか問い合わせをしているので、回答待ち。

f:id:shohu33:20160415201904j:plain

とおもったら、電話番号いれてくれということらしいので、電話番号いれたところ先に進んだが、クレジットカード情報いれたくないのでSTAY。