[c#] WebQQ群發限制的突破[續]


  持久的毅力是事業成功的基礎

上一篇《WebQQ群發限制的突破》講到了基本的消息發送,但是后面沒講完,結果很多朋友就在那里犯迷糊了,說是突破WebQQ群發的限制,卻說了一大堆與突破沒關系的廢話。所以,今天趁着有時間,還是好好補充一下上篇文章沒講完的地方。

 針對發送好友消息沒有實際收到的解決辦法

       可能由於網絡原因,或者Tx的關鍵詞屏蔽功能,使得有些字詞或句子無法發送出去,這就要測試一下web3.qq.com本身到底屏蔽了哪些字詞,好對症下葯。如果我們確實必須要發送這樣一些被屏蔽掉的字詞該怎么做呢?對了,通過將文字轉換成圖片。就可以發送了。但是,在WebQQ里要想發送圖片,對於剛入門WebQQ的新手來說談何容易,可能你對WebQQ的登錄,或是發送消息,已經可以做到熟能生巧,但是發送圖片這一塊很多人可能會卡住。

     在WebQQ里發送圖片給好友,其實分為兩部分:上傳圖片到TX指定服務器,上傳之后得到一個圖片的guid和一些其他參數,作為發送的參數再發送。

    上傳圖片,我們需要改變一下http請求的正文類型(CntentType)為multipart/form-data,並且加上一個分隔符號,這個豐富好可以自己定,但是一定要能將前后兩段文本完整的區分開來。對於請求頭參數構造,我們單獨作為一個方法,將構造好的結果返回到一個字典里,供請求方法調用。

 

View Code
 /// <summary>
      /// 本文自博客園原創,轉載請加上此鏈接
      /// http://www.cnblogs.com/uu102
      /// </summary>
      /// <param name="fileName"></param>
      /// <returns></returns>
        public string Upload_Offline_Pic(string fileName)
        {   
            string timeStamp = Util.GetTimestamp(DateTime.Now).ToString();
            String time = DateTime.Now.Ticks.ToString("x");
            string url = string.Format("http://weboffline.ftn.qq.com/ftn_access/upload_offline_pic?time={0}", timeStamp);
            string skeys = QQGlobal.ACCountManager[this.Uin].CookieString.Substring(QQGlobal.ACCountManager[this.Uin].CookieString.IndexOf("skey=") + 5, 10);
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("callback", "parent.EQQ.Model.ChatMsg.callbackSendPic");
            dic.Add("locallangid", "2052");
            dic.Add("clientversion", "1409");
            dic.Add("uin", this.Uin);
            dic.Add("skey", skeys);
            dic.Add("appid", "15000101");
            dic.Add("peeruin", "593023668");
            dic.Add("fileid", this.fileId.ToString());
            dic.Add("vfwebqq", QQGlobal.ACCountManager[this.Uin].Vfwebqq);
            dic.Add("senderviplevel", "0");
            dic.Add("reciverviplevel", "0");
            this.fileId++;
            string imagePath = new Regex(@"""filepath"":""(?'filepath'[^\""]+)""").Match(SubmitData(url, fileName, dic)).Groups["filepath"].Value.Replace("\\", "");
           string shortfilename = fileName.Substring(fileName.LastIndexOf("\\") + 1, fileName.Length - fileName.LastIndexOf("\\") - 1);
           this.OffLine_Pics[this.OffLine_Pics.Count-1].ServerPath = imagePath;
          
            return imagePath;
        }

 

在這個請求頭的參數構造里,有幾個必須附帶講明一下,時間戳。

View Code
  /// <summary>
      /// 本文自博客園原創,轉載請加上此鏈接
      /// http://www.cnblogs.com/uu102
      /// </summary>
      /// <param name="fileName"></param>
      /// <returns></returns>
public static long GetTimestamp(DateTime dateTime)//獲取時間戳
        {
            DateTime startDate = new DateTime(1970, 1, 1);
            DateTime endDate = dateTime.ToUniversalTime();
            TimeSpan span = endDate - startDate;
            return (long)(span.TotalMilliseconds + 0.5);
        }

      this.Uin是當前登錄的QQ號碼,skeys是從當前所在的cookie里提取出來的,仔細找找,在cookies里確實存在這樣的鍵。file_id是自己定義的一個數字,從1開始累加1,QQGlobal.ACCountManager[this.Uin].Vfwebqq是前面登錄就已經獲取到了的參數。具體獲取登陸之前的參數過程,請大家自己查閱網上登錄WebQQ的教程吧。這里這些東西就不做多余的說明了。

    注意觀察,第一段代碼里面有一個突然冒出來的函數SubmitData(url, fileName, dic),這一個函數,其實就是我們接下來要講到的核心請求了,通過以上構造的參數,我們可以做以下請求了。

View Code
 /// <summary>
        /// 模擬表單提交上傳圖片
        /// 本文自博客園原創,轉載請加上此鏈接
        /// http://www.cnblogs.com/uu102
        /// </summary>
        /// <param name="url">地址</param>
        /// <param name="fileName">圖pain的文件名(例如:a.jpg)</param>
        /// <param name="dic">dictionay<T,T>結構"/></param>
        /// <returns></returns>
        private string SubmitData(string url, string fileName, Dictionary<string, string> dic/* ,string[] keys, string[] values*/)
        {
            string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(new Uri(url));
            httpWebRequest.CookieContainer = QQGlobal.ACCountManager[this.Uin].CookieContainer;
            httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
            httpWebRequest.Method = "POST";
            StringBuilder sb = new StringBuilder();

            if (dic.Count != 0)
            {
                foreach (KeyValuePair<string, string> kvp in dic)
                {
                    sb.Append("--");
                    sb.Append(boundary);
                    sb.Append("\r\n");
                    sb.Append("Content-Disposition: form-data; name=\"" + kvp.Key + "\"\r\n\r\n");
                    sb.Append(kvp.Value);
                    sb.Append("\r\n");
                }
            }
            string shortfilename = fileName.Substring(fileName.LastIndexOf("\\") + 1, fileName.Length - fileName.LastIndexOf("\\") - 1);
            this.OffLine_Pics.Add(new OffLine_Up_Pic()); 
            sb.Append("--");
            sb.Append(boundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"file\"; filename=\"");
            sb.Append(shortfilename);
            sb.Append("\"");
            sb.Append("\r\n");
            sb.Append("Content-Type: application/image/jpeg");
            sb.Append("\r\n");
            sb.Append("\r\n");

            string postHeader = sb.ToString();
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);
            byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");

            FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);

            this.OffLine_Pics[this.OffLine_Pics.Count-1].Length = fileStream.Length;//
            this.OffLine_Pics[this.OffLine_Pics.Count-1].ShortFileName = shortfilename;
            long length = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length;
            httpWebRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            httpWebRequest.AllowWriteStreamBuffering = false;
            httpWebRequest.ServicePoint.Expect100Continue = false;
            httpWebRequest.ContentLength = length;

            Stream requestStream = httpWebRequest.GetRequestStream();

            requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))];
            long filebytes = fileStream.Length;
            int bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                requestStream.Write(buffer, 0, bytesRead);
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);

            WebResponse webResponse2 = httpWebRequest.GetResponse();
            Stream stream = webResponse2.GetResponseStream();
            StreamReader streamReader = new StreamReader(stream);
            string html = streamReader.ReadToEnd();
            requestStream.Close();
            fileStream.Close();

            return html;

        }

這一段代碼其實很好看懂,無非就是一個HttpWebRequest請求,只不過請求的類型不一樣,而且數據是分段上傳的。配合前文所列出的發送消息的代碼,就可以發送圖片了。
另外再補充說明一下,在請求之后返回的html文本里,有三個參數都是非常重要的,到時候自己一看便知道了。

針對圖片不能重復發送的解決辦法

圖片如果重復發送,在現實WebQQ聊天過程中很少會發生重復多次發送同一張圖片的,誰還有事沒事只發同一張圖片啊,但是群發里面就經常碰到的這樣的情況,重復發送一張圖片很多次,所以TX就給你來個限制。

對於重復發送同一張圖片,很好的解決辦法就是控制圖片的發送次數,或者發送頻率快慢。最大程度的模擬真實發送過程,但是這樣是治標不治本,很難保證不會被TX限制。

在圖片里用GDI+給圖片添加干擾素。所謂干擾素,無非就是給圖片隨機生成一些顏色或點,讓圖片看起來不是發的同一張圖片。

這個方法很簡單,代碼就不加了。

 

 

針對一台機器掛QQ數量有限制的解決辦法

一台電腦最多掛QQ的數量很有限,超過這個限額tx會要求強制性下線或是驗證。因此,唯一的辦法,就是批量更改IP。所謂批量,就是說等完10個QQ或者20,然后馬上改變IP,再繼續登另外一批。這就是我所說的批量。^.^

好了,這些就是說掌握的突破方法,大家有什么別的好方法,不妨共享一下。

教程每天都更新,請繼續保持關注!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM