c#自动向网页Post信息并提取返回的信息
1、 打開一家航空運輸公司的查詢網頁,如http://www.skyteamcargo.com/en/tracking/,該頁面有兩個文本框,供用戶輸入業務代碼,如180-36898035,
2、 然后單擊“Go”按鈕后,下一個頁面顯示查詢出來的結果
現在要求以上步驟都用程序自動實現,并把查詢結果提取出來,以備后面進一步處理。?
要完成這樣的功能,首先要解決以下幾個問題:
l 能夠用程序在后臺將數據Post到目標網頁
l 能接收到對方返回的HTML結果頁面
l 能夠分析該頁面,并將需要的結果提取出來
經過一番研究和實驗,我解決了以上幾個問題,下面分別描述。
1. 用程序將指定數據Post到目標網頁,并接收結果網頁
我先用一個網絡嗅探器來捕獲用IE手工查詢時瀏覽器和對方網頁的HTTP協議交互過程,這里推薦用Ultra Network Sniffer,它有個Connection Monitor功能,可以監視某個程序的所有連接,這樣就避免了其他無關數據包的干擾。如圖
當在查詢頁面里輸入數據后,點擊“Go”按鈕,嗅探器捕捉到的數據包如下圖
請注意第三行,有一個Post數據包,這個就是我們需要的,
它所發送的網頁地址為:http://www.skyteamcargo.com/en/tracking/tra_result.php
它所Post的數據為:awbpre=180&awbnum=36898035&x=17&y=9
很顯然,180和36898035是可以替換的,而且要注意的是發送的目標網頁不再是我們在瀏覽器里直接輸入的初始頁面http://www.skyteamcargo.com/en/tracking/了
下面我們用程序來發送這段數據,代碼如下
public static string GetPage(string url, string postData,string encodeType,out string err)
???? {
???????? Stream outstream = null;
???????? Stream instream = null;
???????? StreamReader sr = null;
???????? HttpWebResponse response = null;
???????? HttpWebRequest request = null;
???????? Encoding encoding = Encoding.GetEncoding(encodeType);
byte[] data = encoding.GetBytes(postData);
// 準備請求...
try
???????? {???
// 設置參數
????????????? request = WebRequest.Create(url) as HttpWebRequest;
????????????? CookieContainer cookieContainer = new CookieContainer();
????????????? request.CookieContainer = cookieContainer;
????????????? request.AllowAutoRedirect = true;
????????????? request.Method = "POST";
????????????? request.ContentType = "application/x-www-form-urlencoded";
????????????? request.ContentLength = data.Length;
????????????? outstream = request.GetRequestStream();
????????????? outstream.Write(data,0,data.Length);
????????????? outstream.Close();
//發送請求并獲取相應回應數據
????????????? response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才開始向目標網頁發送Post請求
????????????? instream = response.GetResponseStream();
????????????? sr = new StreamReader( instream, encoding );
//返回結果網頁(html)代碼
string content = sr.ReadToEnd();
????????????? err = string.Empty;
return content;
???????? }
catch(Exception ex)
???????? {
????????????? err = ex.Message;
return string.Empty;
???????? }
}
上面的代碼很好懂,就不多費口水了,只談幾點要注意的問題:
如果你的程序需要保留SessionID,如ASP.NET中的那個SessionID。比如說自動登錄后,可能還要后繼的處理,則你需要在向下一個頁面發送請求之前將前一個request返回的cookieContainer賦值給新的request,因為在cookieContainer中保留了一個叫做ASPNETSessionID的Cookie。
如果你Post的目標頁面是ASP.NET頁面,則一般在要提交的Form里都有一個__ViewState隱藏Input字段,一個服務器返回的網頁源碼的ViewState的例子如下,
?
?
?
???????? value="dDwtMzg4MDA0NzA7Oz7+jHQ0vF37/ga2CitRkQ3sfg+ePg==" />
?
?
然而在嗅探器中捕捉到的Post數據是:
__VIEWSTATE=dDwtMzg4MDA0NzA7Oz7%2BjHQ0vF37%2Fga2CitRkQ3sfg%2BePg%3D%3D&UserName=admin&Password=123&Submit=Button0
請大家注意,這里ViewState的數據和前面的有點不一樣,差別是其中的”+/=”等符號都被轉成了%2B,%2F,%3D等,這其實將ViewState的值進行了URL編碼,大家可以用System.Web.HttpUtility.UrlEncode()方法來做這種轉換
當然,如果你只需要對頁面做一次性訪問,則大可不必理會這些,只用根據嗅探器捕獲的結果來發送數據就可以了,但是如果你需要根據頁面返回的ViewState值動態處理,則需要注意這一點。
2. 從HTML網頁代碼中提取信息
要從HTML網頁中提取信息,首先得將網頁代碼格式化成XML形式的文件,然后可以用XPath很方便的提取出自己想要的信息,要將HTML格式化為XML形式,目前有幾個選擇
1、 Chris Lovett的SgmlReader:
http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=b90fddce-e60d-43f8-a5c4-c3bd760564bc
2、 Simon Mourier的.NET Html Agility Pack
http://blogs.msdn.com/smourier/archive/2003/06/04/8265.aspx
我選擇了SgmlReader, 通過實際使用,發現SgmlReader也不是盡善盡美,格式化出來的XML有時候嵌套關系會搞錯,但即使這樣,根據他格式化出來的文本,用來提取數據也足夠了。
public static DataSet ParsePage(string pageContent, string xpath, out string err)
???? {
???????? err = string.Empty;
string pageContent = this.tbHTML.Text;
???? StreamReader streamReader = null;
???? StringWriter strWriter = null;
???? SgmlReader sgmlReader = null;
???? XmlTextWriter xmlWriter = null;
try
???? {
????????????? sgmlReader = new SgmlReader();
?????????????????? sgmlReader.DocType = "HTML";
?????????????????? sgmlReader.InputStream = new StringReader(pageContent);
?????????????????? strWriter = new StringWriter();
?????????????????? xmlWriter = new XmlTextWriter(strWriter);
?????????????????? xmlWriter.Formatting = Formatting.Indented;
while (sgmlReader.Read())
?????????????????? {
if (sgmlReader.NodeType != XmlNodeType.Whitespace)
?????????????????????? {
??????????????????????????? xmlWriter.WriteNode(sgmlReader, true);
?????????????????????? }
?????????????????? }
string wellFormedHTML = strWriter.ToString();
this.tbHTML.Text = wellFormedHTML;
string xpath = this.tbXPath.Text;
?????????????????? XPathDocument doc = new XPathDocument(new StringReader(wellFormedHTML));
?????????????????? XPathNavigator nav = doc.CreateNavigator();
?????????????????? XPathNodeIterator nodes = nav.Select(xpath);
while (nodes.MoveNext())
?????????????????? {
this.tbResult.Text += nodes.Current.Value+"/n";
?????????????????? }
????????????? }
catch (Exception exp)
????????????? {
string err = exp.Message;
?????????????????? MessageBox.Show("錯誤:"+err);
???????? }
}
}
根據上面的代碼來看,目前主要的問題就是要設置正確的XPath了,Code Project上有篇文章提供了一個簡單的XPath查詢工具,我對其作了一些修改,主要增加了在節點的正文中搜索某個字符串的功能,方便大家根據獲得的HTML頁面查詢XPath
Debugging XPath Queries :?http://www.codeproject.com/dotnet/xpath_visualizer.asp
例如下面是一個根據查詢出來的結果格式化后的XML文本片斷,該信息的XPath為
//div[@class=”content”]/DIV[@id=”tblwithbck”]/TABLE/TR/TD/TABLE/TR/TD/DIV[@class=”data”]
需要注意的是XPath中的每個路徑是大小寫敏感的,我就是一開始沒注意這個問題,犯了些錯誤。
?
?
?
?
?
?
?
?
?
?
?
?
?
| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? |
轉載于:https://www.cnblogs.com/songtzu/archive/2012/08/02/2620394.html
總結
以上是生活随笔為你收集整理的c#自动向网页Post信息并提取返回的信息的全部內容,希望文章能夠幫你解決所遇到的問題。