2

C# WebRequest を使用して、ASP.NET フォーム認証を利用して Web サイトをスクリーン スクレイピングしようとしています。

最初に、アプリケーションはログイン ページに対して GET を実行し、非表示の入力フィールドから __VIEWSTATE および __EVENTVALIDATION キーを抽出し、Cookie から .NET SessionId を抽出します。次に、アプリケーションは、フォーム アクションに対して、ユーザー名、パスワード、その他の必須フォーム フィールド、および前述の 3 つの .NET 変数を使用して POST を実行します。

Chrome を使用して Web サイトへの認証を行う Fiddler セッションから、サイトの安全な領域へのナビゲーションを許可するために、Cookie にトークンが保存された 302 が返されることを期待しています。トークンなしで 302 を取得し続け、Web サイトの認証されていないホームページにリダイレクトされる理由がわかりません。Fiddler では、私のアプリケーションのリクエストは、Chrome または Firefox 内から行われたリクエストとまったく同じに見えます。

        // Create a request using a URL that can receive a post. 
        var request = (HttpWebRequest)WebRequest.Create(LoginUrl);
        // Set the Method property of the request to POST.
        _container = new CookieContainer();

        request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36";
        request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        request.Headers["Accept-Encoding"] = "gzip,deflate,sdch";
        request.Headers["Accept-Language"] = "en-US,en;q=0.8";

        var response = (HttpWebResponse)request.GetResponse();
        _container.Add(response.Cookies);

        string responseFromServer;

        using (var decompress = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
        {
            using (var reader = new StreamReader(decompress))
            {
                // Read the content.
                responseFromServer = reader.ReadToEnd();
            }
        }

        var doc = new HtmlDocument();
        doc.LoadHtml(responseFromServer);

        var hiddenFields = doc.DocumentNode.SelectNodes("//input[@type='hidden']").ToDictionary(input => input.GetAttributeValue("name", ""), input => input.GetAttributeValue("value", ""));

        request = (HttpWebRequest)WebRequest.Create(LoginUrl);

        request.Method = "POST";
        request.CookieContainer = _container;

        // Create POST data and convert it to a byte array.  Modify this line accordingly
        var postData = String.Format("ddlsubsciribers={0}&memberfname={1}&memberpwd={2}&chkRemberMe=true&Imgbtn=LOGIN&__EVENTTARGET&__EVENTARGUMENT&__LASTFOCUS", Agency, Username, Password);
        postData = hiddenFields.Aggregate(postData, (current, field) => current + ("&" + field.Key + "=" + field.Value));

        ServicePointManager.ServerCertificateValidationCallback = AcceptAllCertifications;

        var byteArray = Encoding.UTF8.GetBytes(postData);
        //request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36";
        // Set the ContentType property of the WebRequest.
        request.ContentType = "application/x-www-form-urlencoded";
        request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        request.Headers["Accept-Encoding"] = "gzip,deflate,sdch";
        request.Headers["Accept-Language"] = "en-US,en;q=0.8";
        // Set the ContentLength property of the WebRequest.
        request.ContentLength = byteArray.Length;
        // Get the request stream.
        var dataStream = request.GetRequestStream();
        // Write the data to the request stream.
        dataStream.Write(byteArray, 0, byteArray.Length);
        // Close the Stream object.
        dataStream.Close();
        // Get the response.
        response = (HttpWebResponse)request.GetResponse();
        _container.Add(response.Cookies);

        // Clean up the streams.
        dataStream.Close();
        response.Close();
4

1 に答える 1

0

結局のところ、__EVENTVALIDATION 変数のいくつかの奇妙な文字が改行にエンコードされていたため、ASP.NET はセッションが破損したと見なしてセッションを破棄しました。解決策は、Uri.EscapeDataString を使用して ASP.NET 変数をエスケープすることでした。

postData = hiddenFields.Aggregate(postData, (current, field) => current + ("&" + field.Key + "=" + Uri.EscapeDataString(field.Value)));
于 2013-09-16T06:32:22.040 に答える