错误的思路是这样的:发送一个访问页面的请求过去,得到一个html页面,然后我要的数据全都在这上面。后来发现不是这样的,也猜到可能是页面加载之后还有js代码的ajax的异步加载,那么问题来了?我是不是要等到这些ajax请求结束之后,我才能拿到数据呢?我怎么判断有没有结束?我要等多久合适呢?嗯,仔细向下,还有个问题是,发送的post请求过去,又没有浏览器渲染,谁去执行这些js代码呢?
实际上是这样的:发送一个访问页面的请求过去,上面可能有我要的数据,也可能没有,如果没有,那就看看是不是要发另外的请求。
1、相关工具和技巧
1.1 Chrome浏览器
打开浏览器,按F12进入调式状态,例如打开www.cnblogs.com
1.2 fiddler工具
用fiddler工具查看原始的请求数据,一般都会有一定的编码格式。用Chrome工具可能看不出来编码格式。
1.3 编码解码的工具
这些就不列举了,可以找在线工具。比如下面这个的:
http://meyerweb.com/eric/tools/dencoder/
附js编码与.net编码:
1.window.escape()与HttpUtility.UrlEncodeUnicode()编码格式一样:将一个汉字编码为%uxxxx格式
不会被window.escape编码的字符有:@ _ - . * / +
2.window.encodeURIComponent()与HttpUtility.UrlEncode()编码格式一样:将一个汉字编码为%xx%xx%xx的格式
不会被window.encodeURIComponent编码的字符有:‘ ( ) * - . _ ! ~
不会被HttpUtility.UrlEncode编码的字符有:‘ ( ) * - . _ ! 相比较而言,HttpUtility.UrlEncode比window.encodeURIComponent多一个 ~ 编码
3.不会被window.encodeURI编码的字符有: - _ . ! * ( ) ; / ? : @ & = $ , #,与encodeURIComponent对比,发现encodeURI不对:;/?:@&=+$,#这些用于分隔 URI 组件的标点符号进行编码
参考博文地址:
http://www.cnblogs.com/mxw09/archive/2010/04/06/1704986.html
1.4 正则表达式工具
解析返回的请求,如果是html格式的,就需要解析一下返回的结果。简单的话可以直接用正则表达式解析。反正我就是这么干的。
2 常遇到的问题
2.1 编码问题
(1)返回的信息为空
最开始,用chrome找目标请求,按照Header上的信息构造请求。结果发现怎么都不行,返回都是空。后来发现是编码问题,从chrome上看到的是编码之前的信息,从fiddler上面才能看到原始的请求。
(2)请求之后,结果跟页面上操作的不一致
我创单的时候,明明是有儿童,而且有不同性别的人创单。结果创单之后全部变成女性,全部是成人。我找了好久这个问题,仍然从chrome上一一检查参数发现没有什么问题,直到我看raw请求的时候,我才发现一个是编了码的,一个是没有编码的。一般请求都会进行编码,只是数字和字母基本上编码之后都是一样的,所以没有进行编码就访问了。只要有中文和某些特殊字符就必须要编码,否则可能会引起错误。
2.2 cookie问题
(1)报500,内部服务器错误
自己测的时候没问题,一发布测试就出问题,报500,内部服务器错误。后来才发现是cookie问题,重新登录一下就可以了。原因推测是,因为每次登录成功之后都会存redis,下次再请求,从redis中获取cookie发送请求。因为存redis中的cookie的过期时间跟网站的不一致,也就是网站本身对这个cookie已经失效了,而redis中还存有这个cookie。后来的解决办法是,一遇到这种报500就重新再登录一次。
(2)远程服务器返回错误: (600)
没有登录起,Cookie不对。
2.3代理IP的问题
报字符串格式不正确,这些报错信息有时候并不能说明什么问题,只有解决了这个问题之后,才能发现确实是这个问题。我的意思是,不一定请求过去报输入字符串格式不正确就是代理IP的问题。但是如果我一解决了代理IP的问题,这个报错就解决了。那么我推测是这就是代理IP引起的。
using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Business { /// <summary> /// HttpCallHelper /// </summary> public class HttpCallHelper { /// <summary> /// post /// </summary> /// <param name="param">param</param> /// <returns>HttpResultInfo</returns> public static HttpResultInfo Post(HttpRequestParams param) { HttpResultInfo res = null; try { param.RequestEncoding = Encoding.Default; byte[] bs = param.RequestEncoding.GetBytes(param.Data); HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(param.Url); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; req.ContentLength = bs.Length; if (!string.IsNullOrEmpty(param.Cookie)) { req.Headers[HttpRequestHeader.Cookie] = param.Cookie; } req.Referer = param.Cookie; using (Stream reqStream = req.GetRequestStream()) { reqStream.Write(bs, 0, bs.Length); } string strResponse = string.Empty; HttpWebResponse httpResponse = (HttpWebResponse)req.GetResponse(); using (Stream responseStream = httpResponse.GetResponseStream()) { Stream stream = responseStream; StreamReader streamReader = new StreamReader(stream, param.ResponseEncoding); strResponse = streamReader.ReadToEnd(); streamReader.Close(); } string retcookie = req.GetResponse().Headers["Set-Cookie"]; res = new HttpResultInfo() { Cookie = retcookie, StatusCode = httpResponse.StatusCode, StatusDescription = httpResponse.StatusDescription, Headers = httpResponse.Headers, ErrorMsg = string.Empty, Html = strResponse, ResponseUrl = httpResponse.ResponseUri, }; return res; } catch (Exception esx) { res = new HttpResultInfo() { ErrorMsg = esx.Message.ToString(), }; Console.WriteLine(esx.Message.ToString()); } return res; } /// <summary> /// Get /// </summary> /// <param name="httpParam">httpParam</param> /// <param name="param">param</param> /// <returns>结果</returns> public static HttpResultInfo Get(HttpRequestParams httpParam, Dictionary<string, string> param) { StringBuilder sb = new StringBuilder(); foreach (var item in param) { sb.AppendFormat("{0}={1}&", item.Key, item.Value); } httpParam.Data = sb.ToString(); return Get(httpParam); } /// <summary> /// Get /// </summary> /// <param name="param">param</param> /// <returns>结果</returns> public static HttpResultInfo Get(HttpRequestParams param) { HttpResultInfo ret = null; try { string strResult = string.Empty; HttpWebRequest httpRequest; HttpWebResponse httpResponse; string urlStr = param.Url; if (!string.IsNullOrEmpty(param.Data)) { urlStr = string.Format("{0}{1}", param.Url + "?", param.Data); } httpRequest = (HttpWebRequest)WebRequest.Create(new Uri(urlStr)); httpRequest.Timeout = param.Timeout; httpRequest.Method = "Get"; httpRequest.ContentType = param.ContentType; if (!string.IsNullOrEmpty(param.Cookie)) { httpRequest.Headers[HttpRequestHeader.Cookie] = param.Cookie; } //// 获取提交返回信息 httpResponse = (HttpWebResponse)httpRequest.GetResponse(); string returnStr = string.Empty; using (Stream st = httpResponse.GetResponseStream()) { returnStr = new StreamReader(st, param.ResponseEncoding).ReadToEnd(); } string cookie1 = httpResponse.Headers["Set-Cookie"]; ret = new HttpResultInfo() { Cookie = cookie1, StatusCode = httpResponse.StatusCode, StatusDescription = httpResponse.StatusDescription, Headers = httpResponse.Headers, ErrorMsg = string.Empty, Html = returnStr, ResponseUrl = httpResponse.ResponseUri, }; } catch (Exception ex) { Console.WriteLine(ex.ToString().ToString()); ret = new HttpResultInfo() { Html = string.Empty, ErrorMsg = ex.Message.ToString(), Cookie = string.Empty, }; } return ret; } /// <summary> /// GetQueryString /// </summary> /// <param name="param">param</param> /// <returns>结果</returns> public static string GetQueryString(Dictionary<string, string> param) { StringBuilder sb = new StringBuilder(); foreach (var item in param) { sb.AppendFormat("{0}={1}&", item.Key, item.Value); } if (sb.Length > 0) { sb = sb.Remove(sb.Length - 1, 1); } return sb.ToString(); } } /// <summary> /// 请求消息 /// </summary> public class HttpRequestParams { /// <summary> /// 请求编码 /// </summary> private Encoding requestEncoding = Encoding.Default; /// <summary> /// 响应编码 /// </summary> private Encoding responseEncoding = Encoding.Default; /// <summary> /// 请求超时时间(以毫秒为单位,默认180秒) /// </summary> private int timeout = 180000; /// <summary> /// 请求返回类型(默认text/html) /// </summary> private string contentType = "text/html"; /// <summary> /// HttpRequestParams /// </summary> public HttpRequestParams() { } /// <summary> /// 请求地址 /// </summary> public string Url { get; set; } /// <summary> /// 数据 /// </summary> public string Data { get; set; } /// <summary> /// Cookie /// </summary> public string Cookie { get; set; } /// <summary> /// ContentType /// </summary> public string ContentType { get { return this.contentType; } set { this.contentType = value; } } /// <summary> /// Referer /// </summary> public string Referer { get; set; } /// <summary> /// Timeout /// </summary> public int Timeout { get { return this.timeout; } set { this.timeout = value; } } /// <summary> /// RequestEncoding /// </summary> public Encoding RequestEncoding { get { return this.requestEncoding; } set { if (value == null) { throw new Exception("请求编码格式不能设置为空!"); } this.requestEncoding = value; } } /// <summary> /// 返回编码 /// </summary> public Encoding ResponseEncoding { get { return this.responseEncoding; } set { if (value == null) { throw new Exception("响应编码格式不能设置为空!"); } this.responseEncoding = value; } } } /// <summary> /// 返回消息 /// </summary> public class HttpResultInfo { /// <summary> /// Html /// </summary> public string Html { get; set; } /// <summary> /// Cookie /// </summary> public string Cookie { get; set; } /// <summary> /// IsSuccess /// </summary> public HttpStatusCode StatusCode { get; set; } /// <summary> /// ErrorMsg /// </summary> public string ErrorMsg { get; set; } /// <summary> /// 状态描述 /// </summary> public string StatusDescription { get; set; } /// <summary> /// 响应头 /// </summary> public WebHeaderCollection Headers { get; set; } /// <summary> /// 返回Uri /// </summary> public Uri ResponseUrl { get; set; } } }