前言:javascript
最近在作中國移動爬蟲的過程當中,首先遇到的就是 在某個請求中,有一個名爲「WT_PFC"的cookie鍵值是由前端JavaScript生成的,沒有進入到HttpWebResponse中。事實上,C#不會去執行客戶端腳本 ,用到的HttpWebRequest不是一個真正意義上的web瀏覽器,它只會下載它所請求的地址的html信息,它永遠不會去執行JavaScript或者ajax,同時WebClient這個類間接地也是調用了HttpWebRequest來請求的,因此結論是一致的。html
可是因爲其餘的請求的Request須要Sent該Cookie,因此查了不少資料,基本上只能 從新構建 js 算法 或者使用 WebBrowser自動去執行頁面js前端
IHTMLWindow2 win = (IHTMLWindow2)webBrowser1.Document.Window.DomWindow; string s = @"function confirm() {"; s += @"return true;"; s += @"}"; s += @"function alert() {}"; win.execScript(s, "javascript");
, 但這些都不是最好最快的方法。我採用的是如下的java
C# 代碼動態編譯JavaScript代碼的方式得出 JavaScript函數被調用以後的 返回值。web
1.Cookie(WT_FPC):ajax
2. 經過HttpWatch查到的生成該cookie的js代碼,我提煉出了生成該Cookie的方法,並按格式寫成以下形式:算法
public static function GetWT_FPC(){ var $t = "2"; var $u = new Date(); var $v = new Date($u.getTime() + 315360000000); var $w = new Date($u.getTime()); if ($t.length < 10) { var $x = $u.getTime().toString(); for (var i = 2; i <= (32 - $x.length); i++) $t += Math.floor(Math.random() * 16.0).toString(16); $t += $x; }; $t = encodeURIComponent($t); return "WT_FPC=id=" + $t + ":lv=" + $u.getTime().toString() + ":ss=" + $w.getTime().toString() ; };
請注意:請按以上的格式書寫 腳本函數,即加上"public static ". 方法體不用動。瀏覽器
3.JsHelper(動態編譯Js代碼):服務器
我把上面js代碼放到本地"WT_FPC.js"文件中cookie
public static class JsHelper { /// <summary> /// 執行JS方法 /// </summary> /// <param name="methodName">方法名</param> /// <param name="para">參數</param> /// <returns></returns> public static string GetJsMethd(string methodName, object[] para) { string path = AppDomain.CurrentDomain.BaseDirectory + "WT_FPC.js"; string str2 = File.ReadAllText(path); StringBuilder sb = new StringBuilder(); sb.Append("package aa{"); sb.Append(" public class JScript {"); sb.Append(str2); sb.Append("}}"); CompilerParameters parameters = new CompilerParameters(); parameters.GenerateInMemory = true; CodeDomProvider _provider = new Microsoft.JScript.JScriptCodeProvider(); CompilerResults results = _provider.CompileAssemblyFromSource(parameters, sb.ToString()); Assembly assembly = results.CompiledAssembly; Type _evaluateType = assembly.GetType("aa.JScript"); object obj = _evaluateType.InvokeMember("GetWT_FPC", BindingFlags.InvokeMethod, null, null, para); return obj.ToString(); } }
注意:以上的helper代碼若是報錯的話,99%都是因爲 Js代碼的問題,即js代碼不規範或者 變量缺乏定義之類。
4. C#代碼調用helper得到執行結果
//設置Cookie"WT_FPC" string wt_fpc = JsHelper.GetJsMethd("GetWT_FPC", null); CookieCollection hcc = new CookieCollection(); Cookie wtcookie = new Cookie() { Expires = DateTime.Now.AddYears(10), Path = "/", Domain = ".10086.cn", Name = "WT_FPC", Value = wt_fpc.Substring(wt_fpc.IndexOf('=') + 1, wt_fpc.Length - 7)// }; hcc.Add(wtcookie); HttpHelperNew.cookie.Add(wtcookie);
5. 小經驗: 有時候 JavaScript前端生成的cookie,有時候 服務器端並不 校驗,也就是,若是把這個cookie值不經過js代碼動態獲得,直接 寫死的話 也應該能夠。
6. 其餘:
一:若是須要用C#執行前端js 函數計算的結果,好比 前端js的加密結果,在能找到js代碼前提下,能夠把js寫在本地的html 頁面裏面,而後C#代碼去訪問 便可。so easy!
二: Java 中使用WebClient獲取js執行完返回的值。
try{ WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24); //設置webClient的相關參數 webClient.getOptions().setJavaScriptEnabled(true); webClient.getOptions().setCssEnabled(false); webClient.setAjaxController(new NicelyResynchronizingAjaxController()); //webClient.getOptions().setTimeout(50000); webClient.getOptions().setThrowExceptionOnScriptError(false); //模擬瀏覽器打開一個目標網址 HtmlPage rootPage= webClient.getPage(url); System.out.println("爲了獲取js執行的數據 線程開始沉睡等待"); Thread.sleep(3000);//主要是這個線程的等待 由於js加載也是須要時間的 System.out.println("線程結束沉睡"); String html = rootPage.asText(); System.out.println(html); }catch(Exception e){ }