twitter4jとScalaでネトストしたい!!
好きな人のツイートは全部見たいって思うことありますよね。
ツイ消しも画像も含めて全部見たいって思いますよね。
ということで、ガチネトストプログラムを作りました。
ディレクトリ構成
sbtを使っていくので、ディレクトリ構成は以下のようになります
/ |- src/ |- main/ |- scala/ |- main.scala |- connect.scala |- stream.scala |- files/ |- build.sbt |- twitter4j.properties
build.sbt
build.sbtに必要なライブラリの依存関係を書いていきます。
とはいえ、twitter4j以外使わないので以下のようになります。
lazy val root = (project in file(".")). settings( inThisBuild(List( scalaVersion := "2.11.8", version := "0.1.0-SNAPSHOT" )), name := "stalker", libraryDependencies ++= Seq( "org.twitter4j" % "twitter4j-core" % "4.0.4" , "org.twitter4j" % "twitter4j-stream" % "4.0.4" ) )
twitter4j.properties
次に、twitter4jの設定を書いていきます。
debug=true oauth.consumerKey=YOUR_CONSUMERKEY oauth.consumerSecret=YOUR_CONSUMERSECRET oauth.accessToken=YOUR_ACCESSTOKEN oauth.accessTokenSecret=YOUR_ACCESSTOKENSECRET twitter4j.loggerFactory=twitter4j.NullLoggerFactory
自分のconsumerKeyその他は頑張って探してください。
普通にググれば取り方が出て来るはずなので。
本体
コードそのものを書いていきます。
connect.scala
まずは、screen name(@以下の部分)からID(アカウントに固有の数字)を求めましょう。
そうすることで、@以下を変えられたとしても継続してストーキングすることができるようになります。
package connect import twitter4j._ object TwitterConnector{ val factory = new TwitterFactory() val twitter = factory.getInstance() def getId(names : List[String]) :List[Long] ={ return names.map(x => twitter.showUser(x).getId()) } }
これで終わりです。ライブラリって便利ですね。
StringのListの形で引数を与えると、Id(Long)のListの形で返って来るようになっています。
本当はError処理とかするべきなんですが、面倒なので割愛します。
streaming.scala
次はstreamingでツイートを取得しましょう。
好きな人が呟いた瞬間にツイートを取って来ることができるようになります。
package stream import java.io._ import java.net.URL import twitter4j._ import scala.sys.process._ import scala.language.postfixOps class StalkerListener extends StatusListener{ override def onDeletionNotice(statusDeletionNotice :StatusDeletionNotice) ={ // ツイートが削除された時に発動します // 今回は無視 } override def onScrubGeo(userId :Long, upToStatusId :Long) ={ // 今回は無視 } override def onStatus(status :Status) ={ // ツイートされた時に発動します val user = status.getUser() val file = new File(new File(".").getCanonicalPath, s"files/${user.getId}.txt") s"echo ${status.getText()}" #>> file ! val medias = status.getMediaEntities().map(x => x.getMediaURL()).toList medias.zipWithIndex.foreach{case(x:String, i:Int) => val stream = new URL(x).openStream val buf = Stream.continually(stream.read).takeWhile( -1 != ).map(_.byteValue).toArray val nameOnly = x.drop(x.lastIndexOf('/')) val fileName = nameOnly.split('.').mkString(i.toString ++ ".") val dir = (new File(".").getCanonicalPath).toString ++ s"/files/${user.getId}/" s"mkdir -p ${dir}"! val imageFile = new File(dir, s"${fileName}") val bw = new BufferedOutputStream(new FileOutputStream(imageFile)) stream.close() bw.write(buf) bw.close } } override def onTrackLimitationNotice(numberOfLimitedStatuses :Int) ={ // 今回は無視します } override def onException(e :Exception) ={ // 例外が起こった場合に通知されます // 今回はスタックトレースでも出しておきます e.printStackTrace(); } override def onStallWarning(e: StallWarning) = { // 変わったらしい } }
streaming APIを使うときにはListenerというものが必要になるので、それの定義を行なっています。
監視しているstreamにツイートがされたときに、そのツイート引数としてonStatus関数が呼ばれます。
そのツイート主のIDを取ったtxtファイルを作成し、その中にツイートの内容をリダイレクトすることで書き込んでいます。
JavaのFileとかを使って追記しても良かったんですがめんどくさかったのでscala.sys.processを使って、リダイレクトして書き込んでいます。
後半部は画像ファイルを落として来る処理ですね。
動画が上がったときに関してはテストしていないので、どうなるのかわかりませんが、画像はいい感じに保存されるようになっています。
main.scala
さて、あとはstreamを監視するだけですね。
import java.io._ import twitter4j._ import scala.io._ import scala.sys.process._ import scala.language.postfixOps import stream._ import connect._ object Main{ def main(args: Array[String]) :Unit = { // val newName = ["hoge","fuga"] // val firstIds = TwitterConnector.getId(newName) val idFile = new File(new File(".").getCanonicalPath,"files/ids.txt") println(idFile) // firstIds.foreach{firstId => // s"echo ${firstId}" #>> idFile ! // } val idSource = Source.fromFile(idFile.getPath()) val ids = idSource.getLines.map{x => x.toLong}.toArray idSource.close val twitterStream : TwitterStream = new TwitterStreamFactory().getInstance(); val listener = new StalkerListener() twitterStream.addListener(listener) val fq = new FilterQuery(ids: _*) println(ids.mkString(",")) println("start Streaming") twitterStream.filter(fq) } }
コメントアウトを全て外せば、newNameに含まれているscreenNameからIDを取得して、検索対象に含むようになります。
twitterStreamにはuser,filterなど複数あるのですが、今回はIDを指定してツイートを取得したいので、filterを用いています。
詳しくは公式のドキュメントを。
使い方
これで完成です。
あとはrootディレクトリにて
sbt run
しておくだけで、files/(id).txtにツイートが収集できます。
画像はfiles/images/(id)/以下に収集されます。
ただし、仕様上filterだと非鍵垢のツイートしか取得できないので、鍵垢に対してはuser streamを用いた上でonStatusではじくようにしたら良いのではないでしょうか。
最後に
これを用いた際に生じる不都合については一切責任は追いませんので、ご容赦ください。
それでは、楽しいネトストライフを!
Emacs+sbt+ensimeでScalaの環境を整えた話
今期の実験でScalaを使おうと思い、まず手始めに環境を整えたので、はまったポイントをまとめようかと。
環境は、
です。
コンパイラを入れよう
Scalaのビルドツールとしてメジャーなものの1つであるsbtをインストールします。
幸いbrewに登録されているので、
brew install sbt sbt
でインストールできます。が、めちゃめちゃ時間がかかります。
最初にライブラリとか落としてくるからっぽいです。
IDEを入れよう
ScalaのIDEとしてensimeなるものがあり、これがsbtとEmacsに対応しているとのことだったので導入しましょう。
まずはsbt側から
~/.sbt/0.13/plugins/plugins.sbtを作成し、そこに
if (sys.props("java.version").startsWith("1.6")) addSbtPlugin("org.ensime" % "sbt-ensime" % "1.0.0") else addSbtPlugin("org.ensime" % "sbt-ensime" % "1.9.1")
を書き足します。以上です。
次にEmacs側を
毎度おなじみM-x list-packages でensimeを入れます。
これだけで一応連携自体はできるのですが、どうせやったらIDEらしく
.を入力したらauto-completeが起動したりとか
カーソルを合わせたところの型がみれたりとか
できたらいいなあと思ったので探してみたら、やってらっしゃる方
がいらっしゃったので、コードをコピペしたものの、バージョンの壁に阻まれ、若干妥協することになりました……
最終的なinit.elは以下の通りになりました。
;; ;; Scala-mode ***************************************************************** (require 'scala-mode) ;;; Use auto-complete for ensime (setq ensime-completion-style 'auto-complete) (defun scala/enable-eldoc () "Show error message or type name at point by Eldoc." (setq-local eldoc-documentation-function #'(lambda () (when (ensime-connected-p) (let ((err (ensime-print-errors-at-point))) err)))) (eldoc-mode +1)) (defun scala/completing-dot-company () (cond (company-backend (company-complete-selection) (scala/completing-dot)) (t (insert ".") (company-complete)))) (defun scala/completing-dot-ac () (insert ".") (ac-trigger-key-command t)) ;; look type at point by C-t (bind-key "C-t" `ensime-type-at-point scala-mode-map) ;; Interactive commands (defun scala/completing-dot () "Insert a period and show company completions." (interactive "*") (eval-and-compile (require 'ensime)) (eval-and-compile (require 's)) (when (s-matches? (rx (+ (not space))) (buffer-substring (line-beginning-position) (point))) (delete-horizontal-space t)) (cond ((not (and (ensime-connected-p) ensime-completion-style)) (insert ".")) ((eq ensime-completion-style 'company) (scala/completing-dot-company)) ((eq ensime-completion-style 'auto-complete) (scala/completing-dot-ac)))) ;; Initialization (setq ensime-startup-snapshot-notification nil) (add-hook 'ensime-mode-hook #'scala/enable-eldoc) (add-hook 'scala-mode-hook 'ensime-scala-mode-hook) (add-hook 'scala-mode-hook 'flycheck-mode)
動かしてみよう!
test.scalaを作って意気揚々とM-x ensime としたところ……
byte-code: check that sbt is on your PATH and see the Troubleshooting Guide for further steps http://ensime.org/editors/emacs/troubleshooting/ [(wrong-type-argument stringp nil)]
なんかつらそうなエラーが出てきました……
とりあえず必死になって英語のドキュメントを読んだところ、.ensimeとかいうファイルがないとダメだそうで、それ自体はsbtを使って作れるそうなので作ってみます
sbt ensimeConfig
で、再度M-x ensimeとすると……
ENSIME ready. Let the hacking commence!
成功です!
なんかいい感じに下線引いてくれたり型を出してくれたりするようになりました。
まとめ
多分こんな流れだったとは思うのですが、なにぶん環境が完成してから書き始めたため、他に詰まったところがなかっただろうか……という感じです。
あと、デバッガはうまく連携できなかったので、できた方がいらっしゃったら教えて下さい。
ではではっ
EmacsでSmalltalkの環境を整えようとした話
この夏に純粋オブジェクト指向のSmalltalkを勉強しようと思い、環境を整えていたのですが、様々にはまるポイントがあったのでまとめようと思った次第です。
まず
何をいれたらいいのかわかりにくい
処理系がいっぱいあるっぽくて、どれを入れたらいいのかわからなかったです。
とりあえずEmacsと連携できそうなやつ、ということでSmalltalk emacsでググって出てきたgnu-smalltalkとやらを入れてみました。
一応こいつ自体はbrewで入れられたのですが
付属のEmacs lispの使い方がわからない
付属でsmalltalk-mode.elとかgst-mode.elとかがついて来るんですが、まず使い方がいまいちわからんと。
で、ググってみて出てきたelispのコードをinit.elに書いてみたんですが、動かず
small-talk-mode.elの中身見てみたらコメントでこんなことが書いてありました
;;; Incorporates Frank Caggiano's changes for Emacs 19. ;;; Updates and changes for Emacs 20 and 21 by David Forster
いや、Emacs21とか旧石器時代かよ。そら動かんわ。
ということで、こいつを動かす術を探す旅に出たのですが
調べれど調べれど何も出てこない
Qiitaとかはてなブログとかにまとめがないのは覚悟していたのですが、stack over flowとかですらみつからず途方に暮れていた時にUbuntu向けのパッケージを圧縮したファイルを見つけ、最終更新が2016年だったのでとりあえず落としてみて中身を見ると、
smalltalk-mode-init.el.in
とかいう名前のファイルがあったので、これは!と思いinit.elにコピペしてみると
変数がなくて怒られる
Emacsあるあるですね。24で削除されたinhibit-first-line-modes-regexpsって変数を書き換えようとして怒られてました。その部分をinhibit-local-variables-regexpsとすると
ついに動きました!
C-c mでgstというインタープリタ(と思われるもの)が動きました!
長い道のりでした……ということで結論。
結論:マイナー言語はめんどくさい
この一言に尽きると思います。メジャーな言語ならこんなわたわたしなくていいですからね。
とはいえこのいじってる時間も楽しかったりするのでいいんですが。
これからごりごりsmall-talkを書いていきます!
最後にinit.elに書いたものだけ書いておきます。
(push (cons "\\.star\\'" (catch 'archive-mode (dolist (mode-assoc auto-mode-alist 'archive-mode) (and (string-match (car mode-assoc) "Starfile.zip") (functionp (cdr mode-assoc)) (throw 'archive-mode (cdr mode-assoc)))))) auto-mode-alist) (autoload 'smalltalk-mode "smalltalk-mode.elc" "" t) (autoload 'gst "gst-mode.elc" "" t) (push '("\\.st\\'" . smalltalk-mode) auto-mode-alist) (push "\\.star\\'" inhibit-local-variables-regexps)
ではではっ
org-modeのTableで縦線を入れる方法
org-modeのTableで縦線を入れる方法
こんにちは。
突然ですがみなさんorg-modeのtableで縦線を入れたくて困った経験はないでしょうか。
横線であれば、
|---+---+---+---+---|
こういうやつで入るのに、縦に線を入れようとしても、どうやっても入らない。
で、諦めてM-x org-table-convertしてtable-modeで無理やり入れていたのですが、編集するのも面倒になるのでできれば避けたい。
ということで頑張って探してみたところ、見つけました。
http://orgmode.org/manual/Column-groups.html#Column-groups
column-groupsって書かれても気付かんわ……
とりあえず、ものは試し。書いてみると……
|---+-------+-------+---------+---------+---------+-----------------| | | Name | Hair | Height | Weight | English | Result | |---+-------+-------+---------+---------+---------+-----------------| | / | <> | < | | | > | <> | |---+-------+-------+---------+---------+---------+-----------------| | | Emi | brown | average | heavy | yes | foreign student | | | Mario | brown | short | average | no | Japanese | | | Jun | black | tall | average | no | Japanese | | | Lisa | brown | tall | average | yes | foreign student | | | Jo | red | average | light | yes | foreign student | | | Mie | black | short | light | yes | Japanese | | | Ran | black | average | light | yes | Japanese | | | Mai | brown | tall | heavy | no | Japanese | |---+-------+-------+---------+---------+---------+-----------------|
できました!<>の間が1つのグループとしてみなされるため、その両側で縦線を入れる、という感じでしょうか。
いろいろ探してみてやり方が見つからず、全然違うことを調べていた時に見つかる、という感じだったので、誰か同じように困っている方がいらっしゃったら、と思い記事にしました。
これで、より一層org-modeの使い勝手が上がりますね!
ではでは!
すでにネタがない
すでにネタがない
こんにちは。
タイトルの通りです。ブログを初めて二記事(しかも片方はただの自己紹介)で書くことがなくなりました。
よくよく考えれば、Emacsなんて人の設定をコピペして使ってるだけだし、いろんな言語の深い話かけるほど詳しくないし、プログラミングの話を毎日毎日できるわけがないんですよね。
だから、全然違う話をします。
三回生ですので進路に悩むお年頃です。
理系だから院に行くと思われがちなのですが、就職も少し考えています。
ので、夏期インターンシップを一社だけですが申し込み、明日その面接が控えております。
その対策として今まで自分がしてきたこととか振り返っているのですが、
とても辛い
自分が頑張ったと思ってたことを客観的に見て評価する必要が出てきて、あれ……?俺実は大したことしてない……?って気持ちになります。辛いです。
就活をしてらっしゃる方々は毎度毎度こんなことをしているのですね。そりゃ心の一つや二つ折れますね。
とはいえ面接もしていないのに心を折っている場合ではありません。持ち前の言語能力でそれらしいことをつらつらと語ってきます。
そう、それらしい日本語を並べるのには自身があります。半期でレポートを2万字分書いて10単位も錬成したことのある男です。
そうやって自分を鼓舞しているのですが、そのことすらも大したことじゃないんじゃないかという気になってきます。本当に辛いです。
明日の面接が終わればつらいものは実験と試験だけになるので少しは気が楽になります(実験も実験で憂鬱ですが)。
頑張ってきます。
ではでは。