【Ruby】大量のURLのHTTPステータスコードを取得してCSVで出力する

# はじめに
大量のページのHTTPステータスコードを確認しなければいけないコトがありまして、
スプレッドシートやら、無料のWebサービスを利用したんですがイマイチちゃんとできなかったです。
スプレッドシートのスクリプト実装がよくわからなかった。
無料のサービスだと100件までしか確認できない、多すぎて途中でコケてしまうなどありました。

そのためRubyで実装したという経緯があります。

また自分が使用するかもしれないのでメモがてら記事書きます。

HTTPステータスがヨグワガンニャイ人は下記の記事を見てみてください。
[httpステータスコード一覧 – 各コードの意味・影響・対処法を解説します](https://www.gc-seo.jp/journal/other/status-code/)

# 完成したソースコード

```ruby
require 'csv'
require "net/http"

urls = []
CSV.foreach("urls.csv") do |row|
  urls << row[0]
end

puts "#{urls.length}件のURLを確認します。しばらくお待ちください。"

CSV.open("http_status_result.csv", "w") do |file|
  urls.each do |u|
    uri = URI.parse(u)
    response = Net::HTTP.get_response(uri)
    file <<  [u, response.code]
    sleep 2
  end
end

puts "http_status_result.csvを作成しました。アプリを終了します。"
```

## 解説

### 1.csvを使用できるようにする
``require 'csv'``を忘れずに記載します。

### 2.httpステータスコードを取得できるようにする
HTTPステータスコードを取得するための``require "net/http"``を記載します。

### 3.URLの書かれたCSVファイルを作成
URLのみが１レコードごとに書かれたcsvをご用意ください。
それを、rubyファイルと同階層に入れてください。
エクセルで見ると、こんな感じのやつです。
<img width="381" alt="20493cf0407257fdf775e4c685e0703c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480700/1e0440fe-c3fb-e9a7-3bc8-a1c49732dd4b.png">

### 4.CSVからURLを呼び出して配列にする
```ruby
urls = []
CSV.foreach("urls.csv") do |row|
  urls << row[0]
end
```
上記の部分で、CSVデータを配列にしています。

``CSV.foreach("urls.csv") do |row| ~ end``はeachに似ていて、
``row``という変数に1レコード入れています。
それを``urls << row[0]``で配列に入れています。

``p row``で見てみるとこの時``row``は、``["https://www.yahoo.co.jp/"]``となっています。
配列に入れ直す際に``row[0]``として、１個目を取り出してから入れ直すことを忘れずに。（1敗）

### 5.CSVに書き込む準備
```ruby
CSV.open("XXX.csv", "w") do |file|
 ~ここに処理~
end
```
上記の処理の部分に、CSVにどの情報を入れるかを書きます。
``file << ele``とすると、csvに変数``ele``の中身を書き込むコトができます。

### 6.URLのHTTPステータスコードを取得する
>2.httpステータスコードを取得できるようにする

上記で``require "net/http"``を記載しているので、
httpステータスコード取得するメソッドが使用できます。

```ruby
uri = URI.parse("https://www.yahoo.co.jp/")
response = Net::HTTP.get_response(uri)
puts response.code
 # => 200
```

``uri = URI.parse("https://www.yahoo.co.jp/")``ここでURIを取得して変数に代入、
上記でHTTPステータスコードに読みにいける形状に整形してるような処理です。
それを、さらに``response = Net::HTTP.get_response(uri)``してネットワーク状況を取得して、
``response.code``でHTTPステータスコードが表示できます。

上記のURLが入る部分に、CSVから取り出したURLを入れてHTTPステータスコードを取得し、
``response.code``で取得したHTTPステータスコードをCSVに書き込めば完了です。
あと少し！

### 7.URLとHTTPステータスコードをCSV書き込む

```ruby
CSV.open("http_status_result.csv", "w") do |file|
  urls.each do |u|
    uri = URI.parse(u)
    response = Net::HTTP.get_response(uri)
    file <<  [u, response.code]
    sleep 2
  end
end
```

上記を細かく見ていきます。
まず、配列からURLを取り出して、処理をします。
その処理とは、

>6.URLのHTTPステータスコードを取得する

で使用した、ステータスコードを取得した処理を入れます。

```ruby
urls.each do |u|
  uri = URI.parse(u)
  response = Net::HTTP.get_response(uri)
end
```

そして、取得したHTTPステータスと、URLをセットにしてCSVの1レコードとして書き込みます。
``file <<  [u, response.code]``の部分にてCSVに書き込んでいます。
``u``はeachで取り出したURL、``response.code``は取得したHTTPステータスコードです。
``[u, response.code]``の中身を見ると
``["https://www.yahoo.co.jp/", 200]``となっています。

これが、CSVで書き込まれると、下記のようなデータが作成されます。
<img width="316" alt="a3b8f4995b15a864da3123200e9eda5f.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480700/c903745c-a700-b9fe-a4fd-3c8adc51d0b8.png">

rubyファイルと同階層に出来上がっているかと思います。

やっていることはスクレイピングのようなことなので、``sleep 2``で負荷を軽減することを忘れずに！

## こんな感じのエラーが出たら
```console
Traceback (most recent call last):
        7: from http_status.rb:12:in `<main>'
~~~~~~~~省略~~~~~~~~
/Users/okakaori/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/rfc3986_parser.rb:21:in `split': URI must be ascii only "\uFEFFhttps://www.yahoo.co.jp/" (URI::InvalidURIError)
```

MACエクセルでcsvファイルを作ると、BOMという見えない文字が入ったcsvとなってしまうようで、
その見えない文字列の部分で、処理がコケてしまいます。
下記のサイトを参考にして、BOMを削除したCSVデータで再度実行してみてください。

[UTF-8 のファイルから BOM を削除する方法](https://support.sugutsukaeru.jp/ja/tutorials/installation/214.html)

# おわりに
rubyでサクッと実装できたので、助かりましたが、
GASスプレッドシートのスクリプト覚えた方が良さそうだと思いました。
rubyだと、パソコンにrubyを実行できる環境がないといけないので、
みんなが使用できるスプレッドシートにそれを実装した方が、汎用性はたかそうだと思いました。

rubyで実装できても、他の実装方法の方が良いっていう勉強になるってなんか不思議な感覚ですね。

# 参考記事
[RubyでCSVファイルの読み込み・書き込みをする](https://uxmilk.jp/19202)
[RubyのHTTPリクエストをできるだけシンプルに実装する](https://qiita.com/takano-h/items/dd10818eb7e09161bc29)