C# WebQQ協(xié)議群發(fā)機器人(一)
來源:程序員人生 發(fā)布時間:2014-09-11 17:38:00 閱讀次數(shù):2819次
本文地址
http://blog.csdn.net/zhujunxxxxx/article/details/38931287 轉(zhuǎn)載的話請注明出處!
之前我也寫過一篇使用python來實現(xiàn)的一個版本
點擊打開鏈接
現(xiàn)在我用c#語言改寫過后也放出源碼來讓大家學(xué)習(xí),希望大家喜歡,不懂的相互交流,
目前我實現(xiàn)的一些功能包括 第一次登錄 二次登陸 獲取群信息 獲取群好友 發(fā)送群消息 發(fā)送消息給好友
先給出一些webqq的一些參數(shù)吧
psessionid 這個是在第二次登錄的時候在 cookie中的一個重要的值,在后面獲取群信息,獲取好友信息等 都要用到這個參數(shù)
vfwebqq 這個同上
ptwebqq 同上
hash 這個參數(shù)是后面發(fā)送群消息和好友消息需要用到的,以前版本沒有 后面加上了
先給出騰訊密碼加密算法 這部分我是用我以前python版本的 比較懶這部分沒有轉(zhuǎn)為c#版本的
#md5
def PCMd5(self,s):
h=hashlib.md5()
h.update(s)
return h.hexdigest()
#16 to cgar
def hex2asc(self,s):
_str="".join(s.split(r'x'))
length=len(_str)
data=''
for i in range(0,length,2):
data+=chr(int(_str[i:i+2],16))
return data
#the password encrypt v1 is checkcode
def PasswordSecret(self,password,v1,v2,md5=True):
if md5==True:
password=self.PCMd5(password).upper()
length=len(password)
temp=''
for i in range(0,length,2):
temp+=r'x'+password[i:i+2]
return self.PCMd5(self.PCMd5(self.hex2asc(temp)+self.hex2asc(v2)).upper()+v1).upper()
然后給的是hash算法
/// <summary>
/// 獲取hash值的算法
/// </summary>
/// <param name="b"></param>
/// <param name="j"></param>
/// <returns></returns>
public string Hash(string b, string j)
{
string a = j + "password error";
string i = "";
List<int> E = new List<int>();
while(true)
{
if (i.Length <= a.Length)
{
i += b;
if (i.Length == a.Length)
{
break;
}
}
else
{
i = i.Substring(0, a.Length);
break;
}
}
for (int c = 0; c < i.Length; c++)
{
int tmp = (char)i[c] ^ (char)a[c];
E.Add(tmp);
}
string[] seed = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
i = "";
for (int c = 0; c < E.Count; c++)
{
i += seed[E[c] >> 4 & 15];
i += seed[E[c] & 15];
}
return i;
}
這個函數(shù)的參數(shù)是 第一個是你的qq號 第二個是ptwebqq 之前一直以為是vfwebqq 結(jié)果一直出錯
這兩個函數(shù)都是正確的,網(wǎng)上很多的方法已經(jīng)失效了
首先在登錄時,你必須檢查是否需要輸入驗證碼 這個函數(shù)的返回值是一個字符串
ptui_checkVC('0','!NTZ','x00x00x00x00x22x79x9fx0d', 'ef0e577a40249cc2b77dc9f266a3a4141a987d06a8f3ae39117183f1ff0491720e1f6f498a9a038f032d99f8622ea628');
第一個參數(shù)是0 表示不需要輸入?yún)?shù),第二個參數(shù)是一個驗證碼 后面用來加密密碼的
//檢查是否需要 驗證碼
public bool check()
{
string url = "https://ssl.ptlogin2.qq.com/check?uin={$uin}&appid=1003903&js_ver=10092&js_type=0&login_sig=K5F0E8woS74td4sRIqKiSHmH6B2RYYP467z2r*6YWaH4wc7vE*4G*X7V2kGP9s1*&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html&r=0.2689784204121679";
url = url.Replace("{$uin}", this.qq);
HttpItem item = new HttpItem()
{
URL = url,//URL 必需項
Encoding = System.Text.Encoding.GetEncoding("utf-8"),//URL 可選項 默認為Get
Method = "get",//URL 可選項 默認為Get
IsToLower = false,//得到的HTML代碼是否轉(zhuǎn)成小寫 可選項默認轉(zhuǎn)小寫
Timeout = 100000,//連接超時時間 可選項默認為100000
ReadWriteTimeout = 30000,//寫入Post數(shù)據(jù)超時時間 可選項默認為30000
UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0",//用戶的瀏覽器類型,版本,操作系統(tǒng) 可選項有默認值
ContentType = "application/x-www-form-urlencoded",//返回類型 可選項有默認值
ResultType = ResultType.String,
};
HttpResult result = http.GetHtml(item);
Regex reg = new Regex(@"ptui_checkVC('(.*)','(.*)','(.*)', '(.*)');");
Match m = reg.Match(result.Html);
string[] ret = new string[m.Groups.Count];
for (int i = 0; i < m.Groups.Count; i++)
{
ret[i] = m.Groups[i].Value;
}
this.checkv2 = ret[3];
if (ret[1] == "0")
{
this.checkcode = ret[2];
this.session = ret[4];
return false;
}
else
return true;
}
接下來是我們第一次登錄
public bool Login()
{
string url = "https://ssl.ptlogin2.qq.com/login?u={$uin}&p={$pwd}&verifycode={$verify}&webqq_type=10&remember_uin=1&login2qq=0&aid=1003903&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html%3Flogin2qq%3D0%26webqq_type%3D10&h=1&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=2-9-33854&mibao_css=m_webqq&t=1&g=1&js_type=0&js_ver=10092&login_sig=K5F0E8woS74td4sRIqKiSHmH6B2RYYP467z2r*6YWaH4wc7vE*4G*X7V2kGP9s1*&pt_uistyle=5&pt_vcode_v1=0&pt_verifysession_v1={$session}";
url=url.Replace("{$uin}",this.qq);
url=url.Replace("{$verify}",this.checkcode);
string pwd = encrypt.Encrypt_Password(this.qq,this.password,this.checkcode);
url=url.Replace("{$pwd}",pwd);
url = url.Replace("{$session}", this.session);
HttpItem item = new HttpItem()
{
URL = url,
Encoding = System.Text.Encoding.GetEncoding("utf-8"),
Method = "get",
IsToLower = false,
Timeout = 100000,
Referer="https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20140612002",
Host="d.web2.qq.com",
UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0",//用戶的瀏覽器類型,版本,操作系統(tǒng) 可選項有默認值
ContentType = "application/x-www-form-urlencoded",
ResultType = ResultType.String
};
HttpResult result = http.GetHtml(item);
foreach (Cookie c in result.CookieCollection)
{
if (c.Name == "ptwebqq")
this.ptwebqq = c.Value;
}
this.hash= Hash(this.qq, this.ptwebqq);
Regex reg = new Regex(@"ptuiCB('(.*)','(.*)','(.*)','(.*)','(.*)',s'(.*)');");
Match m = reg.Match(result.Html);
string[] ret = new string[m.Groups.Count];
for (int i = 0; i < m.Groups.Count; i++)
{
ret[i] = m.Groups[i].Value;
}
if (ret[1] == "0")
{
this.proxyurl = ret[3];
return true;
}
else
return false;
}
第一次登錄后會返回 return ptuiCB('0','0','http://ptlogin4.web2.qq.com/check_sig?pttype=1&uin=578395917&service=login&nodirect=0&ptsig=uV34Xt9XM3e2oQ3wuub8LIBIGsIIZATjiz-cqSVHJ5o_&s_url=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html%3Flogin2qq%3D0%26webqq_type%3D10&f_url=&ptlang=2052&ptredirect=100&aid=1003903&daid=164&j_later=0&low_login_hour=0®master=0&pt_login_type=1&pt_aid=0&pt_aaid=0&pt_light=0','0','登錄成功!',
'你的名字');
如果第一個參數(shù)不是0的話 表示有錯,如果像這樣的話就表示成功了
返回結(jié)果中的那個ur鏈接我們用get方式打開它,這個步驟是為了獲取一個關(guān)鍵的cookie值 p_skey 這個是第二次登錄的時候有用
接下來是我們二次登錄了
public void Login2()
{
Dictionary<string, Object> r = new Dictionary<string, Object>();
r.Add("status", "online");
r.Add("ptwebqq", this.ptwebqq);
r.Add("passwd_sig", "");
r.Add("clientid", this.clientid.ToString());
r.Add("psessionid", null);
Dictionary<string, Object> data = new Dictionary<string, Object>();
data.Add("r", JsonConvert.SerializeObject(r));
data.Add("clientid", this.clientid);
data.Add("psessionid", "null");
string postdata = Tool.MakePostData(data);
//string postdata="r=%7B%22status%22%3A%22online%22%2C%22ptwebqq%22%3A%22{$ptwebqq}%22%2C%22passwd_sig%22%3A%22%22%2C%22clientid%22%3A%22{$clientid}%22%2C%22psessionid%22%3Anull%7D&clientid={$clientid}&psessionid=null";
//postdata=postdata.Replace("{$ptwebqq}",this.ptwebqq);
//postdata = postdata.Replace("{$clientid}", this.clientid);
HttpItem item = new HttpItem()
{
URL = "http://d.web2.qq.com/channel/login2",//URL 必需項
Method = "POST",//URL 可選項 默認為Get
IsToLower = false,//得到的HTML代碼是否轉(zhuǎn)成小寫 可選項默認轉(zhuǎn)小寫
Timeout = 100000,//連接超時時間 可選項默認為100000
Postdata=postdata,
Host=HOST[0],
Referer=REFERER[0],
UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36",//用戶的瀏覽器類型,版本,操作系統(tǒng) 可選項有默認值
ContentType = "application/x-www-form-urlencoded",//返回類型 可選項有默認值
Accept="*/*",
ResultType = ResultType.String
};
HttpResult result = http.GetHtml(item);
JObject obj = (JObject)JsonConvert.DeserializeObject(result.Html);
this.vfwebqq= obj["result"]["vfwebqq"].ToString();
this.psessionid = obj["result"]["psessionid"].ToString();
}
這個步驟很重要,獲取很多有用的cookie值,上面提到的那些就要用一個變量保存下來,以便后面使用
下面我們就要拉去我們的群組信息了
這個返回結(jié)果是一個json格式的,我們需要序列化為json對象,把里面的群相關(guān)信息存起來
/// <summary>
/// 獲取群列表
/// </summary>
public void GetGroupNameList()
{
Dictionary<string, Object> r = new Dictionary<string, Object>();
r.Add("hash", this.hash);
r.Add("vfwebqq", this.vfwebqq);
Dictionary<string, Object> data = new Dictionary<string, Object>();
data.Add("r", JsonConvert.SerializeObject(r));
string postdata = Tool.MakePostData(data);
//string postdata = "r=%7B%22hash%22%3A%22{$hash}%22%2C%22vfwebqq%22%3A%22{$vfwebqq}%22%7D";
//postdata = postdata.Replace("{$hash}", this.hash);
//postdata = postdata.Replace("{$vfwebqq}", this.vfwebqq);
HttpItem item = new HttpItem()
{
URL = "http://s.web2.qq.com/api/get_group_name_list_mask2",
Method = "POST",
IsToLower = false,
Timeout = 100000,
Postdata = postdata,
Host = HOST[1],
Referer = REFERER[1],
UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36",//用戶的瀏覽器類型,版本,操作系統(tǒng) 可選項有默認值
ContentType = "application/x-www-form-urlencoded",
ResultType = ResultType.String
};
HttpResult result = http.GetHtml(item);
JObject ret = (JObject)JsonConvert.DeserializeObject(result.Html);
JObject retjson = (JObject)ret["result"];
foreach (JToken jk in retjson["gnamelist"])//獲取群信息用 code 發(fā)送群信息用 gid
{
this.grouplist.Add(jk["gid"].ToString()+":"+jk["code"].ToString(), jk["name"].ToString());
}
}
每個群 有個gid 和code name 其中獲取群成員的使用code 而向群發(fā)送消息的時候用的是gid 這部分一定要注意 我花了很多時間才發(fā)現(xiàn)自己的錯誤
獲取某個群的群成員信息 參數(shù)就是上面提到的code 不要用錯了哦
/// <summary>
/// 根據(jù)群code得到群信息
/// </summary>
/// <param name="gcode"></param>
public void GetGroupInfo(string gcode)
{
string url = "http://s.web2.qq.com/api/get_group_info_ext2?gcode={$gcode}&cb=undefined&vfwebqq={$vfwebqq}&t=1409316979595";
url=url.Replace("{$vfwebqq}",this.vfwebqq);
url = url.Replace("{$gcode}", gcode);
HttpItem item = new HttpItem()
{
URL = url,
Encoding = System.Text.Encoding.GetEncoding("utf-8"),
Method = "get",
IsToLower = false,
Timeout = 100000,
ReadWriteTimeout = 30000,
Host=HOST[1],
Referer=REFERER[1],
UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0",//用戶的瀏覽器類型,版本,操作系統(tǒng) 可選項有默認值
ContentType = "application/x-www-form-urlencoded",
ResultType = ResultType.String,
};
HttpResult result = http.GetHtml(item);
JObject ret = (JObject)JsonConvert.DeserializeObject(result.Html);
JObject retjson = (JObject)ret["result"];
foreach (JToken jk in retjson["cards"])
{
this.groupinfo.Add(jk["muin"].ToString(), jk["card"].ToString());
}
}
下面是向群里面發(fā)送消息 這個用的就是剛才說的 gid 也不要用錯了
public void SendGroupMsg(long groupid,string msg)
{
string style=""{content}"";
string temp="";
temp += style.Replace("{content}", msg) + ",";
temp = temp.Substring(0, temp.Length - 1);
Random rd = new Random();
int msg_id = (rd.Next(100000) + 100000);
string content="[{$msg},"",["font",{"name":"宋體","size":"10","style":[0,0,0],"color":"000000"}]]";
content = content.Replace("{$msg}", temp);
Dictionary<string, Object> r = new Dictionary<string, Object>();
r.Add("group_uin", groupid);
r.Add("content", content);
r.Add("msg_id", msg_id);
r.Add("clientid", this.clientid);
r.Add("psessionid",this.psessionid);
Dictionary<string, Object> data = new Dictionary<string, Object>();
data.Add("r", JsonConvert.SerializeObject(r));
data.Add("clientid", this.clientid);
data.Add("psessionid", this.psessionid);
string postdata = Tool.MakePostData(data);
HttpItem item = new HttpItem()
{
URL = "http://d.web2.qq.com/channel/send_qun_msg2",
Accept="*/*",
Method = "POST",
IsToLower = false,
KeepAlive=true,
Timeout = 100000,
Postdata = postdata,
Host = HOST[0],
Referer = REFERER[0],
UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2041.4 Safari/537.36",
ContentType = "application/x-www-form-urlencoded",
ResultType = ResultType.String
};
HttpResult result = http.GetHtml(item);
JObject ret = (JObject)JsonConvert.DeserializeObject(result.Html);
//string html = HttpHelper2.GetHtml("http://d.web2.qq.com/channel/send_qun_msg2", postdata,HttpHelper.cookies);
}
接下來還有 獲取好友信息和 向好友發(fā)送消息...
這一部分我放在下一篇將 頭昏啊!sorry!
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈