人工知能についてのメモ②「Python環境の設定」
人工知能についてのメモ①では人工知能についてを軽く知り、それを実現するためには機械学習または深層学習が方法としてあり、いろいろな言語があるけどPythonが一番人気というところまでやりました。
今回はPythonの環境を整えて少し触るところまでです。
Anacondaのインストール
Pythonを調べていると便利便利と書いてあるのでAnacondaというものを使用していきたいと思います。
Anacondaは「Python本体と、Pythonでよく利用されるライブラリ」がまとまっているパッケージらしいです。(開発ツールみたいなものと理解しておきました)
www.anaconda.com
Anacondaのダウンロードページから私はPython 3.6 version (64bit) のインストーラーをダウンロードしました。
途中に選択やチェックボックス等ありましたが一応そのまま「Next > Next > Install」といった感じでインストーラーに従いました。
※注意:インストール途中にcmd.exeが開きますが閉じてしまうとインストールできないものが出てきたりするので放置しましょう。
対話型実行環境 Jupyter Notebook
Pythonのコードを含んだWebページを作成できる機能(つまりGitをcmd.exeでやるかSourcetreeのようなGUIツール使うかみたいなものと認識しました)
これを使って可視化しながら簡単なものからやっていきたいと思います。
インストールしたツールはAnaconda-Navigatorから開けるようです。
またJupyter Notebookの直接リンクがありますがブラウザの方が開かなかったことがあるのでAnaconda-Navigatorから手順を踏んで開いた方がよさそうです。
Jupyter Notebookを開くとJupyter NotebookのWindowとブラウザが立ち上がります。
「Documents\Python Jupyter Note」のフォルダを作りそこで作業することにしました。
- Documentsをクリックして階層を移動。
- 右上のNewをクリックし「Folder」を選びリストにUntitled Folderを追加。
- Untitled Folderをチェックし、左上に出てくるRenameを押す。
- フォルダの名前が変更できますので適宜変更してください。
エクスプローラーでフォルダを作り、再度ブラウザを開くことでもOKです。
Pythonの基礎
作業フォルダの作成
Python Jupyter Noteのブラウザで先ほど作った「Documents\Python Jupyter Note」を開きます。
右上の「New」から「Folder」を選択し、Untitled Folderを作成します。
Untitled Folderを選択して、「Rename」でHello Pythonという名前に変更します。
今回は「Documents\Python Jupyter Note\Hello Python」を作業フォルダとして利用します。
Python3の作成
右上の「New」から「Python3」を選択します。
作業フォルダにUntitled.ipynbが作成され、別のブラウザでチャットのような画面が開きます。
Hello Python
作成したUntitled.ipynbの「In [ ]:」の横の入力欄に以下のコードを打って「Shift」+「Enter」を押してください。
print('Hello Python!!')
これで入力に足して「Hello Python!!」と出力されました。
コードを入力し「Shift」+「Enter」で実行して出力という作業が、Jupyter NotebookでのPythonプログラミングの基本となります。
ちなみに一度入力した場所のコードを修正して実行することで出力結果も更新されます。
変数を用いた計算
変数を用いて計算なども可能です。
a = 12 b = 35 c = 53 a + b + c
aに12、bに35、cに53を代入してその3つを足した数、100を出力します。
ファイルの読み込み
機械学習にはデータの入力が必要です。
いちいちデータを手で入力していてはキリがないのでファイルを読み込む機能を使用します。
まずは読み込むためのファイルを作成します。
作業フォルダにて右上の「New」から「Text File」を選択します。
その後作成されたUntitled.txtをチェックして左上の「Rename」でData.csvに名前を変更します。
Data.csvを開いてcsvのコンマ区切り形式で適当にデータを作ります。
作成したファイルをUntitled.ipynbと同じフォルダに配置します。
以下のコードを実行することでファイルを読み込んで出力することができます。
import pandas as pd data = pd.read_csv('Data.csv') data
一番左の太字の0,1,2は何個目のデータかを表しており、その右側はファイルに入力したものと一致しています。
全て空白の行があった場合はスルーされます。
また、ファイルの拡張子がtxtの場合でもコンマ区切りになっていれば問題ないようです。
※しかし一般的には拡張子はcsvなので合わせた方が良いでしょう。
「import pandas as pd」はpdにpandasというデータ分析に特化したライブラリをインポートしており、そこからデータを読み込むことでエクセルやCSVデータを簡単に扱うことが可能になっています。
ファイルの保存
画面上の「Untitled」という部分を任意の名前(HelloPython)に変更し、左上の「File」の下にある保存ボタン(フロッピーディスクのアイコン)を押して完了です。
人工知能についてのメモ①「基礎知識の確認」
ほぼ個人メモなので雑です。理解していくために書き殴ります。
人工知能などに関しての技術進歩が速いので今のうちに基礎を理解しておかないとチンプンカンプンになると思ったのではじめました。(使用だけだと簡易ライブラリなどは出てきていますが...原理的な部分)
定期で何かわかったことがあれば追記したりします。
解釈の違いなど当然あると思いますのでご指摘いただけると嬉しいです。
そもそも人工知能(AI)とは
膨大なデータを元に分析して分析・判断し、検出・抽出を行う機能、仕組み。
今回のような分析・判断するAIを強いAIと呼び、
プログラムで書かれたような知能の低いAIのことを弱いAIと呼ぶそうです。
よく出てくる単語
人工知能を実現する方法
- 機械学習
機械学習を一言で表すと「明示的にプログラムしなくても学習する能力をコンピュータに与える研究分野」- 教師あり学習(Supervised Learning)
- 入力と出力の関係を学習する方法。
ラベルを提示することでそこから解釈されるアルゴリズムを生成する。
- 入力と出力の関係を学習する方法。
- 教師なし学習(Unsupervised Learning)
- 強化学習(Reinforcement Learning)
- 価値・評価を最大化するような行動を学習する方法。
人間が与えた環境を観測し、どう行動すべきかを学習する。行動によって環境に影響が出て、環境から報酬という形でフィードバックを得ることで学習アルゴリズムのガイドとする。
例として「将棋をして、より勝率の高い戦略を学習させる」などという方が個人的にはわかりやすい。
- 価値・評価を最大化するような行動を学習する方法。
- 教師あり学習(Supervised Learning)
- 深層学習(ディープラーニング)
ディープラーニングは機械学習をさらに発展させたもの。主にデータを分析する際に使う枠組みが異なっていて、人間の神経を真似て作った「ニューラルネットワーク」で、コンピューターによるデータの分析と学習を強化している。
機械学習ではデータに対して「入力と出力の関係」や「データの構造」「価値・評価を最大化する」など重点を人間が用意したのに対し、その部分もディープラーニングに学習させ判断させようとしているらしい....。(相手が何を求めているかを考えることでより人間に近くなっている!)
【Unity】WindowsPCのスクリーンをキャプチャして再生する
以下のほうが高機能で高速です。
tips.hecomi.com
しかし...GTX10XX系を搭載したゲーミングPCでは動かないそうで...??
実際、GTX1070を積んだノートで動作しなかった...
なので動作としては遅いが何となくPC画面をUnity内に描画したくてやってみました。
他に解決策があればぜひ教えていただきたいです。
ソースはこちら、サンプルをいくつか用意したのでどうぞ
github.com
実際に動かしてみるとこんな感じです。
exeでもWindowsであればもちろん動きます。
・Windows10
・Unity2017.3.1
WinデスクトップのUnityでのキャプチャ pic.twitter.com/IDOrPtB7kk
— コンソールスープ (@consolesoup) 2018年2月20日
Rendererに対してDesktopの描画 pic.twitter.com/yP1Hned9At
— コンソールスープ (@consolesoup) 2018年2月22日
Unityで背景透過のアプリケーション
— コンソールスープ (@consolesoup) 2018年2月23日
ウィジェット的な感じ pic.twitter.com/7yEk7TQkWn
【Maya】Pythonで線を描画する
MayaをPythonでいじれるということなので手始めに検証です。
今回は線を引いてみました。
import maya.cmds as cmds transform = cmds.createNode('transform', n='curve1') nurbsCurve = cmds.createNode('nurbsCurve',n='curveShape1', p=transform) cmds.curve(nurbsCurve, p=[(0, 0, 0), (3, 5, 6), (10, 12, 14), (9, 9, 9)])
- transformのcurve1を作成
- curve1を親にしてnurbsCurveのcurveShape1を作成
- curveShape1にカーブの値を設定
表示結果はこんな感じ
nurbsCurveで指定したので綺麗な曲線になるかと思ったのですがカクカクになってますね....
【GAS】WebアプリケーションでWebページを作る
GoogleAppScript(以下GAS)のWebアプリケーションの機能を使ってWebページを作ります。
GSuiteのアカウントではGSuiteメンバーのみが閲覧できるページしか作れないのでご注意ください。
通常のGoogleアカウントでは全体公開、自分のみ、Googleにログインしている人のみなど選べます。
GASの準備
過去記事を参考にGASの準備をお願いします。
madgenius.hateblo.jp
GASの記入
以下がページを表示するのに使うGASです。
- doGetが必須のメソッドで、HTMLページを読み込むのに使います
- ここではindex.htmlを読み込んで表示している
- GetTextはHTMLページから情報を引き出すためのメソッドです。
- 特定のKeyを送ることでそれに合った文字列を返します。
- 本来、ここで通信したりスプレットシートの中身を見てページの表示内容を変更する
- GetCSSではCSSの名前を送ることでそのCSSの中身を取得して返します。
function doGet() { var html = HtmlService.createTemplateFromFile("index"); return html.evaluate(); } function GetText(key) { if (key == "title") { return "私が好きなプリパラアイドル"; } else if (key == "rank1") { return "紫京院ひびき"; } else if (key == "rank2") { return "北条そふぃ"; } else if (key == "rank3") { return "東堂シオン"; } else if (key == "rank4") { return "白玉みかん"; } else if (key == "rank5") { return "み〜んなアイドル、み〜んな大好き"; } } function GetCSS(filename) { return HtmlService.createHtmlOutputFromFile(filename).getContent(); }
CSSの作成
GetCSSで取得するCSSを作成します。
「GASのファイル > 新規作成」でHTMLファイルを作成します。
ファイル名は「css.html」です。
<style> body{ font-family:Verdana,Arial; font-size:14px; } #header{ margin-bottom:15px; border-bottom: 1px solid #ccc; } #contents{ } #footer{ font-size:12px; color:#ccc; text-align:center; border-top:1px solid #ccc; padding:10px 0 20px; } h2,h3{ font-size:bold; } h2{ font-size:16px; border-left:5px solid #ccc; padding:3px 0 3px 10px; margin-bottom:10px; } h3{ border-bottom:1px solid #ccc; padding:3px 0; margin-bottom:10px; } p{ margin-bottom:14px; } </style>
HTMLの作成
CSSの時と同じ手順でindex.htmlを作成します。
- 「<head>」の中に「<?!= GetCSS('css'); ?>」とありますが、css.htmlの内容を<head>の中に追加しています。
- 「<?= GetText("title"); ?>」はGetTextメソッドから"title"という文字に紐付けられた文字を返す。
<!DOCTYPE html> <html> <head> <base target="_top"> <?!= GetCSS('css'); ?> </head> <body> <section id="header"> <h2><?= GetText("title"); ?></h2> </section> <section id="contents"> <ul class="products"> <li> 1位:<?= GetText("rank1"); ?> </li> <li> 2位:<?= GetText("rank2"); ?> </li> <li> 3位:<?= GetText("rank3"); ?> </li> <li> 4位:<?= GetText("rank4"); ?> </li> <li> 5位:<?= GetText("rank5"); ?> </li> </ul> </section> <section id="footer"> <a href="https://twitter.com/ele_enji" target="_blank">園児ニアの技術メモ</a> / <a href="https://twitter.com/ele_enji" target="_blank">@ele_enji</a> </section> </body> </html>
Webページを表示する
doGetメソッドを実行してエラーが出なければOKです。
たまにHTML内でのメソッド名などの入力ミスでエラーが出ます。
では、WebページとしてのURLアドレスを取得しましょう。
「公開 > ウェブ アプリケーションとして導入...」を選択。
ウェブアプリケーションとして導入というポップアップが出ます。
- アクセスユーザーを「自分だけ」から「全員(匿名ユーザーも含む)」にしました。
- GSuiteの場合、「全員(hogehogeのメンバー)」など最大でもグループのユーザーしかアクセスできません。
- もしアクセスしたユーザーのアカウントを使う必要がある場合は「次のユーザーとしてアプリケーションを実行」の実行ユーザーを「自分(hogehoge@hoge.com)」ではなく「ウェブアプリケーションにアクセスしているユーザー」にしましょう。
更新を押すと実際のWebサイトのアドレスが取得できます。
実際に今回作ったページがこちら
script.google.com
CSSも入れれるので結構いい感じのデザインにはできるのですが、URLの部分はGoogleAppScriptなんだなって感じなのでHPには向いてないです。
ツールサイトや、個人用として使うぶんには十分だと思います。
【GAS】電車遅延情報をツイート
GoogleAppScript(以下GAS)にて電車遅延の情報をツイートする方法です。
過去記事でGASと連携してTwitter投稿を行う記事を書いてますのでどうぞ
madgenius.hateblo.jp
今回は上の定期ツイートの内容に電車遅延の情報を追加するのみになります。
電車遅延情報を取得してツイート
鉄道遅延情報のjsonを使って電車遅延情報を取得します。
ここがもし使えなくなった場合は各種運行会社のRSSを取得したり、公式Twitterを監視するのも使えます。(RSSなど公式の方が遅延理由もあるので便利ですが今回は簡単な方で...)
以下がソースです。10分毎のタイマーをセットしています。
//10分毎に鉄道遅延情報のjsonを取得して10分以内に更新された遅延情報をツイートする function TrainDelayTweet() { var response = UrlFetchApp.fetch("https://rti-giken.jp/fhc/api/train_tetsudo/delay.json"); var result = JSON.parse(response.getContentText()); for(var i = 0; i < result.length; i++) { var company = result[i].company; //会社 if (company == "東京メトロ" || company == "都営地下鉄") { var name = result[i].name; //路線 var date = new Date(Number(result[i].lastupdate_gmt) * 1000); // 最終更新日時 var Nowymdhms = new Date(); if ((Nowymdhms.getTime()-date.getTime())/1000/60 < 10) { var ResultYear = date.getYear(); var ResultMon = date.getMonth() + 1; var ResultDay = date.getDate(); var ResultHour = date.getHours(); var ResultMin = date.getMinutes(); CS_Twitter.TwitterSend(name+"("+company+")が遅延しました。\n情報更新日時:"+ResultYear+"/"+ResultMon+"/"+ResultDay+" "+ResultHour+":"+ResultMin); } } } }
10分毎に遅延情報を取得して更新時間が10分以内だったらツイートします。(しかし、普通に10分ごとに更新とかもあるので同じ路線が何度もツイートされることもある...)
私が都内に住んでいるので「JR九州」などを出さないために運行会社でフィルターをかけています。
ここでは東京メトロと都営地下鉄のみにしています。
JR東日本で山手線などを入れたいのですがJR東日本には東北も含まれますので、「JR東日本の山手線」の時はフィルターをスルーするようにしてやればOKです。
こちらのBotは私のTwitterにて動作確認が可能です。
以下、フィルターをかけていない時のツイートですが...
湘南新宿ライン(JR東日本)が遅延しました。
— ㅤ園児エル@プリカフェ9/2.10.16 (@ele_enji) 2017年9月5日
情報更新日時:2017/9/5 10:39
【GAS】Twitterの相互じゃない人を自動で定期的にリムーブ
はじめに
Twitterをやっていると前は相互フォローだったのに片思いになってしまった人などがいると思います。
片思いというのは、自分は相手をフォローしているが相手は自分をフォローしていない状態のことです。
しかし、誰と片思いになったかどうかを確認して1人1人リムーブするのは意外と手間がかかりますよね。
かといって一括ツールを使うと公式アカウントなど片思いと知っておきながらフォローしているアカウントまで解除されてしまいます。
GoogleAppScript(以下GAS)でやれば自分の思い通りにできるのでやってみました。
一応、手順とメソッド単位での説明がありますが、最後にソースだけをまとめています。
GASとTwitterAPIの連携
過去記事でGASとTwitterAPIを連携させるライブラリを作成しています。
こちらを参考に導入までどうぞ
madgenius.hateblo.jp
フォロー、フォロワーの取得
片思いかどうかを調べるためには自分のフォローとフォロワーのリストが必要です。
フォローの取得
CS_TwitterのTwitterFollowListを使用します。
//フォローしている人のリストを作成 function GetFollowList(screen_name,user_id) { var followCursor = -1; var followList = []; while (followCursor != 0) { var follow_list = CS_Twitter.TwitterFollowList(5000,screen_name,user_id,followCursor); followCursor = 0; if (follow_list != null) { if (follow_list.errors == null) { followCursor = follow_list.next_cursor; followList = followList.concat(follow_list.ids); } else { break; } } } return followList; }
フォロワーの取得
CS_TwitterのTwitterFollowerListを使用します。
//フォロワーのリストを作成 function GetFollowerList(screen_name,user_id) { var followerCursor = -1; var followerList = []; while (followerCursor != 0) { var follower_list = CS_Twitter.TwitterFollowerList(5000,screen_name,user_id,followerCursor); followerCursor = 0; if (follower_list != null) { if (follower_list.errors == null) { followerCursor = follower_list.next_cursor; followerList = followerList.concat(follower_list.ids); } else { break; } } } return followerList; }
一応これでフォロー全件とフォロワー全件が取得できるはずです。
1回の通信で5000人分なので超有名人でもないかぎりAPI規制がかかったりすることはないはずです。
片思いのユーザーのリストを作成
片思いを判定するのにフォローとフォロワーのリスト配列の差集合を求めます。(差集合でフォローにいてフォロワーにいない人だけのリストになる)
自力でもでき、処理スピード的には変わらないですが、Underscoreというライブラリを使うことにしました。
GASの「リソース > ライブラリ」を開き、Underscoreのプロジェクトキー「1PcEHcGVC1njZd8SfXtmgQk19djwVd2GrrW1gd7U5hNk033tzi6IUvIAV」を入力して追加を押してください。
以下が片思いのリストを作るメソッドです。
引数
- followList - フォローのリスト
- followerList - フォロワーのリスト
//片思いのリストを作成 function GetUnrequitedList(followList, followerList) { var unrequitedList = []; //フォローしているのにフォロワーじゃないユーザーは解除する var _ = Underscore.load(); unrequitedList = _.difference(followList,followerList); return unrequitedList; }
user_idをscreen_nameに変更
片思いのリストを作ったのであとはリムーブするだけ....
残念、user_idでリムーブ可能と公式のTwitterAPIに書いてますがuser_idで探したけど見つからないみたいなエラーが出てほとんどリムーブできません。
なのでscreen_name(@hogehoge)に変換してあげます。
この変換の時はなぜか見つからないエラーが起きないのが救い...
CS_TwitterのTwitterUsersLookupで複数ユーザーを指定してその詳細からscreen_nameを取得します。
//user_idのリストをscreen_nameのリストに変更する function ConvertScreenNameList(userIDList) { var screenNameList = []; while (userIDList.length > 0) { var idList = []; if (userIDList.length <= 100) { idList = userIDList.slice(0); userIDList = []; } else { idList = userIDList.slice(0,100); userIDList = userIDList.slice(100); } var ids = ""; for (var i = 0; i < idList.length; i++) { var id = idList[i]; if (ids != "") { ids += ","; } ids += id; } if (ids != "") { var lockups = CS_Twitter.TwitterUsersLookup(null,ids); if (lockups == null) { break; } else { if (lockups.errors == null) { for (var i = 0; i < lockups.length; i++) { var lockup = lockups[i]; if (lockup != null) { if (lockup.screen_name != null) { screenNameList[screenNameList.length] = lockup.screen_name; } } } } else { break; } } } } return screenNameList; }
これで片思いのユーザーのscreen_nameのリストが取得できました。
「var lockup = lockups[i];」の部分でユーザーの詳細があるので特定のユーザーは片思いでも見逃してスルーするなどの処理を入れることができます。(リムーブ時にscreen_nameで判別してでも良い)
上のメソッドを利用してリムーブまで行う
こんどこそ片思いのリストが用意できたのであとはリムーブするだけです。
リムーブはを使用します。
以下が片思いを取得してリムーブするメソッドです。
このメソッドをタイマーなどで呼べば定期的にリムーブすることができます。
//片思いを解除する function UnFollow() { var user_id = "0000000000"; //フォローしているユーザーのリストを作成 var followList = GetFollowList(null,user_id); if (followList != null && followList.length > 0) { //フォロワーのリストを作成 var followerList = GetFollowerList(null,user_id); if (followerList != null && followerList.length > 0) { //片思いのリストを作成 var unrequitedList = GetUnrequitedList(followList, followerList); if (unrequitedList != null && unrequitedList.length > 0) { //user_idのリストをscreen_nameに変更 var screenNameList = ConvertScreenNameList(unrequitedList); if (screenNameList != null && screenNameList.length > 0) { //フォローを解除する for (var i = 0; i < screenNameList.length; i++) { var screen_name = screenNameList[i]; if (screen_name != null) { var unfollow = CS_Twitter.TwitterUnfollow(screen_name, null); if (unfollow == null || (unfollow != null && unfollow.errors != null)) { } } } } } } } }
全ソース
TwitterAPIの連携や通信周りをまとめたスクリプトファイル
AutoUnFollowを毎分のタイマーに設定することで毎日0時0分に片思いを解除してくれる。
Unfollow.gs
CS_Twitter.TWITTER_CONSUMER_KEY = 'CONSUMER_KEY'; CS_Twitter.TWITTER_CONSUMER_SECRET = 'CONSUMER_SECRET'; CS_Twitter.OAUTH_USER_KEY = 'Unfollow'; //片思いフォローしているユーザーへのフォローを解除する //毎日0時0分 function AutoUnFollow() { var Nowymdhms = new Date(); var NowHour = Nowymdhms.getHours(); var NowMin = Nowymdhms.getMinutes(); if (NowHour == 0 && NowMin == 0) { UnFollow(); } } //片思いを解除する function UnFollow() { var user_id = "your user id"; //フォローしているユーザーのリストを作成 var followList = GetFollowList(null,user_id); if (followList != null && followList.length > 0) { //フォロワーのリストを作成 var followerList = GetFollowerList(null,user_id); if (followerList != null && followerList.length > 0) { //片思いのリストを作成 var unrequitedList = GetUnrequitedList(followList, followerList); if (unrequitedList != null && unrequitedList.length > 0) { //user_idのリストをscreen_nameに変更 var screenNameList = ConvertScreenNameList(unrequitedList); if (screenNameList != null && screenNameList.length > 0) { //フォローを解除する for (var i = 0; i < screenNameList.length; i++) { var screen_name = screenNameList[i]; if (screen_name != null) { var unfollow = CS_Twitter.TwitterUnfollow(screen_name, null); if (unfollow == null || (unfollow != null && unfollow.errors != null)) { } } } } } } } } //user_idのリストをscreen_nameのリストに変更する function ConvertScreenNameList(userIDList) { var screenNameList = []; while (userIDList.length > 0) { var idList = []; if (userIDList.length <= 100) { idList = userIDList.slice(0); userIDList = []; } else { idList = userIDList.slice(0,100); userIDList = userIDList.slice(100); } var ids = ""; for (var i = 0; i < idList.length; i++) { var id = idList[i]; if (ids != "") { ids += ","; } ids += id; } if (ids != "") { var lockups = CS_Twitter.TwitterUsersLookup(null,ids); if (lockups == null) { break; } else { if (lockups.errors == null) { for (var i = 0; i < lockups.length; i++) { var lockup = lockups[i]; if (lockup != null) { if (lockup.screen_name != null) { screenNameList[screenNameList.length] = lockup.screen_name; } } } } else { break; } } } } return screenNameList; } //片思いのリストを作成 function GetUnrequitedList(followList, followerList) { var unrequitedList = []; //フォローしているのにフォロワーじゃないユーザーは解除する var _ = Underscore.load(); unrequitedList = _.difference(followList,followerList); return unrequitedList; } //フォローしている人のリストを作成 function GetFollowList(screen_name,user_id) { var followCursor = -1; var followList = []; while (followCursor != 0) { var follow_list = CS_Twitter.TwitterFollowList(5000,screen_name,user_id,followCursor); followCursor = 0; if (follow_list != null) { if (follow_list.errors == null) { followCursor = follow_list.next_cursor; followList = followList.concat(follow_list.ids); } else { break; } } } return followList; } //フォロワーのリストを作成 function GetFollowerList(screen_name,user_id) { var followerCursor = -1; var followerList = []; while (followerCursor != 0) { var follower_list = CS_Twitter.TwitterFollowerList(5000,screen_name,user_id,followerCursor); followerCursor = 0; if (follower_list != null) { if (follower_list.errors == null) { followerCursor = follower_list.next_cursor; followerList = followerList.concat(follower_list.ids); } else { break; } } } return followerList; }
余談
1回の実行で片思いが多すぎる人などは途中でTwitterAPIの規制や、GASのURLFetchの規制で処理が途中で終わる場合があります。
過去記事の応用などもあり、省略部分があるかと思いますので不明点やエラーが出た場合はコメントにお願いします。
【GAS】時報をツイートする
はじめに
GoogleAppScript(以下GAS)を使って1時間ごとに時刻が変わったことをTwitterに報告するBotを作ります。
GASで定期ツイートをするまでは以下をどうぞ。
madgenius.hateblo.jp
今回は上の定期ツイートの記事に正確性と実行時間の取得を追加するだけになります。
ソース
特に変更が必要な場所はありません、このまま使用できます。
タイマーは毎分で設定してください。
//1時間ごとに時刻をツイートする function HourTweet() { var Nowymdhms = new Date(); var NowYear = Nowymdhms.getYear(); var NowMon = Nowymdhms.getMonth() + 1; var NowDay = Nowymdhms.getDate(); var NowHour = Nowymdhms.getHours(); var NowMin = Nowymdhms.getMinutes(); if (NowMin == 0) { CS_Twitter.TwitterSend(NowHour+"時になりました。\n("+ZeroNum(NowYear,4)+"/"+ZeroNum(NowMon,2)+"/"+ZeroNum(NowDay,2)+")"); } } function ZeroNum(num,zero) { var str = ""+num; for (var i = 0; i < zero; i++) { str = "0"+str; } return str.slice(-zero); }
ただ、タイマーで毎分チェックして0分の時に時報を流すだけです。
ぴったりの時間にお知らせできました。
余談
Twitterに投稿している部分を他のSNSに変更することもできます。
ChatWorkへの投稿については以下をどうぞ。
madgenius.hateblo.jp
【GAS】Twitterと連携して定期ツイート
GoogleAppScript(以下GAS)からTwitterと連携して定期ツイートするまでを書きます。
GASの用意
GASの始め方がわからない人は過去の記事を参考にしてね。
madgenius.hateblo.jp
とりあえず、用意したらTwitterAPIでPROJECT_KEYを取得するのに必要なので開いたまま次へ
TwitterAPIの作成
TwitterAPIを使用するにはKeyとSecretが必要です。
準備までの手順は以下を参考にどうぞ。
madgenius.hateblo.jp
CallBack URLの部分はGASなので「https://script.google.com/macros/d/{PROJECT_KEY}/usercallback」になるように気をつけてください。
その辺りも上の記事に書いています。
GASライブラリを用意
GASでTwitter連携するためにはKeyとSecretを利用してOAuth認証が必要です。
OAuth認証と言われても結構面倒なのでそれを簡単にするライブラリを用意しました。
導入方法や使い方も書いてありますのでどうぞ。
GASでツイート
以下がソースです。
ライブラリが入ってないと動きませんが、上で追加していれば動きます。
CS_Twitter.TWITTER_CONSUMER_KEY = 'API_KEY'; CS_Twitter.TWITTER_CONSUMER_SECRET = 'API_SECRET'; CS_Twitter.OAUTH_USER_KEY = 'AutoTweetBot'; function AutoTweet() { CS_Twitter.TwitterSend("定期ツイートです。"); } }
AutoTweet()をタイマーで呼んでやることでタイマーのタイミングで「定期ツイートです。」とツイートします。
TwitterAPIを利用するまでの登録など
Twitterと連携するアプリやウェブサイトを作るためにはTwitter DevelopersでAppとして登録する必要があります。
登録といってもTwitterアカウントがあれば無料でできるので安心してください。
TwitterDevelopersへ移動
以下より、TwitterAPIが作成できます。
Welcome — Twitter Developers
2017年8月現在ではこんなレイアウトです。
ちょっと前と変わりましたが基本的な配置は一緒です。
右上のMy appsをクリック
My appsを開く
Twitterにログインしていない場合はこんな感じ。
ログインしましょう。
まだ、Appを何も登録していない場合。
すでにAppを登録している場合。
App名や説明は別に見られてもいいものですが、何をしているかバレて恥ずかしいので隠しました。
画面の「Create New App」からAppを新規作成できます。
Appの新規作成
新規作成のページではApp名、利用目的の説明、ウェブサイト、CallBackURLの記入があります。
- Name(必須)
- App名
- Twitter連携時に表示されます。
- Description(必須)
- 利用目的の説明
- Twitter連携時に表示されます。
- CallBack URL
- アプリ連携の場合は基本未記入です。
- Botサービスなど外部サイトの場合、利用方法にCallBackにこのアドレスを記入と指示があると思います。
- GoogleAppScriptの場合は「https://script.google.com/macros/d/{PROJECT KEY}/usercallback」を記入します。
入力したらDeveloper Agreementのところの利用規約に同意のチェックを入れて「Create your Twitter application」をクリック。
Appを登録するとその詳細ページに遷移すると思います。
遷移しない場合はMy Appsから探してください。
【GAS】自動送信じゃないGmailをSNSに通知
私はそんなにメールを使わないのですが、
メールを使う営業の方からしてみればセミナーに参加した時などの自動送信メールに埋もれた個人宛の返信待ちのメールを見逃しがちなのでは?という発送で作りました。
GoogleAppScript(以下GAS)はGmailを持っていれば使えるのでエンジニア以外でも使えるのがいいですね。
機能としては
- 個人宛の場合に必ず入っている単語、ここでは苗字を含む未読のメールを20件まで検索
- 検索結果から特定のアドレスや単語を含むメールを排除し、10分以内に受け取ったものだけにする。
- 残ったメール内容は何回も通知しないように既読にします。
- 残ったメール内容をSNSに通知する。
GASとSNSの準備
以下、今回使うGASとChatWorkについての記事です。
GASを使用する準備は以下を参考にどうぞ。
madgenius.hateblo.jp
下のソースの最後にも同じ内容が入っていますが、GASでChatWorkに投稿する方法は以下を参考にしてください。
madgenius.hateblo.jp
ソース
以下、実際にソース内容です。
function MinuteCheckGMail() { /*---------------------------------------* * 未読で苗字を含んでいるメールを新規100件取得 *---------------------------------------*/ var strTerms = 'is:unread "あなたの苗字"'; //未読で苗字を含むもの var myThreads = GmailApp.search(strTerms, 0, 20); //条件にマッチしたスレッドを100件取得 var myMsgs = GmailApp.getMessagesForThreads(myThreads); //スレッドからメールを取得する →二次元配列で格納 var valMsgs = []; var dateNow = new Date(); /*---------------------------------------* * 10分以上前のものや自動配信のものを除外 * 除外されないものはChatWorkに送るので既読にする *---------------------------------------*/ var j = 0; for(var i = 0;i < myMsgs.length;i++){ var myThread = myThreads[i]; var myMsg = myMsgs[i]; if (myMsg != null) { var date = myMsg[0].getDate(); var from = myMsg[0].getFrom(); var subject = myMsg[0].getSubject(); var body = myMsg[0].getPlainBody(); if (!from.match(/block_user@gmail.com/)) { //特定のアドレスからの通知を拒否 //自動送信のニュースを拒否(Googleカレンダー,ChatWorkなど) if (!body.match(/配信停止/) && !body.match(/受信設定/) && !body.match(/通知設定/)) { //受信日時が今じゃないなら拒否(10分前のものまで受けとる) if (dateNow.getFullYear() == date.getFullYear()) { if (dateNow.getMonth() == date.getMonth()) { if (dateNow.getDate() == date.getDate()) { if (dateNow.getHours() == date.getHours()) { if (dateNow.getMinutes()-10 <= date.getMinutes()) { myThread.markRead(); //ChatWorkに送信したものは既読にする valMsgs[j] = []; valMsgs[j][0] = date; valMsgs[j][1] = from; valMsgs[j][2] = subject; valMsgs[j][3] = body; j++; } } } } } } } } } /*---------------------------------------* * 自分宛ての新着メールをチャットワークに送信する *---------------------------------------*/ if (valMsgs.length > 0) { for (var i = 0; i < valMsgs.length; i++) { var valMsg = valMsgs[i]; if (valMsg != null) { var strBody = ""; strBody += "[info][title]"+valMsg[1]+"[/title]"; strBody += "受信日時:"+valMsg[0].getFullYear()+"/"+valMsg[0].getMonth()+"/"+valMsg[0].getDate()+" "+valMsg[0].getHours()+":"+valMsg[0].getMinutes()+":"+valMsg[0].getSeconds()+"\n"; strBody += "タイトル:"+valMsg[2]+"\n"; strBody += "本文 :"+"\n"+valMsg[3]; strBody += "[/info]"; //ChatWorkに予定一覧を投稿する var client = ChatWorkClient.factory({token:"????????"}); client.sendMessage({ room_id:00000000, body:strBody }); } } } }
動作
hogehoge@gmailから自分が認証したアカウントに「あなたの苗字」の部分を「苗字」に変えて送信した場合です。
たまに2分ほど遅れて通知がきますが、未読であればちゃんと通知してくれます。
一応、同じhogehoge@gmailから「このメールは自動送信です。配信停止はこちら」みたいなメールを送りましたが、それは除外しているのでSNSに通知がきませんでした。
余談
GASでTwitterにツイートする記事です。
ツイート部分のアドレス(/update.json)を自分宛にDMを送信などにすれば使えます。
仕事のメールはChatWorkに、個人のメールはTwitterのDMになど変更可能です。
madgenius.hateblo.jp
【GAS】Googleカレンダーの予定をSNSへ通知
GoogleAppScript(以下GASと略称)でGoogleカレンダーの予定を自分のSNSにお知らせしてくれるツールを作りました。
普段、カレンダーを見る癖がない私ですが、SNSはよく見るのでSNSで自分宛に予定がくれば楽なので...
機能としては
- 1週間後の予定まで確認(改変可能)
- 予定の日時、または通知を設定した時刻(予定の10分前など)になったらSNSで自分宛に通知
SNSの部分は今回はChatWorkになっていますが、
仕事の予定はChatWork、個人はTwitterのDMなどの改変可能です。
GASを使用する準備は以下を参考にどうぞ。
madgenius.hateblo.jp
下のソースの最後にも同じ内容が入っていますが、GASでChatWorkに投稿する方法は以下を参考にしてください。
madgenius.hateblo.jp
以下、Googleカレンダーの予定をChatWorkに投稿するソース
/*------------------------------------* * 毎分カレンダーから1週間先までの予定を見る。 * ↓ * 予定が現在、または通知を登録していた時間だった場合お知らせする *------------------------------------*/ function MinuteCheckCalender() { //カレンダーからイベントの取得 var myCals = CalendarApp.getCalendarById('hogehoge@gmail.com'); //特定のIDのカレンダーを取得 if (myCals != null) { //権限がないなどの時はnullになるので処理をスルーする //カレンダーから現在〜1週間後までのイベントを取得 var startDate = new Date(); startDate = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), startDate.getHours(), startDate.getMinutes(), 0); var endDate = new Date(); endDate.setDate(endDate.getDate()+7); var myEvents = myCals.getEvents(startDate, endDate); if (myEvents.length > 0) { //カレンダーに予定がない時はスルーする //お知らせが必要な予定一覧を作成する var strBody = ""; for(var i = 0; i < myEvents.length; i++){ var alertTime = -1; var strStart = myEvents[i].getStartTime(); //イベントの開始時刻 //予定の日付と今日が同じかチェックする if (startDate.getFullYear() == strStart.getFullYear()) { if (startDate.getMonth() == strStart.getMonth()) { if (startDate.getDate() == strStart.getDate()) { //予定の日時と今が同じ時分かチェックする if (startDate.getHours() == strStart.getHours()) { if (startDate.getMinutes() == strStart.getMinutes()) { //何分前の通知かを保持 alertTime = 0; } } } } } var intReminders = myEvents[i].getPopupReminders(); //何分前にお知らせするか if (intReminders != null) { if (intReminders.length > 0) { //予定の日時じゃなくても通知が登録されていれば通知時間にお知らせする if (alertTime == -1) { for (var j = 0; j < intReminders.length; j++) { //通知として登録していた日時を取得 var minute = intReminders[j]; var alertDate = new Date(strStart.getTime()); alertDate.setMinutes(alertDate.getMinutes()-minute); //通知の日時と今日が同じかチェックする if (startDate.getFullYear() == alertDate.getFullYear()) { if (startDate.getMonth() == alertDate.getMonth()) { if (startDate.getDate() == alertDate.getDate()) { //通知の日時と今が同じ時分かチェックする if (startDate.getHours() == alertDate.getHours()) { if (startDate.getMinutes() == alertDate.getMinutes()) { //何分前の通知かを保持 alertTime = minute; break; } } } } } } } } } if (alertTime >= 0) { var strTitle = myEvents[i].getTitle(); //イベントのタイトル var strEvent = ""; if (strBody != "") { //他の予定の後に追加する場合は空白行を追加する strEvent += "\n\n"; } if (alertTime == 0) { strEvent += "[info][title]予定の時刻です[/title]"; } else { if (alertTime < 60) { strEvent += "[info][title]予定の"+alertTime+"分前です[/title]"; } else if (alertTime < 24*60) { strEvent += "[info][title]予定の"+(alertTime/60)+"時間前です[/title]"; } else { strEvent += "[info][title]予定の"+(alertTime/60/24)+"日前です[/title]"; } } strEvent += "件名:"+strTitle+"\n"; if (myEvents[i].isAllDayEvent()) { strEvent += "時間:終日\n"; } else { var strEnd = myEvents[i].getEndTime(); //イベントの終了時刻 strEvent += "時間:"+Utilities.formatDate(strStart,'JST','HH:mm')+"~"+Utilities.formatDate(strEnd,'JST','HH:mm')+"\n"; } var strLocation = myEvents[i].getLocation(); //場所 strEvent += "場所:"+strLocation+"\n"; var strDescription = myEvents[i].getDescription(); //説明 strEvent += "説明:"+strDescription; strEvent += "[/info]"; if (strEvent != "") { strBody += strEvent; } } } if (strBody != "") { //ChatWorkに予定一覧を投稿する var client = ChatWorkClient.factory({token:"???????????????"}); client.sendMessage({ room_id:00000000, body:strBody} ); } } } }
動作
実際に動かすとこんな感じ。
自分から自分に送るのではなく、Bot用のアカウントから自分に送ると通知がくるのでオススメです。
さらにSNSのスマホ用アプリを入れておくとPush通知でも確認できます。
現在、終日の場合は「時間:終日」となりますが予定日の0:00に通知がくるのでそこらへんは改変して使ってください。
余談
GASでTwitterにツイートする記事です。
ツイート部分のアドレス(/update.json)を自分宛にDMを送信などにすれば使えます。
仕事の予定はChatWorkに、個人の予定はTwitterのDMになどと使い分けが可能です。
madgenius.hateblo.jp
【GAS】ChatWorkに投稿
GoogleAppScript(以下GASと省略)でChatWorkに投稿する方法です。
ChatWorkAPIトークンの発行
まずはChatWorkAPIを使用するためにChatWorkからAPIトークンを発行する必要があります。
以下がChatWork公式のAPIドキュメントです。
developer.chatwork.com
ドキュメントの通り、動作設定を開き
出てきたウィンドウのAPI発行のタブを表示して、パスワードを入力すればAPIトークンが表示されます。
初回はAPIトークンが発行されていないので発行待ちがあるのと、ChatWorkに個人ではなく企業で契約していると管理者しかAPI発行のタブが表示されませんのでご注意ください。
GASに書き込み
APIトークンの取得に成功したら、GASで投稿してみましょう。
GASの準備などはこちらにまとめていますので参考にどうぞ。
madgenius.hateblo.jp
ChatWorkClientというライブラリを使用しますので「リソース > ライブラリ」を開き、プロジェクトキーに「1nf253qsOnZ-RcdcFu1Y2v4pGwTuuDxN5EbuvKEZprBWg764tjwA5fLav」を入力してライブラリを追加してください。
以下のメソッドに引数を渡してあげるとその引数の文字列を投稿してくれます。
function ChatWorkSend(strBody) { //ChatWorkに予定一覧を投稿する var client = ChatWorkClient.factory({token:"????????"}); client.sendMessage({ room_id:00000000, body:strBody }); }
【Unity】Xcodeから実機ビルド時に「App Installation Failed」
はじめに
Unityから書き出したプロジェクトをXcodeで開きiPhoneへインストールしようとした時、以下のエラーが起きた。
`[App Installation Failed] Could not write to the device.`
`[App Installation Failed] This application does not support this device’s CPU type.`
XcodeでRun時にメッセージウィンドウとして表示されます。
頻度としては4回実行して上のエラーが3回に対して、下のエラーは1回くらいです。
動作環境
iPhone7(iOS11 beta)
XCode 9.0 Beta 3
MacBook Pro(macOS Sierra10.12.5)
UnityPro(5.6.2f1)
そうなった経緯
- 朝、問題になっているプロジェクトにて実機インストールができる状態であったことを確認。
- デバッグのためUnityのBuild SettingsにてDevelopment BuildとAutoconnect Profilerにチェックを入れる。
- その後、以下の記事を参考にIl2cppだったプロジェクトをMono2xに変更する。
すると、エラーが出てインストールができなくなりました。
解決のためにやったこと
Mono2xからIl2cppに戻す
効果なし...
Unity Development Buildを解除
UnityのBuild SettingsにてDevelopment BuildとAutoconnect Profilerにチェックが入っていたので外したが効果なし。
以下は普通にエラー文で検索してみていろいろやってみました
正しいArchitecturesの設定かどうか
teratail.com
Targetの「Build Settings > Architectures > Valid Architectures」にiPhone7のarm64が追加されているか確認したが追加されていた...
容量
gootara.org
iPhoneの容量が足りず入れられない時にエラーが出るとあり、
iPhoneの容量が足りているか確認したが121.6GBも残っていた...
stackoverflow.com
Macの容量が足りないとインストールできずにエラーが出る的なことが英語で書いてあったのでMacの容量が足りているか確認したが67.09GB残っていた...
CocoaPods
neighborhood.bluz.io
CocoaPodsを使用している場合は.xcodeprojファイルではなく、.xcworkspaceファイルから起動しなくてはいけない。
forums.developer.apple.com
CocoaPodsを更新することで解決すると書かれている。
しかし、このプロジェクトはUnityでCocoaPodsは未使用です...
記事がなくなってきたので汎用的な祈りの儀式を始めます
Gitから復元
GitからUnityのプロジェクトを復元しました。
そしてバックアップしていたその後の編集内容を手動でマージ....
動いた!
まとめ
- いろいろやってみて解決しなかったらGitから復元しよう
- 慣れないことをする前にはバックアップを取ろう
おそらく原因は「Il2cpp⇆Mono2x」だとは思いますが戻しても動かなくなるのは厄介ですね...