c#屏幕抓取.. NET web表单页面- POST请求不完全工作

本文关键字:POST 请求 不完全 工作 抓取 屏幕 NET web 表单 | 更新日期: 2023-09-27 18:04:02

请原谅我这个有点冗长的描述,但我有一个奇怪的问题,c#屏幕抓取ASP。. NET web表单页面。我试图做的步骤如下:-

1)该网站使用HTTPS的基本身份验证是安全的,所以我需要适当地登录。

2)我正在页面上执行GET请求以检索__VIEWSTATE值(如果我不设置这个东西,该死的东西什么也不做!)

登录后,有几个表单字段需要完成,然后是一个提交按钮,该按钮将表单发送到服务器

4)当提交按钮被按下时,表单被POST到服务器,响应是相同的页面和表单,但现在在表单底部有一个额外的小HTML表,其中包含一些我需要获取的数据。

到目前为止,我已经使用WebClient类对登录和表单帖子进行了排序。我使用fiddler(和firebug)来检查通常使用浏览器完成表单时发送的POST字段值。我可以成功地从POST请求获得响应,其中所讨论的数据表如预期的那样出现在表单下面。然而,问题是,虽然表中填充了数据,但它填充了我不期望的数据。显示的数据是,如果我在浏览器中像往常一样完成表单,但将一个特定参数(下拉列表)设置为与我在POST请求中传递给服务器的值不同的值。我已经使用fiddler和firebug确认,我正在传递与使用web浏览器人工完成表单正常发送的完全相同的POST参数。我现在完全卡住了,为什么这个参数没有被服务器"考虑"?

唯一的区别是,这个特定的控件是一个选择列表,它执行页面重新加载或'回发'更改时。然而,这似乎并没有做任何事情,除了改变一些其他选择列表的内容后面的形式。

我想我是在问,我还缺少什么东西会导致这种情况吗?我简直要把头发都扯掉了。有人能帮忙吗?我把代码贴在下面(为了隐私,地址和参数都空白了)。

    // a place to store the html
    string responseBody = "";
    // create out web client to handle the request
    using (WebClient webClient = new WebClient())
    {
        // space to store responses from the remote site
        byte[] responseBytes;
        // site uses basic authentication over HTTPS so we'll need to login
        CredentialCache credentials = new CredentialCache();
        credentials.Add(new Uri(Url), "Basic", new NetworkCredential(Username, Password));
        // set the credentials in the web client
        webClient.Credentials = credentials;
        // a place for __VIEWSTATE
        string viewState = "";
        // try and get __VIEWSTATE from the web site
        try
        {
            responseBytes = webClient.DownloadData(Url);
            viewState = GetHtmlInputValue(Encoding.UTF8.GetString(responseBytes), "__VIEWSTATE");
        }
        catch (Exception e)
        {
            bool cancel = false;
            ComponentMetaData.FireError(10, "Read web page data", "Error whilst trying to get __VIEWSTATE from web page: " + e.Message, "", 0, out cancel);
        }
        // add our POST parameters (don't forget the __VIEWSTATE or it won't work as its an ASP.NET web page)
        NameValueCollection requestParameters = new NameValueCollection();
        // add ASP.NET fields
        requestParameters.Add("__EVENTTARGET", __EVENTTARGET);
        requestParameters.Add("__EVENTARGUMENT", __EVENTARGUMENT);
        requestParameters.Add("__LASTFOCUS", __LASTFOCUS);
        // add __VIEWSTATE
        requestParameters.Add("__VIEWSTATE", viewState);
        // all other form parameters
        requestParameters.Add("btnSubmit", btnSubmit);      
        /* I've hidden the rest of the parameters hidden for privacy just in case */
        // see if we can connect and get data
        try
        {
            // set content type
            webClient.Headers.Clear();
            webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");                             
            // 'POST' the form data using web client and hope we get a response
            responseBytes = webClient.UploadValues(Url, "POST", requestParameters);
            // transform the response to a string
            responseBody = Encoding.UTF8.GetString(responseBytes);
        }
        catch (Exception e)
        {
            bool cancel = false;
            ComponentMetaData.FireError(10, "Read web page data", "Error whilst trying to connect to web page: " + e.Message, "", 0, out cancel);
        }
    }

请忽略'ComponentMetaData'引用,因为这是SSIS脚本源代码的一部分。

任何想法或帮助将非常感激-干杯!

RE:谢谢你的快速回复,我对这些评论只能说…

有正常的ASP会话cookie,但cookie中没有值(当然除了会话ID),我认为该网站使用基本身份验证而不是表单身份验证,我可以忽略cookie -当我进入网站并获得数据返回时,这是可以的。我想这是值得一试,但我将不得不改变代码使用WebRequest类方法代替…

对于选择列表javascript,没有javascript在页面加载后改变选择列表的值。选择列表上唯一的javascript是一个onchange事件来做一个"回发",这似乎只会改变表单上的一些其他选择列表,无论如何在最后的POST中都是空的。注意,当生成POST请求时,我包括所有的POST参数,即使它们是空的,我也包括所有的"web表单"特殊字段,如__VIEWSTATE, __EVENTTARGET等…

我不是web表单(MVC人自己)的专家,但有什么其他的web表单"引擎"是期待吗?我已经发送了1头为"应用程序/x-www-form-urlencoded"的"内容类型",但我已经尝试设置其他人,如从原来的POST复制"用户代理"头,但这最终导致我从服务器得到500个错误,不知道为什么会发生?

下面是'GetHtmlInputValue'的代码,它有点简单/基本,可以做得更好,但是:-

    private string GetHtmlInputValue(string html, string inputID)
    {
        string valueDelimiter = "value='"";
        int namePosition = html.IndexOf(inputID);
        int valuePosition = html.IndexOf(valueDelimiter, namePosition);
        int startPosition = valuePosition + valueDelimiter.Length;
        int endPosition = html.IndexOf("'"", startPosition);
        return html.Substring(startPosition, endPosition - startPosition);
    }

c#屏幕抓取.. NET web表单页面- POST请求不完全工作

如果我理解正确的话,那么在下拉菜单中选择一个项目将导致执行POST,并且服务器更改表单另一部分中的可用选项。服务器将在__VIEWSTATE字段值中包含下拉列表的当前值。

当您执行抓取时,您应该确保__VIEWSTATE包含下拉框所需的值。要进一步研究,请尝试解码来自服务器的视图状态,并查看发回的值。