FunnyWeb

据说这里有很多神奇的东西...

网页百度云数据包解析(一)

2017-06-17 18:06:261136 views


最近好懒,都没做什么东西,发一些之前的吧。

下面介绍网页版百度云(http://pan.baidu.com)登陆、文件列表解析、视频播放等各种操作。

代码均为C#,在.net4.5环境下测试有效。

1、登陆

登陆post的地址为:https://passport.baidu.com/v2/api/?login

程序运行过程中的cookie使用CookieContainer管理

CookieContainer LoginCookie = new CookieContainer();

登陆之前要先访问http://passport.baidu.com初始化cookie

public string GetCookie()
{
    HttpWebRequest request = null;
    request = WebRequest.Create(new Uri("http://passport.baidu.com")) as HttpWebRequest;
    request.Method = "GET";
    request.CookieContainer = new CookieContainer();
    HttpWebResponse myResponse = (HttpWebResponse)request.GetResponse();
    LoginCookie = request.CookieContainer;
    return myResponse.Cookies[0].Value;
}//获取cookie

然后带着cookie获取token

public string GetToken()
{
    string ret = string.Empty;
    string url = "http://passport.baidu.com/v2/api/?getapi&class=login&tpl=pp&tangram=false";
    HttpWebRequest request = null;
    request = (HttpWebRequest)WebRequest.Create(new Uri(url));
    LoginCookie = LoadCookieContainer(GetCookie());
    request.CookieContainer = LoginCookie;
    request.Method = "GET";
    request.Host = "passport.baidu.com";
    request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
    request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36";
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
    ret = sr.ReadToEnd();
    response.Close();
    string title = "";
    Regex pattern = new Regex(@"token='([\w\W]+?)'");
    Match matchMode = pattern.Match(ret);
    if (matchMode.Success)
    {
        title = matchMode.Groups[1].Value;
    }
    if (title.IndexOf("should") > 0)
    {
        MessageBox.Show("获取token失败");
    }

    return title;
}//获取百度token

登陆时的HTTP头需要带User-Agent和Refer

需要提交的参数为

"charset=utf-8&codestring=" + logincode

 + "&token=" + token 

 +"&isPhone=false&index=0&u=&safeflg=0&staticpage=http%3A%2F%2Fwww.baidu.com%2Fcache%2Fuser%2Fhtml%2Fjump.html&loginType=1&tpl=mn&callback=parent.bdPass.api.login._postCallback&username=" + username

 + "&password=" + password

 + "&verifycode=" + logincodestr

 + "&mem_pass=on"

分别为codestring(验证码相关,下面是获取方式)、token(上面获取的token)、用户名、密码、验证码

第一次登陆时可以把codestring和验证码都设置为空,如果是常用登陆地无需验证码可以成功登陆。

解析返回值的正则语句为Regex pattern = new Regex(@"encodeURI\(\'([\w\W]+?)\'");

使用正则表达式解析返回值,如果返回error=0则为登陆成功,返回error=257则需要输入验证码重新登陆。

当需要输入验证码时,解析codestring的正则语句为pattern = new Regex(@"codestring=([\w\W]+?)&username");

返回值中可以获取到codestring。

构造验证码图片的地址为"https://passport.baidu.com/cgi-bin/genimage?" + logincode+ "&v=1437399073084"(logincode即为codestring值)

public string Login(string username,string password,string ccode="")
{
    
    string ret = string.Empty;
    string url = "https://passport.baidu.com/v2/api/?login";
    HttpWebRequest request = null;
    if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
    {
        //对服务端证书进行有效性校验(非第三方权威机构颁发的证书,如自己生成的,不进行验证,这里返回true)
        ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
        request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
        request.ProtocolVersion = HttpVersion.Version11;    //http版本,默认是1.1,这里设置为1.0
    }
    else
    {
        request = (HttpWebRequest)WebRequest.Create(new Uri(url));
    }

    request.Method = "POST";
    
    request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36";
    request.Referer = "http://www.baidu.com/cache/user/html/login-1.2.html";

    if (ccode == "")
    {
        token = GetToken();
    }
    request.CookieContainer = LoginCookie;
    byte[] byteArray = Encoding.UTF8.GetBytes("charset=utf-8&codestring=" + logincode + "&token=" + token + "&isPhone=false&index=0&u=&safeflg=0&staticpage=http%3A%2F%2Fwww.baidu.com%2Fcache%2Fuser%2Fhtml%2Fjump.html&loginType=1&tpl=mn&callback=parent.bdPass.api.login._postCallback&username=" + username + "&password=" + password + "&verifycode=" + logincodestr + "&mem_pass=on"); //转化
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = byteArray.Length;
    Stream newStream = request.GetRequestStream();
    newStream.Write(byteArray, 0, byteArray.Length);//写入参数
    newStream.Close();
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    LoginCookie = request.CookieContainer;
    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
    ret = sr.ReadToEnd();
    response.Close();
    string title = "";
    Regex pattern = new Regex(@"encodeURI\(\'([\w\W]+?)\'");
    Match matchMode = pattern.Match(ret);
    if (matchMode.Success)
    {
        title = matchMode.Groups[1].Value;
        if (title.IndexOf("error=0") == -1)
        {
                
            if (title.IndexOf("error=257") != -1)
            {
                LoginCookie = request.CookieContainer;
                pattern = new Regex(@"codestring=([\w\W]+?)&username");
                matchMode = pattern.Match(ret);
                logincode = matchMode.Groups[1].Value;
                //弹出新窗口输入验证码
                Form2 f2 = new Form2();
                f2.seturl("https://passport.baidu.com/cgi-bin/genimage?" + logincode + "&v=1437399073084");
                f2.login(true);
                f2.ShowDialog();
                if (logincodestr != "")
                {
                    Login("username","password",logincodestr);
                    logincodestr = "";
                    logincode = "";
                }
                return matchMode.Groups[1].Value;
            }
            MessageBox.Show("登录失败");
        }
        else
        {
        //登陆成功保存cookie
            WriteCookiesToDisk("cookie.txt",LoginCookie);
        }
    }
    
    return ret;
}//登陆百度

cookie获取后几年内都不会失效...所以可以保存在文件里随时使用。

非常好用的存取CookieContainer到文件的函数

public static void WriteCookiesToDisk(string file, CookieContainer cookieJar)
{
    using (Stream stream = File.Create(file))
    {
        try
        {
            Console.Out.Write("Writing cookies to disk... ");
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, cookieJar);
            Console.Out.WriteLine("Done.");
        }
        catch (Exception e)
        {
            Console.Out.WriteLine("Problem writing cookies to disk: " + e.GetType());
        }
    }
}//写cookie进文件

public static CookieContainer ReadCookiesFromDisk(string file)
{
    try
    {
        using (Stream stream = File.Open(file, FileMode.Open))
        {
            Console.Out.Write("Reading cookies from disk... ");
            BinaryFormatter formatter = new BinaryFormatter();
            Console.Out.WriteLine("Done.");
            return (CookieContainer)formatter.Deserialize(stream);
        }
    }
    catch (Exception e)
    {
        Console.Out.WriteLine("Problem reading cookies from disk: " + e.GetType());
        return new CookieContainer();
    }
}//从文件中读cookie

2、解析文件列表

登陆成功后获取bdstoken,此值几乎所有操作都需要使用。

public string GetBdstoken()
{
    string ret = GetHtml("http://pan.baidu.com/disk/home");
    string title = "";
    Regex pattern = new Regex(@"bdstoken[\w\W]+?""([\w\W]+?)[\w\W]+?""");
    Match matchMode = pattern.Match(ret);
    if (matchMode.Success)
    {
        title = matchMode.Groups[1].Value;
        //LoginCookie = request.CookieContainer;
    }
    else
    {
        Console.WriteLine("获取BDSTOKEN失败");
    }
    return title;
}//获取bdstoken

下面使用了Newtonsoft.Json.dll辅助解析json

public string GetFileList(string aimdir)
{
    this.listView2.Clear();
    this.listView2.Columns.Add("名称", 280, HorizontalAlignment.Left); //一步添加
    this.listView2.Columns.Add("fs_id", 110, HorizontalAlignment.Left); //一步添加
    this.listView2.Columns.Add("大小", 50, HorizontalAlignment.Left); //一步添加
    this.listView2.Columns.Add("文件夹", 50, HorizontalAlignment.Left); //一步添加
    this.listView2.Columns.Add("添加时间", 140, HorizontalAlignment.Left); //一步添加
    string ret = string.Empty;
    string url = "http://pan.baidu.com/api/list?channel=chunlei&web=1&num=100&page=1&dir=" + aimdir + "&order=time&desc=1&showempty=0&_=" + GetTimeStamp() + "&bdstoken=" + bdstoken + "&app_id=250528" + "&t=0.5443218712975175";
    HttpWebRequest request = null;
    request = (HttpWebRequest)WebRequest.Create(new Uri(url));
    request.Method = "GET";
    request.CookieContainer = LoginCookie;
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
    ret = sr.ReadToEnd();
    if (aimdir.ToUpper() != "%2F")
    {
        this.listView2.BeginUpdate();
        ListViewItem lv = new ListViewItem();
        lv.Text = "返回上层";
        this.listView2.Items.Add(lv);
        this.listView2.EndUpdate();
    }
    try
    {
        JObject obj = JObject.Parse(ret);
        foreach (JToken record in obj["list"])
        {
            this.listView2.BeginUpdate();
            ListViewItem lvi = new ListViewItem();
            lvi.Text = record["server_filename"].ToString();
            lvi.SubItems.Add(record["fs_id"].ToString());
            lvi.SubItems.Add((Convert.ToInt64(record["size"]) / 1024 / 1024).ToString() + "MB");
            lvi.SubItems.Add(Convert.ToInt32(record["category"]) == 6 ? "是" : "否");
            lvi.SubItems.Add(GetRealTime(record["server_ctime"].ToString()).ToString());
            this.listView2.Items.Add(lvi);
            this.listView2.EndUpdate();
        }
        nowlocation = aimdir;
        if (nowlocation.Substring(nowlocation.Length - 3, 3) == "%2F")
        {
            nowlocation = nowlocation.Substring(0, nowlocation.Length - 3);
        }
    }
    catch
    {
        this.listView2.BeginUpdate();
        ListViewItem lv2 = new ListViewItem();
        lv2.Text = "发生错误..请返回重试...";
        this.listView2.Items.Add(lv2);
        this.listView2.EndUpdate();
    }
    return ret;
}//获取目录内文件列表

代码字数太多了...下一篇继续...