草庐IT

C# 屏幕抓取 ASP.NET 网页表单页面 - POST 请求未完全正常工作

coder 2024-05-31 原文

请耐心等待这个略显冗长的描述,但我在 C# 屏幕抓取 ASP.NET Web 表单页面时遇到了一个奇怪的问题。我正在尝试执行的步骤如下:-

1) 该站点使用基于 HTTPS 的基本身份验证进行保护,因此我需要正确登录。

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

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

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

到目前为止,我已经设法使用 WebClient 类对登录和表单发布进行了排序。我使用 fiddler(和 firebug)来检查在使用浏览器正常完成表单时发送的 POST 字段值。我可以成功地从 POST 请求中获得响应,其中有问题的数据表按预期显示在表单下方。然而问题是,尽管表中填充了数据,但它填充了我不期望的数据。出现的数据是,如果我像往常一样在浏览器中完成表单,但将一个特定参数(下拉列表)设置为与我将 POST 请求传递给服务器的值不同的值。我已经使用 fiddler 和 firebug 确认我传递的 POST 参数与使用 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 session cookie,但 cookie 中没有值(当然除了 session ID),我想因为该站点使用的是基本身份验证而不是表单例份验证,所以我可以忽略 cookie - 当我进入站点并返回数据,这没问题。我想这值得一试,但我必须更改代码以使用 WebRequest 类方法代替...

至于选择列表 javascript,没有 javascript 在页面加载后更改选择列表的值。选择列表上唯一的 javascript 是执行“回发”的 onchange 事件,它似乎只会更改表单上的一些其他选择列表,这些列表在最终 POST 中无论如何都是空的。注意我在生成 POST 请求时包括所有 POST 参数,即使它们是空的,我还包括所有“网络表单”特殊字段,如 __VIEWSTATE、__EVENTTARGET 等......

我不是 Web 表单方面的专家(我自己是 MVC 人),但是 Web 表单“引擎”还期待其他什么吗?我已经为“application/x-www-form-urlencoded”的“Content-Type”发送了 1 个 header ,但我尝试设置其他 header ,例如从原始 POST 复制“User-Agent” header ,但这最终我从服务器收到 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);
    }

最佳答案

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

当您执行抓取时,您应该确保 __VIEWSTATE包含下拉列表所需的值。要进一步调查,请尝试 decode the viewstate从服务器并查看哪些值被发回。

关于C# 屏幕抓取 ASP.NET 网页表单页面 - POST 请求未完全正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31543566/

有关C# 屏幕抓取 ASP.NET 网页表单页面 - POST 请求未完全正常工作的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby - 完全离线安装RVM - 2

    我打算为ruby​​脚本创建一个安装程序,但我希望能够确保机器安装了RVM。有没有一种方法可以完全离线安装RVM并且不引人注目(通过不引人注目,就像创建一个可以做所有事情的脚本而不是要求用户向他们的bash_profile或bashrc添加一些东西)我不是要脚本本身,只是一个关于如何走这条路的快速指针(如果可能的话)。我们还研究了这个很有帮助的问题:RVM-isthereawayforsimpleofflineinstall?但有点误导,因为答案只向我们展示了如何离线在RVM中安装ruby。我们需要能够离线安装RVM本身,并查看脚本https://raw.github.com/wayn

  5. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  6. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  7. ruby-on-rails - rails : How to make a form post to another controller action - 2

    我知道您通常应该在Rails中使用新建/创建和编辑/更新之间的链接,但我有一个情况需要其他东西。无论如何我可以实现同样的连接吗?我有一个模型表单,我希望它发布数据(类似于新View如何发布到创建操作)。这是我的表格prohibitedthisjobfrombeingsaved: 最佳答案 使用:url选项。=form_for@job,:url=>company_path,:html=>{:method=>:post/:put} 关于ruby-on-rails-rails:Howtomak

  8. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  9. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  10. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

随机推荐