1、对于网络请求,可先通过Chrome的F12调试模式分析网页接口规则,其Network的XHR可找到对应数据的请求链接,同时其使用的cookie也需要拿去到,程序模拟请求时也需要cookie才能能正常拿取到数据
a.若直接输入该链接可获得数据,则建立如下公用方法:
public static string Request(string url, string cookie) //设置通用方法
{
using (WebClient w = new WebClient())
{
w.Encoding = Encoding.GetEncoding("utf-8");
w.Headers.Add("ContentType", "application/json; charset=utf-8");
w.Headers.Add("Accept", "application/json, text/javascript, */*; q=0.01");
w.Headers.Add("UserAgent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36");
w.Headers.Add("Cookie", cookie);
return w.DownloadString(url);
}
}
b.若请求方式为post则建立如下公用方法:
public static string Post(string url, string cookie, string data)
{
using (WebClient w = new WebClient())
{
w.Encoding = Encoding.GetEncoding("utf-8");
w.Headers.Add("ContentType", "application/json");
w.Headers.Add("Accept", "application/json, text/javascript, */*; q=0.01");
w.Headers.Add("UserAgent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36");
w.Headers.Add("Cookie", cookie);
byte[] postData = Encoding.UTF8.GetBytes(data);
byte[] response = w.UploadData(url, "POST", postData);
string r = Encoding.UTF8.GetString(response);
return r;
}
}
c.还有部分网站禁止使用程序直接调用接口,此时就需要模拟浏览器进行操作
首先需要在前端创建一个Webview控件,当某业务需要进行模拟操作时显示该浏览器,操作如下:
//设该浏览器控件名称为WebView
WebView.Visibility = Visibility.Visible;
WebView.Navigate(new Uri("http://www.baidu.com"));
WebView.NavigationCompleted += NavigationCompletedAsync; //网页加载成功后进行指定操作
当浏览器成功加载某网站后,在NavigationCompletedAsync进行指定操作:登录、获取数据
这里需要运用一些简单的前端知识,可以在调试模式中的Console先使用前端代码测试成功后,再放入后端代码里
注意:
①有些网站可能要求输入验证码,这里可让程序检测到验证码后不进行任何操作,由人工处理,当跳转到指定网页后会自动触发一次NavigationCompletedAsync
②部分网站的页面可能本身存在多次刷新的情况,获取数据时请注意进行去重
private async void NavigationCompletedAsync(WebView sender, WebViewNavigationCompletedEventArgs args)
{
try
{
if (args.Uri.ToString().Equals(loginPage)) //如果加载登录页则进行登录
{
string js = "document.getElementById('email').value='" + account + "';";
js += "document.getElementById('password').value='" + pwd + "';";
js += "document.getElementById('id_remember_user').checked=true;";
await WebView.InvokeScriptAsync("eval", new string[] { js });
js = @"document.getElementById('submit').click();";
await WebView.InvokeScriptAsync("eval", new string[] { js });
}
else //非登录页模拟AJAX直接拿数据
{
string js = "var result = '';";
js += "$.ajax({url:'http://www.baidu.com/xxx',context:document.body,
async:false,success: function(data){ result = data; }});";
js += "JSON.stringify(result);"; //一定要转换成JSON,UWP才能接收到数据
string result = await WebView.InvokeScriptAsync("eval", new string[] { js });
}
WebView.Visibility = Visibility.Collapsed;
}
catch (Exception ex) { ResultText.Text = ex.ToString(); }
}
2、网络数据处理上,最好处理的莫过json数据,部分网站返回HTML代码则需要针对性处理
a.JSON数据,直接使用Newtonsoft组件即可
T t = JsonConvert.DeserializeObject<T>(result);
b.HTML代码的场景中,设某网站返回数据格式:<tr>A<\/tr><tr>B<\/tr>,我们希望获取A、B,则可用正则进行快捷提取
string s = "对应字符串";
List<string> result = new List<string>(); //最终将A、B装入result
Regex rex = new Regex("(?<=<tr>).*?(?=<\\\\/tr>)"); // ?<=E代表获取E后面的部分,?=E代表获取E前面的部分,正则中普通“\”需要通过“\\”转义,而C#又要求对“\”再转义,所以就有4个“\”
MatchCollection m = rex.Matches(s); //匹配<tr>标签的结果集
foreach(KeyValuePair<string, string> i in GlobalPara.Country)
for (int j = 0; j < m.Count; j++) result.Add(rowData[j].Value);
3、数据获取后若需要数据求和,则不影响计算性能的情况下可用泛型+反射的思路搞定。设对象只需对int或float类型的字段求和,则建立如下通用方法:
public static void SumData<S>(List<S> s, S result) //s为数据列表,result为求和结果
{
if (s == null || s.Count == 0) throw new Exception("数据汇总方法调用错误:空数据源");
else
{
foreach (var i in s)
{
Type t = result.GetType //获取对象
FieldInfo[] fieldList = t.GetFields(); //获取对象下所有字段
foreach (FieldInfo j in fieldList) //依次遍历字段
{
if (j.FieldType == typeof(int) || j.FieldType == typeof(float)) //只要int、float类型的字段
{
float exValue = Convert.ToSingle(result.GetType().GetField(j.Name).GetValue(result)); //先统一转换为小数计算
float addValue = Convert.ToSingle(j.GetValue(i)); //当前数据对象中该字段值
float value = exValue + addValue; //求和
result.GetType().GetField(j.Name).SetValue(result, Convert.ChangeType(value, j.FieldType));//最后赋值并转换类型
}
}
}
}
}
调用方式如下:
List<Data> list = ...
Data result = new Data();
Common.SumData<Data>(list, result);