C# HttpClient 自動ログイン　「楽天市場」

##はじめに##

WEBサイトから様々なデータを自動で収集するとき（いわゆるスクレイピングするとき）は、時にユーザーアカウントを作成してログインするサイトも対象となるときがある。

私の記事でオンライン麻雀サイトに自動ログインしてプレイ履歴を取得するソフトは作成して紹介したが他のサイトにもログインして自動ログインをいろいろ実行してみようと思う。

あらかじめ断っておくが今回、楽天市場にログインまではできたが商品情報などは楽天ＡＰＩでしかアクセスできないようスクリプトが組んであり商品情報の抜き取りはできなかったためご了承いただきたい。


それでは早速、楽天市場のログイン画面を開いてみる。今回は初めからChromeブラウザの検証画面を同時に表示してある（画面上で右クリックして「検証」）

![ログインID入力フォーム.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510936/03f590e5-512c-d6e1-e974-345711cae33d.png)

HTMLのスクリプトをカーソルでなぞると左側のサイトの中のどこのことを書いているのか
グレーにして表示してくれているので適時▽を押しながらツリーを表示していき該当箇所を探す。
**「ユーザＩＤ」はinputフォームのname ="u"**
**「パスワード」はinputフォームのname ="p"**

ということが分かった。

また、＜input＞タグは必ず＜form＞タグの内側にあるのでformの中の**action="./logini"**も確認しておく。（actionはPOST要求する際にサイトのURLにactionを続けて書いたURLがPOSTの送り先になるため）


##メインスレッド(変更部分"./logini")##

```Rakutenlogin.cs


using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;


namespace HttpClient_test
{
    class Program
    {

        private static HttpClient client;

        static void Main(string[] args)
        {
            //ログインページ
            string url_login = "https://grp01.id.rakuten.co.jp/rms/nid/vc?__event=login&service_id=top";
            //formタグ内のaction
            string url_action = "./logini";
　　　　　　 //POST要求先
            string url_post = url_login + url_action;
            //ログイン後にジャンプするページ(ホーム画面)
            string url_history = "https://www.rakuten.co.jp/";
  

            string USER_ID = "XXXXXXXXXXXXXX@mineo.jp";
            string PASSWORD = "XXXXXXXX";


            try
            {
                //クライアント接続開始
                client = new HttpClient();
            }
            catch (Exception ex)
            {
                Console.WriteLine("【接続エラー】：" + ex.Message);
            }

            string HTMLtext = "";
            try
            {
                //POST要求（ログインしてクッキー取得）
                Task<bool> task_login = PostRequest(url_post, USER_ID, PASSWORD);

                //URLでHTMLを取得する。
                if (task_login.Result)
                {
                    Task<string> task_get = GetRequest(url_history);
                    HTMLtext = task_get.Result;
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("【応答エラー】：" + ex.Message);
            }

            //HTMLテキスト確認
            Console.WriteLine(HTMLtext);

            //HTML構造解析
            //string resultstr = AnalizeHtml(50, HTMLtext);


            // ファイルの保存（別タスクで非同期処理　続けて処理をおこなうときはWait()を削除する）
            //Task task1 = Task.Run(() => { SaveFile(resultstr); });
            //task1.Wait();

            //End待機
            //Thread.Sleep(1000);
            Console.ReadKey();

        }

        //POST要求（ログイン）
        async static Task<bool> PostRequest(string url_post, string user, string password)
        {
            //POSTで送る内容作成。mContent.Add(属性の値, 属性の名前) 
            MultipartFormDataContent mContent = new MultipartFormDataContent();
            mContent.Add(new StringContent(user), "u");
            mContent.Add(new StringContent(password), "p");

            //ヘッダ情報確認
            Console.WriteLine("【PostRequest Headers】" + mContent.Headers);

            //POSTしてレスポンスの要求。（要求先、要求内容）
            HttpResponseMessage response = await client.PostAsync(url_post, mContent);
            Console.WriteLine("【PostRequest Response】 " + response.StatusCode.ToString());

            if (response.StatusCode == HttpStatusCode.OK)
            {
                //応答ステータスがOKならHTML文字列を取得する。
                string contentstr = await response.Content.ReadAsStringAsync();
                Console.WriteLine("【PostRequest HTMLcontent】" + contentstr);
                Console.WriteLine("【PostRequest Cookie】" + response.Headers.GetValues("Set-Cookie").First());
            }

            return true;

        }


```

##PostRequest   (変更部分"u","p")##
```Method1.cs
       async static Task<bool> PostRequest(string url_post, string user, string password)
        {
            //POSTで送る内容作成。mContent.Add(属性の値, 属性の名前) 
            MultipartFormDataContent mContent = new MultipartFormDataContent();
            mContent.Add(new StringContent(user), "u");
            mContent.Add(new StringContent(password), "p");

            //ヘッダ情報確認
            Console.WriteLine("【PostRequest Headers】" + mContent.Headers);

            //POSTしてレスポンスの要求。（要求先、要求内容）
            HttpResponseMessage response = await client.PostAsync(url_post, mContent);
            Console.WriteLine("【PostRequest Response】 " + response.StatusCode.ToString());

            if (response.StatusCode == HttpStatusCode.OK)
            {
                //応答ステータスがOKならHTML文字列を取得する。
                string contentstr = await response.Content.ReadAsStringAsync();
                Console.WriteLine("【PostRequest HTMLcontent】" + contentstr);
                Console.WriteLine("【PostRequest Cookie】" + response.Headers.GetValues("Set-Cookie").First());
            }

            return true;

        }
```

##GetRequest (変更なし)##
```Method2.cs
        async static Task<string> GetRequest(string url)
        {
            HttpResponseMessage response = await client.GetAsync(url);
            string contentstr = response.StatusCode.ToString();
            Console.WriteLine("【GetRequest Response】" + contentstr);

            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                contentstr = await response.Content.ReadAsStringAsync();
            }
            else if (response.StatusCode == HttpStatusCode.Redirect)
            {
                //StatusCode リダイレクトのときの処理
                var r = client.GetAsync(url).Result;
                Uri uri = new Uri(new Uri(url), r.Headers.Location);
                contentstr = client.GetAsync(uri).Result.Content.ReadAsStringAsync().Result;
            }

            return contentstr;
        }

```


##終わりに##
上記のソフトではPOST要求とGET要求それぞれで通信ステータスが返るのでURLの間違いなのか、入力フォームの間違いなのか、エラーの確認がしやすく自作ではあるが使いやすい造りになっている。以前にMJサイトで右往左往して作った甲斐があった。

今回はあまりデータを抜き取れる要素が無かったので次回は楽天APIを使って商品情報の取得を目指したいと思います。
おわり