ジョブカンをＷＥＢスクレイピング（打刻情報）

前記事[ジョブカンをＷＥＢスクレイピング（スタッフ情報）](https://qiita.com/harhid/items/bbec1099a24ce01dd66f) に引き続き、打刻情報の取出しにチャレンジします。

```:前記事より
日本で一番有名な勤怠管理システム「ジョブカン」（ごますりすり）！
残念ながら公開ＡＰＩがなく自社システムへデータを連動させる仕組みを提示して
くれていません。
ＣＳＶダウンロード機能はありますが、自分の手でＣＳＶを一旦ダウンロードして、
それを自社システムへアップロードして・・・という手間が必要です。
ここのところを自動化したいという思いがありまして、連動させるための仕組みを
調べてみた次第です。
```

# はじめに

前回記事では「スタッフ情報」をJSON形式で取得できました。

当社ではジョブカンを使ってＩＣカード打刻をしております。
打刻情報を自社の勤怠管理システムへ自動的に取り込みたいと考え、打刻情報の取出しにトライしました。

本稿で開示するソースは一部分のみです。ご要望があればコメントいただければ必要部を開示します。開示していないのは面倒だからだけです。

# 前提

前回同様、Java を使ってごりごりと実装します。(Java 1.8 で確認）

# 利用するライブラリ

前回同様、jsoup　を使います。

# わかったこと

・WEBスクライピングでジョブカン管理画面へログインできること
・打刻情報を CSV形式で取得できること（以外の形式は見つけられない）
・特定個人の日別打刻、月間の打刻、全社員の日別打刻、月間の打刻、いろいろ取れる。
・打刻情報は、打刻した時刻順で取れる。一日に数回打刻していれば全部とれる。
・取得できる情報は下記のとおり(リスト形式）。

| 位置 | CSV項目 | 内容 | 補記 |
|:---|:-----------------|:------------------|:------------------|
|1| スタッフコード  | ジョブカンへ登録したスタッフコード|英数字のやつ|
|2| スタッフ名   | スタッフの名前|  |
|3| 日付 | 打刻した年月日| 西暦 yyyy/m/d ( 前ゼロつかない）|
|4| 時刻 | 打刻した時刻 | 24時間形式の H:M (前ゼロつかない)|
|5| 打刻方法 | (*註1) | |
|6| GPS住所         |GPS打刻時のみ住所が出る|      aligned       |
|7| 不明         |情報なし| |
|8| 備考         |打刻時に入れたコメントらしい| |

(*註1)　下記の例のとおり、ICカード/PCマイページ打刻/GPS と表示されるようです。

【CSVの例】（１行目はヘッダー、テキトーにマスクしています）
"スタッフコード","","日付","時刻","打刻方法","","","備考"
"it-01","奄美権兵衛","2019/9/2","8:43","ICカード","","",""
"it-01","奄美権兵衛","2019/9/2","20:27","ICカード","","",""
"it-02","鹿児島太郎","2019/9/2","8:53","PCマイページ打刻","","",""
"it-02","鹿児島太郎","2019/9/2","20:38","PCマイページ打刻","","",""
"it-03","福岡正子","2019/9/2","8:25","GPS","住所が特定できませんでした。","","PC打刻"
"it-03","福岡正子","2019/9/2","19:8","GPS","福岡県福岡市※※（Mask）","",""


上記はブラウザより手でダウンロードした内容と同じです（それ以上の情報はとれない）。

今回記事のポイントは、取得する範囲をパラメータとして与えてCSV形式の情報を取り出せる！というところにあります（パラメータの解析で試行錯誤しましたので）。

# ＷＥＢスクレイピングしているところの解説

打刻CSVダウンロードのＵＲＬは下記のようです。

```
https://ssl.jobcan.jp/client/raw-adit/download?searching=1&search_type=(TYPE)&year=(yyyy)&month=(mm)&fromYear=(yyyy)&fromMonth=(mm)&fromDay=(dd)&toYear=(yyyy)&toMonth=(mm)&toDay=(dd)&employee_id=(ID)

```

【必須の項目】

| parmeter | 内容 | 設定値 | 補記 |
|:---|:-----------------|:------------------|:-----------|
|searching|  | 1 固定 |(*註1) |
|search_type | 月・日 の指定 | month or date |必須 |
|year | 取得するデータの西暦年 | yyyy　|必須 |
|month |取得するデータの月 | 01～12  | 必須 |

(*註1) searching の意味は結局わからず。固定の1 でよさそう。


【search_type=date のときに必要である項目】

| parmeter | 内容 | 設定値 | 補記 |
|:---|:-----------------|:------------------|:-----------|
|fromYear |開始年 | yyyy| (*註2) |
|fromMonth |開始月| mm　|  |
|fromDay |開始日| dd　|  |
|toYear |終了年 | yyyy　| (*註2) |
|toMonth|終了月|mm　|  |
|toDay|終了日|dd　|  |

(*註2) 必須の year と異なる年を入れたらどうなるかは試していない。

【 特定のスタッフの打刻のみ取り出したいときの項目】

| parmeter | 内容 | 設定値 | 補記 |
|:---|:-----------------|:------------------|:-----------|
|employee_id|スタッフ連番 | 数字 |(*註3)  |

(*註3) 英数字のスタッフコードではありません。スタッフに連番で振られた数字です。
前記事で取得したスタッフ情報（JSON形式）にて取得できます。

[スタッフ情報の件はここにあります](https://qiita.com/harhid/items/bbec1099a24ce01dd66f#%E3%82%8F%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8)

## 今回は・・・

全スタッフの特定年月の打刻情報を取りたいときは、下記のＵＲＬになります。

```
https://ssl.jobcan.jp/client/raw-adit/download?searching=1&search_type=month&year=2019&month=09

```

ジョブカン管理画面にログインして上記ＵＲＬを叩けばＣＳＶがダウンロードされることがわかります。


# ソース一部公開

ということで、これを自動化するためのソースは下記です。（一部抜粋）

ログインしてみるところは前記事を参照願います。（ここではＣＳＶをダウンロードするところのみ）

```
public class JobCanWebDakokuDL {
	/** 打刻CSVダウンロード */
	private static final String DOWNLOAD_URI = "https://ssl.jobcan.jp/client/raw-adit/download";
	private static final String PARMS_BASE = "searching=1&search_type=@type&year=@year&month=@month";
	private static final String PARMS_FROM = "&fromYear=@year&fromMonth=@month&fromDay=@date";
	private static final String PARMS_TO = "&toYear=@year&toMonth=@month&toDay=@date";
	private static final String PARMS_STAFF_NO = "&employee_id=@staffNo";

	/** JobCan Cookies */
	private JobCanCookies cookies;
	
	public JobCanWebDakokuDL(JobCanCookies cookies){
		
		this.cookies = cookies;
	}
	
	public String download(JobCanDakokuDownloadParams params) throws JobCanWebException{
		return download(params,null);
	}
	public String download(JobCanDakokuDownloadParams params, Integer staffNo) throws JobCanWebException{
		
		StringBuilder b = new StringBuilder();
		b.append(DOWNLOAD_URI);
		b.append("?");
		b.append(
				PARMS_BASE
				.replaceAll("@type",params.getType())
				.replaceAll("@year", String.format("%04d", params.getYear()))
				.replaceAll("@month", String.format("%02d", params.getMonth()))
				);
		if(JobCanDakokuDownloadParams.TYPE_DATE.equals(params.getType())){
			b.append(
					PARMS_FROM
					.replaceAll("@year", String.format("%04d", params.getYear()))
					.replaceAll("@month", String.format("%02d", params.getMonth()))
					.replaceAll("@date", String.format("%02d", params.getFromDay()))
					);
			if(params.getToDay()!=null && params.getToDay().compareTo(params.getFromDay())>0){
				// ToDay > FromDay のとき
				b.append(
						PARMS_TO
						.replaceAll("@year", String.format("%04d", params.getYear()))
						.replaceAll("@month", String.format("%02d", params.getMonth()))
						.replaceAll("@date", String.format("%02d", params.getToDay()))
						);
				
			}else{
				// ToDay を FromDay にする。
				b.append(
						PARMS_TO
						.replaceAll("@year", String.format("%04d", params.getYear()))
						.replaceAll("@month", String.format("%02d", params.getMonth()))
						.replaceAll("@date", String.format("%02d", params.getFromDay()))
						);
				
			}
			
		}
		if( staffNo != null){
			b.append(
					PARMS_STAFF_NO
					.replaceAll("@staffNo", String.format("%d", staffNo))
					);
		}
		try {
			URL targetUrl = new URL(b.toString());
			Connection con = Jsoup.connect(targetUrl.toString())
					// ContentTypeを無視する
					.ignoreContentType(true) 
					.cookies(this.cookies.getCookies())
					.userAgent(JobCanConstants.Jsoup.UA)
					.method(Method.GET)
					.followRedirects(true);
			Response res = con.execute();
			this.cookies.save(res.cookies());
			
			if(JobCanWeb.isLogin(res)){
				return res.body();
			}else{
				Response reRes = JobCanWeb.login(targetUrl, this.cookies);
				this.cookies.save(reRes.cookies());
				return reRes.body();
			}
			
		} catch (IOException e) {
			e.printStackTrace();
			logger.error(e.getMessage());
			throw new JobCanWebException(e);
		}
	}
}

```

# 最後に


取得したＣＳＶ形式の打刻情報を、改行部でSPLITして、ヘッダー行を除去して、"," でSPLITして・・とごにょごにょとすると、必要な情報を取り出すことができそうです（実際できた）。

思い切り端折ったソース公開ですが、参考にはなると信じています！