ProcessingとSeleniumを使ってレッツ、ツイート自動化

こんにちは！　筆者、この記事が初投稿なので生暖かい目で見てくださると助かります。

#はじめに
この記事ではプログラミング言語「Processing」と、Webアプリケーションテストツール「Selenium」を用いて、ツイートを自動で行うことを目標に解説していきます。
（正直な話この記事見るよりpythonで動かす方が記事も豊富だし楽そうなんだよなあ...）


#環境
とりあえず以下の環境では可能です。Windowsでの動作確認はしてないのでわかりませんが、ライブラリを入れる手順が変わるのでは？くらいしか違いは無いと思います。

||名称|備考|
|:--:|:--:|:--:|
|PC|MacOS Mojave|Ver10.14.6|
|言語|Processing3|Ver3.5.3|
|ライブラリ|Selenium|Java用 Ver3.141.59|
|webdriver|ChromeDriver|Ver77.0.3865.40(Chromeのバージョンと近いものが望ましいです)|

#環境(必要なもの)
##Processing3
プログラミング初心者やデザイン系の人におすすめ、らしい。自分自身は大学の講義で使う機会があったのでこの言語にこだわりました。Java互換のフレームワークなのでJavaの文法が少し使えます。(しかもIDEなので落とすだけでバリバリコードが書けるよ、やったね！)ダウンロードはこちらの[公式サイト](https://processing.org/download/)からどうぞ。

##Selenium
Webアプリケーションをテストするためのポータブルフレームワークです。響きがかっこいい。こちらも[公式サイト](https://www.seleniumhq.org/download/)よりダウンロードしてください。
ここで注意して欲しいのはProcessing用のライブラリは無いので、**Java版のクライアントライブラリをダウンロードしてくること**です。

##ChromeDriver
最後に、実際動かすために必要なWebDriverをダウンロードします。selenium自体はどのブラウザでも大丈夫らしいのですが、今回はGoogle Chromeを使った場合を解説していきます。
こちらも[ダウンロードページ](https://chromedriver.chromium.org/downloads)より、ダウンロードしてください。この時注意して欲しいのは**現在使用しているGoogle Chromeと近いバージョンのものを落としてくること**です。まあ、これに関してはバージョン違いで何が起こるかわからないので念の為、ですが。

#準備
さて、必要なものの準備はできましたね。今度は諸々のセッティングです。

まずはこの五つのjarファイルを
<img width="770" alt="selenium解凍　編集済.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442889/3598615f-c75f-1025-7084-e7f9e6358943.png">
Processingのライブラリフォルダに入れます。
macOSの方は`/Users/[ホームディレクトリの名前]/Documents/Processing/libraries`の下に`selenium`その下に`library`というフォルダを作って全て置いてください。
<img width="1183" alt="プロセ selenium置き場　編集済.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442889/9f8deb70-347b-d409-679b-b8da7c3b6816.png">

ここで見覚えのない`selenium.jar`が見えると思います。こいつは`client-combined-[バージョン].jar`の名前を変えてあげて、置いてください。

これでProcessing上でライブラリとして扱えるはずです。

#実践
さて、実際にコードを書いていきましょう。[github](https://github.com/kota-shiokara/autoTweet)にもあげましたが、こちらが自動ツイートのコードです。

```Java:MainDraw.pde
/* autoTweet Ver:0.1 */

//seleniumライブラリのインポート
import org.openqa.selenium.Keys;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;


WebDriver driver;

String TwiId = "@hoge";   //TwitterID
String TwiPass = "huga";  //パスワード

String tweet = "test";  //ツイート内容を書いてください
String putDriver = "/piyo/hogehoge";  //ChromeDriverが置かれている場所を指定してください

void setup(){
  size(500,500);
  
  //driver setup
  System.setProperty("webdriver.chrome.driver", putDriver);
  driver = new ChromeDriver();
}

void draw(){
  background(0);  
  
  if(frameCount % frameRate == 1){
    thread("test"); //テスト用
    //thread("tweetThread"); //自動ツイート
  }
}

void test(){
  driver.get("https://github.com/kota-shiokara");
  delay(2000);
  dispose();
}
```
```Java:TweetThread.pde
void tweetThread(){
  //WebElement 変数名 = driver.~; 省略可能
  //.findElement(); 引数の条件で要素を探し出す
  //.activeElement(); アクティブ化してる要素を探し出す
  //.linkText(); テキストで要素を探し出す
  //.className(); クラス名で要素を探し出す
  
  driver.get("https://twitter.com");
  driver.findElement(By.linkText("ログイン")).click();
  delay(1000); //1秒くらい待機
  driver.switchTo().activeElement().sendKeys(TwiId); //アクティブな要素に文字列を送る
  
  delay(500);
  WebElement login = driver.findElement(By.className("js-password-field"));
  login.sendKeys(TwiPass);
  
  delay(500);
  login.sendKeys(Keys.chord(Keys.ENTER));
  
  delay(2000);
  driver.findElement(By.className("DraftEditor-root")).click(); //ツイートボックス？の表示
  
  delay(1000);
  driver.switchTo().activeElement().sendKeys(tweet);
  
  delay(3000);
  driver.switchTo().activeElement().sendKeys(Keys.chord(Keys.COMMAND, Keys.ENTER)); //commandキーを押しながらenterキーを押す指示
  
  delay(1000);
  dispose();
  
}

void dispose(){
  driver.quit();
  println("disposed.");
}
```
processing君、実は優秀なので同じフォルダ内のファイルは変数も関数も勝手に共有してくれます。
基本的にはコメントアウトしている通りなので重要、だったり自分が躓いた部分を解説していきます。

##processing
まずprocessingの基本的な部分について解説します。知ってる方は読み飛ばしてください。
processingという言語の特徴として、setupメソッドとdrawメソッドがあげられます。setupメソッドは実行時に1フレームだけ呼び出され、drawメソッドは最初の1フレームを除き、毎フレーム呼び出されます。この言語は、基本的にsetupメソッドで諸々の定義などを済ませ、drawメソッドで繰り返し描写していくことが多いです。(使いこなしてる人はちょっと違うのでしょうけどね...)

##MainDraw.pde
###driver setup
`//driver setup`のところをご覧ください。まずは実際にChoromeを動かすwebdriverがどこにあるかの指定、Pathを通してあげなくてはなりません。System.setProperty()というメソッドでPathを通します。このメソッドでは第一引数でwebdriverの種類、第二引数で置き場所をString型で指定します。
その後、Webdriver型として宣言していた変数にChromeDriver()メソッドで値を入れてあげます。（実はこれがどういったものなのかいまいち理解できてないので詳しい方、教えてください）

###thread
実際の処理をdrawメソッド内で行なっているのですが、この際気をつけて欲しいのがdraw内に直接処理を書くことです。先述の通り、drawメソッドというのは毎フレーム呼び出される為、そこに今回の処理を入れると...考えたくもありませんね。
そこで使用するのがこれ、threadメソッド。こいつはdraw内の処理とは別の枠で処理を行なってくれる優れものです。これを一回呼び出すだけであとは処理が終わるのをじっと待つだけ、素晴らしい。

##TweetThread
具体的に自動ツイートするための処理を書いているところです。大体はコメントアウトしてるので読んでください。
###.get()
String型として入れた引数のurlに飛ぶメソッドです。

###.click()
要素にクリックイベントを付与します。

###delay()
引数(ミリ秒)の分だけ処理を中断するメソッドです。

##dispose()
「ゴミのポイ捨て禁止」
一連の処理を終わらせた後、ChromeDriverによって開かれてるChromeを閉じなくてはなりません。そこで処理の終わり際quitメソッドで終わらせます。しかし、処理の最中にChromeのウィンドウを消したり、などの想定外の出来事が無いとも言い切れません。
そこでこれ、disposeメソッド。processingでは終了時にこの関数が呼び出されます。ですのでそこにquitメソッドを混ぜてやれば安心という訳ですね。（実際はおまじない的な感覚で入れてるだけなんですけどね...）

#終わりに
さて、いかがでしたでしょうか。ここまでやっていくに当たってとても苦労しました。
processingの純正IDEはコーディング中でもエラーを吐いてくれるのですが、やれPathが通ってない、やれ要素が見つからないなどと出る度に頭を抱える羽目になりました。なにせprocessingを使ってseleniumを動かす記事が一つしか見つからなかったので(何度python使おうかと悩んだことか...)
今回、初めての記事制作で拙いところもあると思います。そこらへんの指摘なども受け付けておりますので、(自分の心が折れない程度に)じゃんじゃん質問等、投げてみてください。

#参考サイト
[ProcessingでSeleniumを使ってみよう](https://qiita.com/hiroshitoda/items/aaac63c3c6aaa06471c2)
[Selenium APIクイックリファレンス](https://www.seleniumqref.com/api/webdriver_gyaku.html)