クリスマス後のカップルの様子をTwitterで分析するクソアプリを作った with @t_yng
どうも!
もっこりMokkoです!
クリスマスもいよいよ終わりを迎えるこのタイミング。 クソアプリアドカレ2016の大トリを投稿させていだきます。
#作ったもの
ゲスッター
※予告なく公開停止にする場合があります。
今回はフロントとデプロイ周りを私が、サーバー側を@t_yng氏で分担して作りました。
ありがとう、t_yng氏!
どんなアプリかは多くを語ることなかれ、みてくださいな。
ゲスッターはこちら
クリスマス前後で別れたカップル多すぎてビビりました。
いつまで動かしとくか分からないけど、twitterがある限りゲスッターにもカップルカウントとツイートは溜まり続けますのでたまに覗くと面白いかも?
#何をしているの?
Twitterのエゴサで特定のワードを含んでいるものを取得し、カウントしています。
「何でエゴサすれば目的の情報がとれるか?」を考えるのは面白かったです。
なお、ゲスッターはあくまでクソアプリなので、検索ロジックはゆるめです。
#中はこうなっている
TwitterのAPIを定期的に叩いて、fireBaseのDBに入れておき、それをJSから呼び出しています。
フロントはt_yng氏に教えてもらったNetlifyという静的フィアルのホスティングサービスを使って公開しました。めちゃくちゃ便利なので気になる人は一度触って見て欲しい。
というわけで、緩めですがクソアプリ2016締めの投稿でございました! 思いの外良い勉強になりましたし、作るの楽しかったです。
それでは、良いお年を!
(JAVA) Play FrameworkでAkkaのスケジューラーを使わずに処理を定期実行する
どうも!もっこりmokkoです。
これはHamee Advent Calendar 2016の24日目の記事です!
前回に引き続きPlay FrameWorkネタを一つ。
Play FrameworkではAkkaを使用したスケジューラーが提供&推奨されておりますが、今回はjarファイルを作成しcrontabで定期実行する方法です。
フレームワークの思想からは外れるかもしれないけど、WEBアプリケーションのデプロイ時にバッチの動作を担保したい場合は有用かも。あくまで一つの方法として記事にしておきます。
#この記事から分かること
- PlayFrameWorkでjarファイルを作成して処理を定期実行をする方法
- jarファイルの生成に使用するプラグインの導入方法
#作ったもの
- 10分間に一回、引数に渡した文字列でtwitterでエゴサしてコンソールに出す
#jarファイルを作成するプラグインを導入
sbt assemblyというプラグインを使用します。
Play FarmeworkはScalaで実装されたフレームワークなのでパッケージ管理はsbt(Scala build tool)になります。
というわけで、project/plugins.sbtに下記を追記。
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")
せっかくなので最新バージョン(2016年12月末時点)を使用。
過去のバージョンに比べて設定に必要な記述が減っています。
続いてsbt assemblyの設定をbuild.sbtに記述します。
今回はシンプルに3つの設定だけ書きました。
//jarファイルの名前を決める。 assemblyJarName in assembly := "twitter-kun.jar" //これを書いておくと、テストをスキップしてjarファイルを作成できる。コンパイル時間が長いので今回はスキップしちゃいます。 test in assembly := {} //jarファイルのマニュフェストを設定できます。今回は実行したいmain関数を持つクラスを指定しました。 mainClass in assembly := Some("batch.GetToTweet")
これでjarファイルを作成する準備は整いました。
プラグインをインストールする時間がかかるので、すぐにassemblyコマンドを叩くとエラーになるかも。
実際に叩くコマンドはこちら。プロジェクト直下で叩くとtarget/scala-x.xx.xx/下にjarファイルができます。
$activator assembly
後はcrontabに書いてjarを実行してあげればいいわけですが、ここでハマりポイントがあります。
Play Frameworkはサーバー上でアプリケーションが起動している状態じゃないとクラスやORMを使えない場合があります。
Ebeanを使った時はうんともすんとも言いませんでした。
というわけで、jarファイルからでもアプリのソースを使いまわせるよう実行するmain関数内でアプリケーションの起動と停止をやってあげましょう。
Play Framework入門の記事で作ったアプリに定期実行で使えるクラスを追加してみました。
package batch; import controllers.ApplicationController; import play.api.Play; import play.inject.guice.GuiceApplicationLoader; import play.libs.Json; import twitter4j.TwitterException; import utils.TwitterSearch; import java.io.File; import java.util.Arrays; public class GetToTweet { public static void main(String[] args) { //アプリケーションを起動するソース play.Environment env = new play.Environment( new File("."), ApplicationController.class.getClassLoader(), play.Mode.PROD ); play.ApplicationLoader.Context context = play.ApplicationLoader.Context.create(env); GuiceApplicationLoader appLoader = new GuiceApplicationLoader(); play.Application application = appLoader.load(context); //javaのライブラリにはstartのメソッドがないため、ここだけScalaのライブラリのPlay.api.play Play.start(application.getWrappedApplication()); //コンソールに取得したツイートをはく。 Arrays.stream(args).forEach(arg -> { try { System.out.println(Json.toJson(TwitterSearch.searchTweet(arg).getTweets())); } catch (TwitterException e) { e.printStackTrace(); } }); //処理が終わったらアプリケーションを停止してあげることも忘れずに Play.stop(application.getWrappedApplication()); } }
起動時に使っているクラス達はJavaとScalaで同名のクラスがあり、importを間違えると型を解決できなくなるので要注意!
今回書いたソースでは、Play.start()までは全部Javaのクラスを使います。
//scalaにはplay.api.Environmentがある。play.apiと続くものはscala。 play.Environment env = new play.Environment( new File("."), ApplicationController.class.getClassLoader(), play.Mode.PROD ); play.ApplicationLoader.Context context = play.ApplicationLoader.Context.create(env); GuiceApplicationLoader appLoader = new GuiceApplicationLoader(); play.Application application = appLoader.load(context); //javaのライブラリにはstartのメソッドがないため、ここだけScalaのライブラリのPlay.api.play。Applicationクラスの.getWrappedApplication()でscalaのアプリとしてstart()に渡さなければいけない。 Play.start(application.getWrappedApplication());
これで問題なくjarファイルが実行できるようになりました!
java -jar twitter-kun.jar 'メリークリスマス'
Jsonにして出力してみました。
play.libs.Jsonを使えば簡単にListをJsonにして出力できるので便利です。
あとはcrontabをこんな感じで書けば、定期実行できますね。
*/10 * * * * root java -jar hogehoge/twitter-kun.jar 'メリークリスマス'
といったところで、javaでplay Framework使っている人のお役に立てれば幸いです!
(Java) Play FrameWork入門! Twitter のつぶやき検索アプリを作ってみたよ
どうも!もっこりmokkoです。
日付も変わろうとしていますが、Hamee Advent Calendar 2016の10日目の記事です!
初アドカレにドキがムネムネなわけですが、最初書こうと思っていた内容(スクレイピングと置換)は自分自身納得ができなかったのでまた次回に。
というわけで、今日はScalaのフレームワークとして有名な「Play Framework」のJava版入門を1つ。
簡単なTwitterのエゴサアプリを作ってみました。
デモ
※herokuのFreeの使用時間超えて止まっちゃいました。(12月11日追記)
この記事から分かること
- PlayFrameWorkの導入方法
- 簡単なアプリケーションのつくりかた
- 開発環境 & 本番環境での動かし方
(組み込みのNetty と Tomacatの2手法を紹介)
Play FrameWorkとは
公式ドキュメントより引用
https://www.playframework.com/
Ruby on Rails感覚で扱えるJavaのフレームワーク。
Scala界ではかなり有名だそう。
導入方法
公式ページよりactivatorというツールをインストール。
▼こちらからどぞ
Typesafe Activator(https://www.lightbend.com/activator/download)
コマンドラインを通して、コマンドを叩けばすぐ使える。
▼ちょっとサボるけど、詳しくはこちらを参照
Installing - 2.4.x
プロジェクトを作成するコマンドはこれ。
$ activator new
対話式でアプリ名など色々聞かれるので答えると必要なファイルが生成される。
Browse the list of templates: http://lightbend.com/activator/templates Choose from these featured templates or enter a template name: 1) minimal-akka-java-seed 2) minimal-akka-scala-seed 3) minimal-java 4) minimal-scala 5) play-java 6) play-scala (hit tab to see a list of all templates)
簡単なアプリケーションを作ってみた
機能はtwitterでエゴサしてそれを引っ張ってくるだけ。
※Play Frameworkのバージョンは2.4.8を使用。現時点での最新バージョンは2.5.10。
▼画面はこんなの
コマンドでプロジェクトを作成すると既に Model 、View、Controllerのクラスが作成されている。
このMVCの仕様はjava初めての私でもとても分かりやすかった。
▼Modelクラスはこんな感じ。
package models; public class SearchWord { public String word; public String getWord() { return word; } public void setWord(String word) { this.word = word; } }
今回はPOSTされた文字列をtwitterでエゴサするだけなのでシンプルに。
DBに繋がないのでORMも使用しない。
Ebeanを使用した時はebeanのModelクラスを継承して使った。
▼そして、conf/routesにルーティングを書く。
#アプリのルーティングを設定するファイル #HTTPリクエスト URL 呼び出すメソッド名 の順に記載 GET / controllers.ApplicationController.index() POST /search controllers.ApplicationController.search() # 静的ファイルのルーティング viewの呼び出しに使用する GET /assets/*file controllers.Assets.at(path="/public", file)
こんな感じで、アクセスしたURLに応じて呼び出すControllerを指定する。
分かりやすい。
▼Controllerクラス
package controllers; import models.SearchWord; import play.data.Form; import play.mvc.Controller; import play.mvc.Result; import twitter4j.TwitterException; import utils.TwitterSearch; import java.util.List; import java.util.Map; public class ApplicationController extends Controller { /** POSTされた文字を元にtwitterでエゴサをかけるよ*/ public Result search() throws TwitterException { Map<String, String> postData = new Form(SearchWord.class).bindFromRequest().data(); List<twitter4j.Status> searchResult = TwitterSearch.searchTweet( postData.get("searchWord")) .getTweets(); return ok(views.html.listTweet.render(searchResult)); } /** viewを表示するだけだよ */ public Result index() { return ok(views.html.index.render()); } }
Resultクラスで受け取ってviewへレンダリング。
POSTされた値を受け取る時はFormクラスを使えばMAP型で受け取れる。
▼twitterのAPIを叩くライブラリはTwitter4Jを使わせて頂きます。
package utils; import play.Play; import twitter4j.*; import twitter4j.conf.ConfigurationBuilder; public class TwitterSearch { public static QueryResult searchTweet(String searchWord) throws TwitterException { ConfigurationBuilder configInfo = new ConfigurationBuilder(); //application.confからTwitterの設定を読み込むよ configInfo.setDebugEnabled(true) .setOAuthConsumerKey(Play.application().configuration().getString("twitter.authKey")) .setOAuthConsumerSecret(Play.application().configuration().getString("twitter.authSecret")) .setOAuthAccessToken(Play.application().configuration().getString("twitter.authToken")) .setOAuthAccessTokenSecret(Play.application().configuration().getString("twitter.authSecretToken")); TwitterFactory tf = new TwitterFactory(configInfo.build()); Twitter twitter = tf.getInstance(); Query query = new Query(); query.setQuery(searchWord); QueryResult result = twitter.search(query); return result; } }
twitterの認証に使う情報はconf/application.confという設定ファイルに外出し。
このapplication.confという設定ファイルは環境変数から読み込めるのでおすすめ。
#twitterの認証情報を環境変数から取得 twitter.authKey=${?AUTH_KEY} twitter.authSecret=${?AUTH_SECRET} twitter.authToken=${?AUTH_AUTHTOKEN} twitter.authSecretToken=${?AUTH_SECRET_TOKEN} #アプリの言語 play.i18n.langs = [ "ja" ]
▼他クラスでapplication.confの変数を呼ぶ時はこれ
(※Playのバージョンによって使うクラスが絶妙に違う。2.4はこれでいける)
Play.application().configuration().getString("twitter.authKey")
▼Viewクラス
@import b3.vertical.fieldConstructor @main("ツイッターくん") { @b3.form(routes.ApplicationController.search, 'class -> "form-group") { <div class="col-sm-offset-0 col-sm-6"> <label for="searchWord">#つぶやき検索</label> <input type="text" name="searchWord"> @b3.submit('class -> "btn btn-default"){ <span class="glyphicon glyphicon-globe"></span> 検索} </div> } }
Play Framewokのviewテンプレート。
ヘルパーでhtml生成はもちろん、素書きでもOKなので扱いやすい。
bootstrapにも対応しており、公式のPlay Bootstrapがあるのであまり手をかけず整ったページを作れる。
viewテンプレートの記法はScalaを使う。
@以降がScalaとして認識されてるのでせ、ループ処理もこのように書ける。
@(searchResult: List[twitter4j.Status]) @main("ツイッターくん") { @for(tweet <- searchResult) { <li>@tweet.getText()</li> } }
分かりづらいのが、@main()なるもの。
これは要するに変数で、viewの共通ファイルになっているmain.scala.htmlというファイルに渡すhtml要素を定義している。
▼main.scala.htmlはこんな感じ
最上部に@()で定義されているのが、このファイルに渡ってくる引数。
他のviewの@main("ツイッターくん"){ hogehoge }の"ツイッターくん"がmain.scala.htmlのtitleとして、そして{hogehoge}がhtmlとして渡されている。
@(title: String)(content: Html) <!DOCTYPE html> <html> <head> <title>@title</title> <link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")"> <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")"> <script src="@routes.Assets.at("javascripts/jquery-1.9.0.min.js")" type="text/javascript"></script> </head> <body> <div class="page-header"> <a class="navbar-brand logo" href="/"> <img src="@routes.Assets.at("images/medjed.png")" /> </a> <h1>Play Frameworkのテストだよ <br> <small>つぶやきを検索するよ</small> </h1> </div> @content </body> </html>
ささ、これだけでつぶやき取得アプリが完成!
テストと入力すると...
つぶやきを取得する。
デプロイしてみる
組み込みサーバーで動かすのはactivatorのコマンドで
$ activator start
application.confでsecret key(クライアントセッションの暗号化に使う)を指定していない場合はstartの引数に
$activator start -Dapplication.secret=abcdefghijk
だけでOK。
▼組み込みサーバーでデプロイ時のコマンドについて。こちら参照
Production - 2.4.x
Tomcatでデプロイする場合はwarファイルを作成する必要があるので、 play2warというプラグインを入れてコマンド1つでサクッと。
project/plugin.sbtに
addSbtPlugin("com.github.play2war" % "play2-war-plugin" % "1.4-beta1")
と build.sbtに
import com.github.play2war.plugin._ libraryDependencies ++= Seq( cache, jdbc, "mysql" % "mysql-connector-java" % "5.1.40", "com.adrianhurt" %% "play-bootstrap" % "1.1-P24-B3", "org.twitter4j" % "twitter4j-core" % "4.0.5" )
このように依存関係を追加すればコマンドからwarファイルを作成できる。
コマンドは
$activator war
使っているplay frameworkのバージョンによってバージョンの指定が異なるので注意! 2016年12月時点で2.5以降は非対応。
後はこのwarファイルをTomcat直下のwebapps内に置いてTomcatを立ち上げればデプロイ完了。
使ってみた感想
java初心者にとってとっつきやすかった。
ハマりどころも多いが嫌いじゃないし、むしろ好きかも。
PS.
▼ライブラリ探しはmaven repositoryでどうぞ。
https://mvnrepository.com/
米国大統領選の週ごとの投票率をいい感じのデザインで見れる「Count Yourself In」
グラフィックインフォを見かけることが多くなった。
そんな中でも、特に面白いな、優れているな、と思ったのが米国大統領選のグラフィックインフォだ。
というか、単純にこのサイトの各所で使われれいるイラストやフォント、色感が個人的にとても好きだ。
大統領選を追っている人には、ぜひ訪れて欲しいサイトだ。
このサイトのコンセプトは名前からも分かる通り、自分の州での支持率がパッと見で分かる工夫が散りばめられている。
私が気づいたのはこれくらい。
* 州のアイコンの色やグラフの配色を党で決めていて、共和党優勢か民主党優勢かで具合を変えている。(赤い州、青い州ってやつ)
* 州のアイコンが州の形(文字だけより分かりやすいと思う)
* 候補者の顔イラストと、ステータスバーで双方の支持率の具合がパっと見で分かる
* 世論調査を円グラフと着色で見えやすく
* 数字の表示を大きめに。強調している
* アクセス元の地域の情報をランディングページとして表示している(日本はnon-usだよ)
ものの見せ方の良い勉強になった。
デザインやアプローチの仕方を変えてみると、小難しい話でもとっつきやすかったり、参加意欲を変えることができたりするものだろうなあ。
参考兼チェック用として、メモ。
個人間の決済サービス「AnyPay」がいい感じ
かなりフレキシブルに使える個人間決済のサービスだなあという感想。
何ができるの?
* 初期費用・月額費用なしで、個人間でクレジットカードを使った決済ができる
* 販売者は物販やデータ販売、サービスまで扱えて、簡単に販売ページを作成できる
* 共有はQRコードかURLを渡せばOK
特徴的だなあと思ったところ
* 月額固定費用の販売(いわゆるサブスクリプション)形式もできる
* 手数料が安い(月間5000万円以上の売上から2.8%) ※2016年10月現在
* 登録が簡単で、決済にクレカが使える(手軽にこれができるのは嬉しい)
導入コストが劇的に低いので、友人間の貸し借りや割り勘にも気軽に使える。
サブスクリプションも可能なため、個人レッスン等にも相性がよい。
普通のオンライサロンよりも手数料も低いので、既存のユーザーを抱えている人であればAnypayを使って運営する人も出てくると予想。
ちなみに、売上の引き出しは200円の手数料のみ。
また、BASEとAnypayを比較すると、anypayの方がよりスコープを広い印象を持つ。
BASEが個人クリエイター向けのオンラインショップ作成コストを引き下げたが、Anypayは個人間の送金コストを引き下げた、という感じだろうか。
▼ダッシュボードはこんな感じ
登録は簡単だった。
これは今度使うことがあるだろう。
飲み会の費用徴収とかも「アプリでお願いね〜」みたいなのがあたりまえになったりして。
マネーロンダリングとかグレーなことにも使われそう。