1)通过HTTPS使用基本身份验证来保护站点,所以我需要正确登录.
2)我在页面上执行GET请求来检索__VIEWSTATE值(如果我没有设置这个东西,那么事情什么都不做)!
3)登录后,会有几个表单字段来完成,然后提交一个提交按钮,POST的形式就是服务器
4)当提交按钮被按下时,表单被POST到服务器,响应是相同的页面和表单,但现在在表单底部有一个额外的小HTML表格,需要一些数据.
我已经设法使用WebClient类对登录名和表单进行排序.我使用fiddler(和firebug)来检查在正常使用浏览器完成表单时发送的POST字段值.我可以从POST请求中成功获得响应,并显示正如预期在表单下方的数据表.然而,问题是,尽管表中填有数据,但是它填充了我不期望的数据.出现的数据是,如果我在浏览器中正常完成表单,但是将一个特定参数(下拉列表)设置为与将POST请求传递给服务器不同的值.我已经确认使用fiddler和firebug,我正在传递完全相同的POST参数,正常使用Web浏览器完成的表单发送.我现在完全坚持为什么这个参数不被服务器’考虑’?
一个区别是这个特定的控件是一个选择列表,它在更改时执行页面重新加载或“回发”.然而,除了稍后在表单中更改其他一些选择列表内容之外,这似乎并没有做任何事情.
我想我正在问有没有什么我会失踪,会导致这个?我完全把我的头发撕掉了.谁能帮忙?我已经发布了下面的代码(地址和参数被隐藏了隐私).
// 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,"",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,"Error whilst trying to connect to web page: " + e.Message,out cancel); } }
请忽略“ComponentMetaData”引用,因为这是SSIS脚本源的一部分.
任何想法或帮助将不胜感激 – 欢呼声!
有一个普通的ASP会话cookie,但cookie中没有值(当然,除了会话ID),我认为网站使用基本身份验证而不是表单身份验证我可以忽略cookie – 当我进入站点和获取数据返回这是可以的.我想这是值得一试,但我不得不只是改变代码来使用WebRequest类方法…
对于选择列表javascript,没有JavaScript在页面加载后更改选择列表的值.选择列表中唯一的JavaScript是一个onchange事件来做一个“回发”,只是在最后的POST中似乎更改了表单上的一些空白的其他选择列表.注意:生成POST请求时,包括所有POST参数,即使它们为空,并且还包括所有“web表单”特殊字段,如__VIEWSTATE,__EVENTTARGET等…
我不是Web表单的专家(MVC人自己),但网络形式的“引擎”还有什么期待?我已经为’application-type’的’application-x-www-form-urlencoded’发送了1个标题,但是我已经尝试过设置其他文件,例如从原始POST复制’User-Agent’头,但是最终与我从服务器得到一个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); }
解决方法
执行抓取时,应确保__VIEWSTATE包含所需的下拉列表值.要进一步调查,尝试从服务器decode the viewstate,并查看哪些值被发回.