博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c#自动向网页Post信息并提取返回的信息
阅读量:5124 次
发布时间:2019-06-13

本文共 4872 字,大约阅读时间需要 16 分钟。

1、 打开一家航空运输公司的查询网页,如,该页面有两个文本框,供用户输入业务代码,如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是可以替换的,而且要注意的是发送的目标网页不再是我们在浏览器里直接输入的初始页面了

下面我们用程序来发送这段数据,代码如下

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

我选择了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 : 

例如下面是一个根据查询出来的结果格式化后的XML文本片断,该信息的XPath为

//div[@class=”content”]/DIV[@id=”tblwithbck”]/TABLE/TR/TD/TABLE/TR/TD/DIV[@class=”data”]

需要注意的是XPath中的每个路径是大小写敏感的,我就是一开始没注意这个问题,犯了些错误。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2 piece(s) 42 K departed on flight KE6316/04JUN from PVG to ICN

 

Actual Time of Flight-Departure : 19:20

 

Scheduled Time of Flight-Arrival : 21:55

 

 

 

 

 

 

2 piece(s) 42 K departed on flight 9S0910/06JUN from ICN to DFW

 

Actual Time of Flight-Departure : 22:15

 

Scheduled Time of Flight-Arrival : 05:35+1

 

 

 

 

 

 

2 piece(s) 42 K departed on flight 3A3617/07JUN from DFW to ELP

 

Actual Time of Flight-Departure : 22:00

 

 

 

 

 

 

2 piece(s) 42 K arrived in ELP from flight 3A3617

 

Scheduled arrival : 08 JUN

 

Goods checked in at : 11:00

 

 

 

 

 

 

Arrival docs delivered for 2 piece(s) 42 K on 09 JUN at 09:48 in ELP

 

 

 

 

 

转载于:https://www.cnblogs.com/songtzu/archive/2012/08/02/2620394.html

你可能感兴趣的文章
滚动侦测scrollspy
查看>>
Navicat 连接MariaDB 失败: Host '*' is not allowed to connect to this MariaDB server
查看>>
条件、循环、函数定义 练习
查看>>
Sql语句之递归查询
查看>>
模式(一)javascript设计模式
查看>>
关于构造函数和this调用的思考
查看>>
vi命令
查看>>
23种设计模式之原型模式代码实例
查看>>
python操作文件
查看>>
Linux系统开发之路 - 下
查看>>
iOS开发网络篇—GET请求和POST请求 分类: ios开发 ...
查看>>
C#学习之按钮点击事件
查看>>
C# 线程手册 第三章 使用线程 Monitor.TryEnter()
查看>>
【Xmail】使用Xmail搭建局域网邮件服务器
查看>>
zoj 4049
查看>>
一个关于数学归纳法的悖论问题-续
查看>>
selenium之截图
查看>>
自己的碎碎念
查看>>
Unity3D 物体移动方法总结
查看>>
MFC中CString.Format的用法
查看>>