和雅虎中国亲密接触
来源:互联网 发布:大数据与房地产公司 编辑:程序博客网 时间:2024/04/29 19:22
BQYAHOO在替我们做什么
从本质上来说,BQYAHOO只是代替你做一些你也采取其他方式来做的事情。比如代替你登陆邮箱,代替你下载附件。那么我们来看看,没有BQYAHOO的帮助,我们该怎么做这些事情。
第一步:我们首先来到邮件登录网页,输入自己的用户名和密码,最后单击登录。
第二步:进入了邮箱,但是没有进入收件箱,这时看不到邮件也下载不了附件,只好在单击收件箱的链接。
第三步:进入了收件箱,这个时候看到了邮件,如果你想下载附件,那么你还需要进入特定的邮件,然后单击相关链接下载附件。但是,对于BQYAHOO来说,一切到此结束。现在这个年代,即使是程序也要讲究智能,其实收件箱网页的源代码已经将所有信息一览无余的告诉了你。BQYAHOO会对这些信息进行分析,最终计算出附件的下载地址。
接下来将结合程序讲解如何在BQYAHOO中实现登陆邮箱和下载附件。
在编写BQYAHOO的时候,我总是在类库的选择上费尽心机。有时候会出现彼此矛盾的情况,如果你使用A类库,那么就不可以同时使用B类库。总的来说,应该尽可能选择由一家公司提供的类库,比如说微软。
在登录邮件和下载附件的过程当中,你不得不使用HTTP函数库,因为和雅虎中国服务器的交互就是建立在HTTP协议上的。当然你也可以使用Windows Sockets封装一个自己的HTTP函数库,不要以为我在开玩笑,我差一点就这么做了(在文章的后面会提到我为什么这么做)。
目前有多种HTTP函数库可供选择,仅考虑微软提供的函数库就有以下四种:
l MFC HTTP
l ATL Server HTTP
l Windows HTTP
l Windows Internet
BQYAHOO里面使用的是最后一种:Windows Internet 。它在这些函数库里面是封装程度最低的,但是,我却觉得用起来最为顺手,所需要知道的额外信息很少。关于Windows Internet函数库的详细内容,请你阅读MSDN,这里只介绍源代码中使用到的函数及其相关知识。
为了使用Windows Internet函数库,你必须在程序中使用头文件wininet.h和库文件wininet.lib。
其实在BQYAHOO当中,一共只使用到这个函数库当中的三个函数:
l InternetOpen
l InternetOpenUrl
l InternetReadFile
怎么样?是不是觉得很轻爽?
///这里可以对上面三个函数的用法进行简单介绍,视情况而定。/////
如果我告诉你,在IE中不用输入用户名和密码,只需根据用户名,密码以及登录网页上的其它信息计算出一个网址,然后输入到IE的地址栏里面,就可以正常登录雅虎邮箱,你觉得可能吗?
其实你自己可以尝试一下,先输入用户名和密码(故意输入错误的信息),然后单击登录,最后,你会在地址栏上看到一串很长的网址。如果你输入正确的用户名和密码,就看不到这个网址,因为IE会自动跳转到邮箱当中,那么你看到的就是邮箱的网址。
可以通过下面源码获得该网页的源码。
bool WebClient::BeforeLogIn()//进入登陆页面
{
hsession=::InternetOpen("biqiong",INTERNET_OPEN_TYPE_PRECONFIG ,NULL ,NULL,NULL);
hconnect=::InternetOpenUrl(hsession,BeforLogInUrl.c_str (),NULL,NULL,CONNECT_FLAG,NULL);
GetResponse();
GetHead();
xlog.log ("进入登陆页面");//记录日子信息
xlog.log (head);
xlog.log (response);
if(TestResponse()==false) return false;
if(strstr(response,"ShowFolder?rb=Inbox" )!=NULL) MayBeIn=true;//目前已经登陆成功
return true;
}
现在问题的关键是如何计算出这个网址?它如何产生?需要知道哪些信息?
在登录的时候,雅虎中国会使用MD5加密用户名和密码,密文会在服务器端进行验证,最终确定你的身份。以下雅虎中国的网页源代码或许会给你一些启示(... ... ...表示删减)。
<script language=javascript>
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Copyright (C) Paul
* Updated by Greg Holt 2000 - 2001.
* See http://pajhome.org.uk/site/legal.html for details.
*/
var hex_c
function rhex(num)
{
str = "";
for(j = 0; j <= 3; j++)
str += hex_c
hex_c
return str;
}
function str2blks_MD5(str)
{
nblk = ((str.length + 8) >> 6) + 1;
blks = new Array(nblk * 16);
for(i = 0; i < nblk * 16; i++) blks[i] = 0;
for(i = 0; i < str.length; i++)
blks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8);
blks[i >> 2] |= 0x80 << ((i % 4) * 8);
blks[nblk * 16 - 2] = str.length * 8;
return blks;
}
function add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
... ... ...
function ii(a, b, c, d, x, s, t)
{
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function MD5(str)
{
x = str2blks_MD5(str);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = ff(a, b, c, d, x[i+ 0], 7 , -680876936);
... ... ... ...
b = ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = add(a, olda);
b = add(b, oldb);
c = add(c, oldc);
d = add(d, oldd);
}
return rhex(a) + rhex(b) + rhex(c) + rhex(d);
}
function hash(form,login_url) {
var url;
if (arguments.length > 1 && login_url != "") { // in case login_url is not passed in
url = login_url;
} else {
url = "http://edit.bjs.yahoo.com/config/login";
}
url += "?";
if (navigator.userAgent.indexOf("Mozilla/4")==0) {
var passwd = form.passwd.value;
var hash1 = MD5(form.passwd.value);
var challenge = form[".challenge"].value;
var hash2 = MD5(form.passwd.value) + challenge;
var hash;
if(form.passwd.value){
hash=MD5(hash2);
} else {
hash="";
}
var js = 0;
for(i=0; i<form.elements.length; i++){
if(form.elements[i].name.length <=0) {
continue;
}
if(i > 0){
url += "&";
}
url += form.elements[i].name;
url += "=";
if(form.elements[i].name == "passwd"){
url += hash;
} else if (form.elements[i].type == "checkbox" && !form.elements[i].checked) {
url += "";
} else if (form.elements[i].name == ".save"){
url += "1";
} else if (form.elements[i].name == ".js"){
js = 1;
url += "1";
} else {
url += escape(form.elements[i].value);
}
}
url += "&.hash=1";
if(js == 0){
url += "&.js=1";
}
url += "&.md5=1";
location.
form.onsubmit=null;
return false;
}
return true;
}
</script>
雅虎中国使用javaScript实现了MD5加密,而我们要做的就是在程序中也实现上面的过程并产生同样的结果。
///这里可以对MD5加密进行简单介绍,视情况而定。/////
在计算的过程当中,我们除了需要知道用户名和密码,而且还需要知道当前网页上的challenge值。每次打开登录网页,该值都发生随机变化,这也是安全的保证。以下代码可以告诉你该值的作用。
var challenge = form[".challenge"].value;
var hash2 = MD5(form.passwd.value) + challenge;
以下代码用C++计算登录网址。
const char * CGLIU::GetLogInUrl()
{
//以下代码计算登录URL,来自于开源项目YPOPs!
//下面的MD5加密完全再现了雅虎中国网页上的加密过程
char hash[256];
MD5_CTX ctx;
MD5_Init(&ctx);
MD5_Update(&ctx, password, strlen(password));
MD5_Final(reinterpret_cast<unsigned char *>(hash), &ctx);
hash[0] = '/0';
rhex(ctx.A, data);
strcat(hash, data);
rhex(ctx.B, data);
strcat(hash, data);
rhex(ctx.C, data);
strcat(hash, data);
rhex(ctx.D, data);
strcat(hash, data);
strcat(hash, ChallengeText);
MD5_Init(&ctx);
MD5_Update(&ctx, hash, strlen(hash));
MD5_Final(reinterpret_cast<unsigned char *>(hash), &ctx);
hash[0] = '/0';
rhex(ctx.A, data);
strcat(hash, data);
rhex(ctx.B, data);
strcat(hash, data);
rhex(ctx.C, data);
strcat(hash, data);
rhex(ctx.D, data);
strcat(hash, data);
sprintf(data, "%s?login=%s&passwd=%s&.save=1&.intl=cn&.src=ym&.challenge=%s&.hash=1&.js=1&.md5=1", HTTP_LOGIN, user, hash, ChallengeText);
strcpy(LogInUrl,data);
return (const char *)LogInUrl;
}
inline void rhex(unsigned int num, char *data)
{
CStdString hex_c
CStdString str;
for(int j = 0; j <= 3; j++)
{
str += hex_c
str += hex_c
}
strcpy(data, str);
}
函数GetLogInUrl()返回登录网址,使用它我们就可以登录雅虎邮箱了。
在上面我们提到如果输入正确的用户名和密码,IE会自动地跳转到邮箱。在程序当中也是如此,当我们向雅虎中国服务器发送正确的登录网址,接下来,我们将接受到进入邮箱后的网页内容。
到目前为止,我们终于登录成功并进入邮箱。接下来的要做的就是进入收件箱。
bool WebClient::InInBox(const string MailHostUrl)
{
string InBoxUrl;
InBoxUrl=MailHostUrl+"ym/ShowFolder?rb=Inbox&box=Inbox";
hconnect=::InternetOpenUrl(hsession,InBoxUrl.c_str (),NULL,NULL,CONNECT_FLAG,NULL);
GetResponse();
GetHead();
xlog.log ("进入收件箱");//记录日子信息
xlog.log (head);
xlog.log (response);
if(TestResponse()==false) return false;
return true;
}
收件箱就是我们的目的地,来到这一页,BQYAHOO就可以通过网页分析得到所需要的所有信息,最终获得所有的邮件附件的下载网址。
接下来就是下载附件了。
bool WebClient::DownLoadFile(string FileSaveName,string DownLoadUrl)
{
//所有下载操作,最终由以下代码执行。
//虽然简单粗俗,却很是实用。
const unsigned long CacheSize=100*1024;//分块下载,每一块100K
HINTERNET hfile;
char cache[CacheSize];
unsigned long byteofread=CacheSize;
FILE *fdest;
fdest=fopen(FileSaveName.c_str (),"wb");
hfile=::InternetOpenUrl(hsession ,DownLoadUrl.c_str (),NULL,NULL,NULL,NULL);
while(::InternetReadFile(hfile,cache,CacheSize,&byteofread)==true)
{
fwrite(cache ,sizeof(char),byteofread ,fdest);
if(byteofread==0)break;
}
fclose(fdest);
return true;
}
在下载这个地方,我花费了很多精力。我一直想实现而从来就没有实现的目标是:多线程下载。我对于将一个文件分块,然后使用多线程下载没有兴趣。因为BQYAHOO每个附件的内容本身就不多,不可以超过
每当我在同一时间向不同的附件网址发起请求时,只有一个请求会得到答复,而其他请求之能够等待。从线程的角度来看,那个时间里确实存在着多线程。也就是说即便使用多线程,文件还是一个接一个的被下载。而且使用多线程会带来不稳定,排在后面的线程常常“无疾而终”,什么也没有下载。
总的来说,BQYAHOO相当于一个功能极其简陋,作用极其明确的”IE”。在和雅虎中国服务器的交互过程当中,我们只是做了两件事情:获取网页和获取文件。整个登录过程当中,难点就是计算登录网址,如果你熟悉JavaScript,也不是那么困难,最多就是照葫芦画瓢。
其实在本文当中,有很多关键内容我都没有讲到,比如说如何得到challenge。这些内容我都留到下一篇文章讲解,因为它们统统都属于网页分析。
- 和雅虎中国亲密接触
- 和领导亲密接触
- 和Lnux亲密接触
- 和webshell第一次亲密接触
- 终于和struts亲密接触了
- 我和XML的亲密接触
- 我和Spring第一次亲密接触
- 第一次和CSDN的亲密接触
- 我和汉语编程的亲密接触
- 再次和Memcached、Tbstore亲密接触
- 我和唐骏的亲密接触
- 珍惜和企业的第一次亲密接触
- 珍惜和企业的第一次亲密接触
- 和神奇code的第一次亲密接触
- STM32F429I-DISCO 和GPS的亲密接触
- 和csdn的第一次亲密接触
- lua和c的亲密接触
- 雅虎中国关闭雅虎空间和雅虎关系---雅虎在打败自己了
- Linux网络代码导读v0.2
- (转载)Google Hacking的实现以及应用
- BQYAHOO开发杂谈
- QQ的三大阴谋
- D语言中的混入(Mixin)
- 和雅虎中国亲密接触
- 新年,旧物已新
- 在网页中寻宝
- 我的地盘我做主
- 契约式编程
- 结束语
- DataGrid资料
- 关于const好文2
- vbs日历