RでFTPを使う

CRANにサブミットされたパッケージは以下で見られます。

ftp://cran.r-project.org/incoming/

どのディレクトリがどういう意味なのかよく分からないんですが、

  • pending: 審査待ち
  • inspect: 審査中?
  • recheck: 何か問題があって確認待ち?

という感じの意味のようです。まあとにかく、ここを見ていればCRANパッケージの最新動向がわかるということです。

そして、これをRからやりたい。

curlパッケージでFTPを使う

「R FTP」でググると以下の質問が引っかかります。これはRCurlパッケージですが、これはつまりcurlFTPをサポートしているということなので、curlパッケージでも同じことができます。

やってみるとこんな感じ。

library(curl)

x <- curl_fetch_memory("ftp://cran.r-project.org/incoming/pending/")

x
#> $url
#> [1] "ftp://cran.r-project.org/incoming/pending/"
#> 
#> $status_code
#> [1] 226
#> 
#> $headers
#>   [1] 32 32 30 20 57 65 6c 63 6f 6d 65 20 74 6f 20 74 68 65 20 43 52 41 4e
#>  [24] 20 46 54 50 20 73 65 72 76 69 63 65 2e 0d 0a 33 33 31 20 50 6c 65 61
#>  [47] 73 65 20 73 70 65 63 69 66 79 20 74 68 65 20 70 61 73 73 77 6f 72 64
#>  ....
#> 
#> $modified
#> [1] NA
#> 
#> $times
#>      redirect    namelookup       connect   pretransfer starttransfer 
#>         0.000         1.266         1.516         4.500         4.500 
#>         total 
#>         4.766 
#> 
#> $content
#>   [1] 2d 72 77 2d 72 77 2d 72 2d 2d 20 20 20 20 31 20 31 30 35 20 20 20 20
#>  [24] 20 20 31 30 30 31 20 20 20 20 20 20 20 38 31 39 34 34 35 20 4e 6f 76
#>  [47] 20 32 36 20 32 32 3a 33 30 20 64 62 6d 73 73 5f 32 2e 35 2d 31 2e 74
#>  ...

content要素に入っているバイト列を文字列に変換すると読めるようになります。

cat(rawToChar(x$content))
#> -rw-rw-r--    1 105      1001       819445 Nov 26 22:30 dbmss_2.5-1.tar.gz
#> -rw-rw-r--    1 1005     1001       314984 Nov 24 13:51 ems_1.0.0.tar.gz
#> -rw-rw-r--    1 105      1001       116156 Nov 26 19:16 knor_0.0-3.tar.gz
#> -rw-rw-r--    1 105      1001      4112350 Nov 24 15:26 outbreaker2_1.0-0.tar.gz
#> -rw-rw-r--    1 105      1001        22272 Nov 24 22:55 strider_1.1.tar.gz
#> -rw-rw-r--    1 105      1001       300464 Nov 26 23:55 voteogram_0.2.0.tar.gz

CURLOPT_CUSTOMREQUESTFTPコマンドを指定する

さて、上の結果はこうして視認するには十分ですが、もう少しプログラマブルに扱いたいところです。

FTPにはさまざまなコマンドがあり、NLSTというコマンドを使えば名前だけを返してくれるようです。これをcurlで指定するには、CURLOPT_CUSTOMREQUESTというオプションを使います。

Rでやるときには、handle_setopt()から指定します。

h <- new_handle()
handle_setopt(h, customrequest = "NLST")

r <- curl_fetch_memory("ftp://cran.r-project.org/incoming/pending/", h)

cat(rawToChar(r$content))
#> dbmss_2.5-1.tar.gz
#> ems_1.0.0.tar.gz
#> knor_0.0-3.tar.gz
#> outbreaker2_1.0-0.tar.gz
#> strider_1.1.tar.gz
#> texteffect_0.1.tar.gz
#> voteogram_0.2.0.tar.gz

あとは、個別のファイルの最終更新日時を得るにはMDTMというコマンドが使えます。これはcontentではなくmodifiedというフィールドに結果が入っています(contentにもなにかデータが入ってるんですが、何なのか分からなかった...)。

h <- new_handle()
handle_setopt(h, customrequest = "MDTM")
r <- curl_fetch_memory("ftp://cran.r-project.org/incoming/recheck/knitr_1.18.tar.gz", h)

r$modified
#> [1] "2017-11-27 03:47:01 JST"

ステータスコードをチェック

あとは、まじめにやるならstatus_codeをチェックしましょう。詳しくは知らないんですが、以下を読んだ感じ、大まかにはHTTPと同じで400以上ならエラー、という捉え方でよさそうです。

stopifnot(r$status_code < 400)

感想

FTPってもっとしっかり規格があると思ってたんですけど、決まってないことが多いんですね。。あんまりFTPについての知識を増やさなくてもいい世の中になっていくことを願うばかりです。