你們能夠先看下這篇文章,將微博或者qq空間的說說同步至博客園 wcf+js(ajax)跨域請求(1),在該文裏面,對使用javascript調用wcf到我本機取數據做了介紹。不過吐槽一下,該文發佈沒多久,就被博客園移除首頁了,博主但是花了五個小時調試代碼,部署環境。最後太晚了,因此文章寫得倉促了點。文章寫得不咋滴。大概是博客園管理認爲我沒寫完,因此移除了首頁。博主可真是冤枉。最後這一系列文章寫完,博主會從新詳細寫一下如何經過javascript調用wcf。廢話很少說。咱們今天來看一下,如何在本地去qq空間的數據。javascript
剛開始博主的思路是寫一個Chrome擴展,而後每次當我打開空間的時候自動記錄數據到本地。後來感受javascript操做數據很不方便,便決定仍是使用C#來取數據。html
另外先透漏一下,從qq空間取數據到博客園後博主的思路。博主打算使用Knockout組件的形式在博客園渲染頁面。因此如今把qq空間同步至博客園這個工程大概有如下三步。一是本地服務端取數據存儲到數據庫。二是經過javascript調用wcf將數據傳輸到博客園,最後是使用KnockOut將數據渲染至頁面。java
另:博主本打算模擬qq空間登陸的方式來取數據。不過qq空間登陸的模塊是使用插件的形式登陸的。瞭解其機制代價太大。因此決定經過下面這種方式取數據。python
另:如今頁面上還看不到效果。最後一步使用KnockOut將數據渲染至頁面博主還沒開始準備。如今咱們開始到qq空間取數據。ajax
咱們仔細觀察下qq空間首頁,會發現qq空間所有動態那兒有個刷新的按鈕sql
點擊此處會異步去qq服務器取數據。以下圖chrome
咱們將該連接訪問如下。數據庫
http://user.qzone.qq.com/p/ic2.s51/cgi-bin/feeds/feeds3_html_more?uin=11******88&scope=0&view=1&daylist=&uinlist=&gid=&flag=1&filter=all&applist=all&refresh=0&aisortEndTime=0&aisortOffset=0&getAisort=0&aisortBeginTime=0&pagenum=2&externparam=basetime%3D1428817036%26pagenum%3D2%26dayvalue%3D0&firstGetGroup=0&icServerTime=0&mixnocache=0&scene=0&begintime=1428817036&count=10&dayspac=0&sidomain=cm.qzonestyle.gtimg.cn&useutf8=1&outputhtmlfeed=1&rd=0.1990418911445886&g_tk=1385204724json
如上所示,能夠經過這樣取到咱們須要的json數據。c#
那麼問題來了。咱們若是要使用System.Net該類庫提供的服務來模擬http請求報文,都須要什麼條件麼。毫無疑問,在這兒須要的是,一個是get請求的url,包括該get請求傳遞過去的參數。以及報文發送時隨報文發送的cookie.
需求已經明瞭。咱們須要獲得get參數,以及發送的cookie.
觀察上面我發佈get連接。首先最想說的是,這參數也太**多了。不過沒問題。咱們多對比幾回就會發現,上面的大部分參數都是不怎麼變化的。其中一個begintime參數,博主試了下並無多大的影響。幾經確認,發現該get請求最重要的參數只有一個,那就是g_tk參數。該參數和cookie幾乎決定了咱們請求數據的成敗。那麼該參數究竟是在哪兒來的呢。
要想知道該參數怎麼來的,咱們就要知道當咱們點擊刷新的時候,javascript函數到底作了什麼。怎樣生成的ajax請求呢。那麼咱們就須要知道當咱們點擊該刷新按鈕的時候執行的是什麼函數,也就是該按鈕到底和哪一個javascript函數綁定。那麼問題來了----如何找到dom元素綁定的函數呢。咱們首先在chrome瀏覽器下f12調試。
以下圖
博主在這兒找了半天,也沒找到有用的信息,不過幸虧博主找到了一個神器
該插件能夠提供讓咱們看dom元素綁定函數的功能,雖然說有些限制,不過在這兒確實發揮了做用。
既然找到了該函數調用的函數,那麼順藤摸瓜。博主找到了下面這個函數。
pingCgi: function () { var a = "http://" + g_R_Domain + "/cgi-bin/user/qzone_cgi_msg_getcnt2"; setInterval(function () { QZFL.pingSender(a + "?uin=" + g_iLoginUin + "&bm=" + g_LoginBitmap + "&v=" + c.getCGISeed("_QZN_TodoMsgCnt") + "&g_tk=" + QZONE.FrontPage.getACSRFToken() + "&g=" + Math.random(), 0) }, 6E5) }
顯然g_tk是經過QZONE.FrontPage.getACSRFToken()這個函數生成的。咱們繼續找到該函數。
QZONE.FrontPage.getACSRFToken = function (a) { a = QZFL.util.URI(a); var b; a && (a.host && 0 < a.host.indexOf("qzone.qq.com") ? b = QZFL.cookie.get("p_skey") : a.host && 0 < a.host.indexOf("qq.com") && (b = QZFL.cookie.get("skey"))); b || (b = QZFL.cookie.get("skey") || QZFL.cookie.get("rv2")); a = 5381; for (var c = 0, d = b.length; c < d; ++c) a += (a << 5) + b.charAt(c).charCodeAt(); return a & 2147483647 };
找到了個函數那麼問題就清楚了。該函數調用了cookie裏面的P_skey參數來生成了該g_tk. 咱們可使用C#來重寫該javascript函數。
public string getg_tk(string str) { var b = str; var a = 5381; for (int c = 0, d = b.Length; c < d; ++c)
//這兒是javascript代碼的c#實現。b[c]取到字符串在c索引處的字符。強轉爲int既是將char轉爲Unicode a += (a << 5) + (int)b[c]; return (a & 2147483647).ToString(); }
以後咱們傳入cookie裏面的p_skey=rK6xJHZPMWUxBj6ehdS5CoILGC8aMt7EPEgNYVRBbRU_;會發現生成的g_tk和咱們用來調用的g_tk=1385204724相等。以下圖。
如今解決了get參數的問題,咱們再來解決咱們的cookie問題。
咱們找到chrome cookie所在的文件夾。
使用notepad打開,會發現是亂碼。這是由於chrome後來版本的cookie都是經過加密後存儲到了sqlite數據庫裏面。
爲咱們的項目添加以下引用。同時在咱們項目的bin問價夾下添加SQLite.Interop.dll類庫。
咱們添加一個sqllitehelper幫助類。
//添加一個靜態幫助類
public static class SqlLiteHelper { public static DataTable ExecuteSql(System.Data.IDbConnection connection, string sql) { var cmd = connection.CreateCommand(); cmd.CommandText = sql; using (var reader = cmd.ExecuteReader()) { var dataTable = new DataTable(); dataTable.Load(reader); return dataTable; } } }
//這是sqllite數據庫的鏈接字符串
string connectionString = @"Data Source=C:\Documents and Settings\wfm\Local Settings\Application Data\Google\Chrome\User Data\Default\Cookies";
//使用using用來釋放非託管資源,垃圾回收。 using (var conn = new System.Data.SQLite.SQLiteConnection(connectionString)) { conn.Open(); DataTable db = SqlLiteHelper.ExecuteSql(conn, "select host_key,name,value,encrypted_value from cookies;"); }
使用上面的代碼咱們就可取到sqllite數據庫的數據。
如上圖取到cookie的數據後咱們會發現取到的value值是空的,同時有一個encrypted_value的byte數組.隨便google一下咱們就知道這是chrome新版本里面存儲的cookie數據。不過被chrome加密了。那麼如今咱們就須要解密cookie.如何解密,博主其實一點也不會。不過幸虧有大神會。搜索相關資源,咱們知道須要用到
crypt32.dll下的CryptUnprotectData函數來解密。咱們尋找資源會發現相關的資料都是使用Python實現的。並無c#下面的代碼能夠拿來直接用。相關鏈接以下
Chrome 33+瀏覽器 Cookies encrypted_value解密腳本(python實現),還有一些其它相似的資料。這裏就不列出了。
咱們新建一個類DPAPI相關代碼以下。
/////////////////////////////////////////////////////////////////////////////// // SAMPLE: Encryption and decryption using DPAPI functions. // // To run this sample, create a new Visual C# project using the Console // Application template and replace the contents of the Class1.cs file // with the code below. // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR // PURPOSE. // // Copyright (C) 2003 Obviex(TM). All rights reserved. // using System; using System.Text; using System.Runtime.InteropServices; using System.ComponentModel; /// <summary> /// Encrypts and decrypts data using DPAPI functions. /// </summary> public class DPAPI { // Wrapper for DPAPI CryptProtectData function. [DllImport("crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] private static extern bool CryptProtectData(ref DATA_BLOB pPlainText, string szDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pCipherText); // Wrapper for DPAPI CryptUnprotectData function. [DllImport("crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] private static extern bool CryptUnprotectData(ref DATA_BLOB pCipherText, ref string pszDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pPlainText); // BLOB structure used to pass data to DPAPI functions. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct DATA_BLOB { public int cbData; public IntPtr pbData; } // Prompt structure to be used for required parameters. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct CRYPTPROTECT_PROMPTSTRUCT { public int cbSize; public int dwPromptFlags; public IntPtr hwndApp; public string szPrompt; } // Wrapper for the NULL handle or pointer. static private IntPtr NullPtr = ((IntPtr)((int)(0))); // DPAPI key initialization flags. private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1; private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4; /// <summary> /// Initializes empty prompt structure. /// </summary> /// <param name="ps"> /// Prompt parameter (which we do not actually need). /// </param> private static void InitPrompt(ref CRYPTPROTECT_PROMPTSTRUCT ps) { ps.cbSize = Marshal.SizeOf( typeof(CRYPTPROTECT_PROMPTSTRUCT)); ps.dwPromptFlags = 0; ps.hwndApp = NullPtr; ps.szPrompt = null; } /// <summary> /// Initializes a BLOB structure from a byte array. /// </summary> /// <param name="data"> /// Original data in a byte array format. /// </param> /// <param name="blob"> /// Returned blob structure. /// </param> private static void InitBLOB(byte[] data, ref DATA_BLOB blob) { // Use empty array for null parameter. if (data == null) data = new byte[0]; // Allocate memory for the BLOB data. blob.pbData = Marshal.AllocHGlobal(data.Length); // Make sure that memory allocation was successful. if (blob.pbData == IntPtr.Zero) throw new Exception( "Unable to allocate data buffer for BLOB structure."); // Specify number of bytes in the BLOB. blob.cbData = data.Length; // Copy data from original source to the BLOB structure. Marshal.Copy(data, 0, blob.pbData, data.Length); } // Flag indicating the type of key. DPAPI terminology refers to // key types as user store or machine store. public enum KeyType { UserKey = 1, MachineKey }; // It is reasonable to set default key type to user key. private static KeyType defaultKeyType = KeyType.UserKey; /// <summary> /// Calls DPAPI CryptProtectData function to encrypt a plaintext /// string value with a user-specific key. This function does not /// specify data description and additional entropy. /// </summary> /// <param name="plainText"> /// Plaintext data to be encrypted. /// </param> /// <returns> /// Encrypted value in a base64-encoded format. /// </returns> public static string Encrypt(string plainText) { return Encrypt(defaultKeyType, plainText, String.Empty, String.Empty); } /// <summary> /// Calls DPAPI CryptProtectData function to encrypt a plaintext /// string value. This function does not specify data description /// and additional entropy. /// </summary> /// <param name="keyType"> /// Defines type of encryption key to use. When user key is /// specified, any application running under the same user account /// as the one making this call, will be able to decrypt data. /// Machine key will allow any application running on the same /// computer where data were encrypted to perform decryption. /// Note: If optional entropy is specifed, it will be required /// for decryption. /// </param> /// <param name="plainText"> /// Plaintext data to be encrypted. /// </param> /// <returns> /// Encrypted value in a base64-encoded format. /// </returns> public static string Encrypt(KeyType keyType, string plainText) { return Encrypt(keyType, plainText, String.Empty, String.Empty); } /// <summary> /// Calls DPAPI CryptProtectData function to encrypt a plaintext /// string value. This function does not specify data description. /// </summary> /// <param name="keyType"> /// Defines type of encryption key to use. When user key is /// specified, any application running under the same user account /// as the one making this call, will be able to decrypt data. /// Machine key will allow any application running on the same /// computer where data were encrypted to perform decryption. /// Note: If optional entropy is specifed, it will be required /// for decryption. /// </param> /// <param name="plainText"> /// Plaintext data to be encrypted. /// </param> /// <param name="entropy"> /// Optional entropy which - if specified - will be required to /// perform decryption. /// </param> /// <returns> /// Encrypted value in a base64-encoded format. /// </returns> public static string Encrypt(KeyType keyType, string plainText, string entropy) { return Encrypt(keyType, plainText, entropy, String.Empty); } /// <summary> /// Calls DPAPI CryptProtectData function to encrypt a plaintext /// string value. /// </summary> /// <param name="keyType"> /// Defines type of encryption key to use. When user key is /// specified, any application running under the same user account /// as the one making this call, will be able to decrypt data. /// Machine key will allow any application running on the same /// computer where data were encrypted to perform decryption. /// Note: If optional entropy is specifed, it will be required /// for decryption. /// </param> /// <param name="plainText"> /// Plaintext data to be encrypted. /// </param> /// <param name="entropy"> /// Optional entropy which - if specified - will be required to /// perform decryption. /// </param> /// <param name="description"> /// Optional description of data to be encrypted. If this value is /// specified, it will be stored along with encrypted data and /// returned as a separate value during decryption. /// </param> /// <returns> /// Encrypted value in a base64-encoded format. /// </returns> public static string Encrypt(KeyType keyType, string plainText, string entropy, string description) { // Make sure that parameters are valid. if (plainText == null) plainText = String.Empty; if (entropy == null) entropy = String.Empty; // Call encryption routine and convert returned bytes into // a base64-encoded value. return Convert.ToBase64String( Encrypt(keyType, Encoding.UTF8.GetBytes(plainText), Encoding.UTF8.GetBytes(entropy), description)); } /// <summary> /// Calls DPAPI CryptProtectData function to encrypt an array of /// plaintext bytes. /// </summary> /// <param name="keyType"> /// Defines type of encryption key to use. When user key is /// specified, any application running under the same user account /// as the one making this call, will be able to decrypt data. /// Machine key will allow any application running on the same /// computer where data were encrypted to perform decryption. /// Note: If optional entropy is specifed, it will be required /// for decryption. /// </param> /// <param name="plainTextBytes"> /// Plaintext data to be encrypted. /// </param> /// <param name="entropyBytes"> /// Optional entropy which - if specified - will be required to /// perform decryption. /// </param> /// <param name="description"> /// Optional description of data to be encrypted. If this value is /// specified, it will be stored along with encrypted data and /// returned as a separate value during decryption. /// </param> /// <returns> /// Encrypted value. /// </returns> public static byte[] Encrypt(KeyType keyType, byte[] plainTextBytes, byte[] entropyBytes, string description) { // Make sure that parameters are valid. if (plainTextBytes == null) plainTextBytes = new byte[0]; if (entropyBytes == null) entropyBytes = new byte[0]; if (description == null) description = String.Empty; // Create BLOBs to hold data. DATA_BLOB plainTextBlob = new DATA_BLOB(); DATA_BLOB cipherTextBlob = new DATA_BLOB(); DATA_BLOB entropyBlob = new DATA_BLOB(); // We only need prompt structure because it is a required // parameter. CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT(); InitPrompt(ref prompt); try { // Convert plaintext bytes into a BLOB structure. try { InitBLOB(plainTextBytes, ref plainTextBlob); } catch (Exception ex) { throw new Exception( "Cannot initialize plaintext BLOB.", ex); } // Convert entropy bytes into a BLOB structure. try { InitBLOB(entropyBytes, ref entropyBlob); } catch (Exception ex) { throw new Exception( "Cannot initialize entropy BLOB.", ex); } // Disable any types of UI. int flags = CRYPTPROTECT_UI_FORBIDDEN; // When using machine-specific key, set up machine flag. if (keyType == KeyType.MachineKey) flags |= CRYPTPROTECT_LOCAL_MACHINE; // Call DPAPI to encrypt data. bool success = CryptProtectData(ref plainTextBlob, description, ref entropyBlob, IntPtr.Zero, ref prompt, flags, ref cipherTextBlob); // Check the result. if (!success) { // If operation failed, retrieve last Win32 error. int errCode = Marshal.GetLastWin32Error(); // Win32Exception will contain error message corresponding // to the Windows error code. throw new Exception( "CryptProtectData failed.", new Win32Exception(errCode)); } // Allocate memory to hold ciphertext. byte[] cipherTextBytes = new byte[cipherTextBlob.cbData]; // Copy ciphertext from the BLOB to a byte array. Marshal.Copy(cipherTextBlob.pbData, cipherTextBytes, 0, cipherTextBlob.cbData); // Return the result. return cipherTextBytes; } catch (Exception ex) { throw new Exception("DPAPI was unable to encrypt data.", ex); } // Free all memory allocated for BLOBs. finally { if (plainTextBlob.pbData != IntPtr.Zero) Marshal.FreeHGlobal(plainTextBlob.pbData); if (cipherTextBlob.pbData != IntPtr.Zero) Marshal.FreeHGlobal(cipherTextBlob.pbData); if (entropyBlob.pbData != IntPtr.Zero) Marshal.FreeHGlobal(entropyBlob.pbData); } } /// <summary> /// Calls DPAPI CryptUnprotectData to decrypt ciphertext bytes. /// This function does not use additional entropy and does not /// return data description. /// </summary> /// <param name="cipherText"> /// Encrypted data formatted as a base64-encoded string. /// </param> /// <returns> /// Decrypted data returned as a UTF-8 string. /// </returns> /// <remarks> /// When decrypting data, it is not necessary to specify which /// type of encryption key to use: user-specific or /// machine-specific; DPAPI will figure it out by looking at /// the signature of encrypted data. /// </remarks> public static string Decrypt(string cipherText) { string description; return Decrypt(cipherText, String.Empty, out description); } /// <summary> /// Calls DPAPI CryptUnprotectData to decrypt ciphertext bytes. /// This function does not use additional entropy. /// </summary> /// <param name="cipherText"> /// Encrypted data formatted as a base64-encoded string. /// </param> /// <param name="description"> /// Returned description of data specified during encryption. /// </param> /// <returns> /// Decrypted data returned as a UTF-8 string. /// </returns> /// <remarks> /// When decrypting data, it is not necessary to specify which /// type of encryption key to use: user-specific or /// machine-specific; DPAPI will figure it out by looking at /// the signature of encrypted data. /// </remarks> public static string Decrypt(string cipherText, out string description) { return Decrypt(cipherText, String.Empty, out description); } /// <summary> /// Calls DPAPI CryptUnprotectData to decrypt ciphertext bytes. /// </summary> /// <param name="cipherText"> /// Encrypted data formatted as a base64-encoded string. /// </param> /// <param name="entropy"> /// Optional entropy, which is required if it was specified during /// encryption. /// </param> /// <param name="description"> /// Returned description of data specified during encryption. /// </param> /// <returns> /// Decrypted data returned as a UTF-8 string. /// </returns> /// <remarks> /// When decrypting data, it is not necessary to specify which /// type of encryption key to use: user-specific or /// machine-specific; DPAPI will figure it out by looking at /// the signature of encrypted data. /// </remarks> public static string Decrypt(string cipherText, string entropy, out string description) { // Make sure that parameters are valid. if (entropy == null) entropy = String.Empty; return Encoding.UTF8.GetString( Decrypt(Convert.FromBase64String(cipherText), Encoding.UTF8.GetBytes(entropy), out description)); } /// <summary> /// Calls DPAPI CryptUnprotectData to decrypt ciphertext bytes. /// </summary> /// <param name="cipherTextBytes"> /// Encrypted data. /// </param> /// <param name="entropyBytes"> /// Optional entropy, which is required if it was specified during /// encryption. /// </param> /// <param name="description"> /// Returned description of data specified during encryption. /// </param> /// <returns> /// Decrypted data bytes. /// </returns> /// <remarks> /// When decrypting data, it is not necessary to specify which /// type of encryption key to use: user-specific or /// machine-specific; DPAPI will figure it out by looking at /// the signature of encrypted data. /// </remarks> public static byte[] Decrypt(byte[] cipherTextBytes, byte[] entropyBytes, out string description) { // Create BLOBs to hold data. DATA_BLOB plainTextBlob = new DATA_BLOB(); DATA_BLOB cipherTextBlob = new DATA_BLOB(); DATA_BLOB entropyBlob = new DATA_BLOB(); // We only need prompt structure because it is a required // parameter. CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT(); InitPrompt(ref prompt); // Initialize description string. description = String.Empty; try { // Convert ciphertext bytes into a BLOB structure. try { InitBLOB(cipherTextBytes, ref cipherTextBlob); } catch (Exception ex) { throw new Exception( "Cannot initialize ciphertext BLOB.", ex); } // Convert entropy bytes into a BLOB structure. try { InitBLOB(entropyBytes, ref entropyBlob); } catch (Exception ex) { throw new Exception( "Cannot initialize entropy BLOB.", ex); } // Disable any types of UI. CryptUnprotectData does not // mention CRYPTPROTECT_LOCAL_MACHINE flag in the list of // supported flags so we will not set it up. int flags = CRYPTPROTECT_UI_FORBIDDEN; // Call DPAPI to decrypt data. bool success = CryptUnprotectData(ref cipherTextBlob, ref description, ref entropyBlob, IntPtr.Zero, ref prompt, flags, ref plainTextBlob); // Check the result. if (!success) { // If operation failed, retrieve last Win32 error. int errCode = Marshal.GetLastWin32Error(); // Win32Exception will contain error message corresponding // to the Windows error code. throw new Exception( "CryptUnprotectData failed.", new Win32Exception(errCode)); } // Allocate memory to hold plaintext. byte[] plainTextBytes = new byte[plainTextBlob.cbData]; // Copy ciphertext from the BLOB to a byte array. Marshal.Copy(plainTextBlob.pbData, plainTextBytes, 0, plainTextBlob.cbData); // Return the result. return plainTextBytes; } catch (Exception ex) { throw new Exception("DPAPI was unable to decrypt data.", ex); } // Free all memory allocated for BLOBs. finally { if (plainTextBlob.pbData != IntPtr.Zero) Marshal.FreeHGlobal(plainTextBlob.pbData); if (cipherTextBlob.pbData != IntPtr.Zero) Marshal.FreeHGlobal(cipherTextBlob.pbData); if (entropyBlob.pbData != IntPtr.Zero) Marshal.FreeHGlobal(entropyBlob.pbData); } } }
咱們能夠經過以下調用解密cookie:
Encrypted_value = DPAPI.Decrypt(Convert.ToBase64String(cookieContent))
如今關於模擬http報文請求的條件已經都準備好了。
使用System.net類庫模擬http請求報文
HttpResponseParameter responseParameter1 = httpProvider.Excute(new HttpRequestParameter { Url = "http://user.qzone.qq.com/p/ic2.s51/cgi-bin/feeds/feeds3_html_more?uin=11******88&scope=0&view=1&daylist=&uinlist=&gid=&flag=1&filter=all&applist=all&refresh=0&aisortEndTime=0&aisortOffset=0&getAisort=0&aisortBeginTime=0&pagenum=2&externparam=basetime%3D1428810895%26pagenum%3D2%26dayvalue%3D0&firstGetGroup=0&icServerTime=0&mixnocache=0&scene=0&begintime=1428810895&count=10&dayspac=0&sidomain=cm.qzonestyle.gtimg.cn&useutf8=1&outputhtmlfeed=1&rd=0.9383603150490671&g_tk=" + getg_tk(GetCookieStr("p_skey").Split('=')[1].Replace(";", "")), IsPost = false, Encoding = Encoding.UTF8, Cookie = new HttpCookieType() { CookieCollection = addCookieToContainer(cookieSend) } });
注意上面我使用了一個類庫,也是園子裏的一位大神寫的,你們能夠本身去下載。
.Net(c#)模擬Http請求之HttpWebRequest封裝
如今,全部的難點咱們都一一解決了。如今咱們運行代碼
OK,咱們須要的數據都取到了。可是注意一個問題,取數據的時候只有咱們登錄qq空間也就是qq空間的cookie有效的時候才能夠取到數據。
如今咱們能夠將數據存儲到數據。等待javascript調用wcf來讀取數據
本文地址:http://www.cnblogs.com/santian/p/4420877.html
博客地址:http://www.cnblogs.com/santian/