系列手记:
开心网辅助程序开发手记
开心网辅助程序开发手记(二):获取好友私家车位信息
在前面的两篇手记中,较为详细的介绍了如何借助工具对网页进行分析及如何编写代码实现一些简单的功能。如果还有后续手记,笔者将只简单记录《开心网辅助程序》开发过程中碰都的主要问题及解决方法。
在这篇手记中,笔者将简单描述如何实现简单的停车功能,并且制作一个简单的界面用于呈现系列手记的开发成果。
一、识别好友私家车位中的免费车位:把车停到免费车位中可是会分文无收到,所以千万不能把车停到免费车位上了。
通过Firebug调试发现,当玩家点击“争车位”中部Flash中的停车按钮时,parking-7.js中第169行当parking_park方法将被执行。
Code
g_curparkid = parkid;
var v_park_free = (parseInt(g_curparkid) >> 16) & 0xff;
在parking-park中,有以上代码。其中传入参数parkid就是在《开心网辅助程序开发手记(二):获取好友私家车位信息》获取的好友私家车位信息中的parkid。对Javascript不了解到朋友看到这段代码可能会犯晕,不明白其中的含义。
1. Javscript中的位运算符">>":关于JS中的位运算符,请参考http://www.w3school.com.cn/js/as_js_operators_bitwise.asp。其实在C#中,右移运算符也是">>"。如:67174403 >> 16 = 1025;
2.0xff:这个其实是以16进制表达的数字,对应着十进制中的255
在程序中,笔者在ParkingInfo这个实体类中添加了一个属性IsParkFree来标志车位是否免费
Code
/// <summary>
/// 是否为免费车位
/// </summary>
public bool IsParkFree
{
get
{
return Convert.ToBoolean(ParkId >> 16 & 255);
}
}
二、模拟停车:在识别出免费车位后,终于可以模拟停车了。
在页面上进行停车,通过Firebug,我们可以发现每次成功停车都会有两个post。一个是park.php:该Post进行停车;另一个是user.php:该post是用来更新玩家车辆停车情况的。当然,在下图中还有一个newmsg.php这个post,该post是用来检查是否有短消息的。
下图是park.php的post情况截图:除了acc和verify,其他的数据都可以从之前程序中获取的JSON中取得;verify在之前的手记中也取到了,现在就差acc了。那么acc是个什么玩意儿呢?
在app.php?aid=1040上,可以找到一个叫做acc()的方法,没错了,acc就是由这个方法生成的。经过几天的观察,貌似这个方法中的代码是有变化的。。。那么该如何做程序中获取acc呢?经过搜索发现,原来在.NET中也是可以执行Javascript的。下面是一篇在google上找到的参考文章:http://www.west-wind.com/WebLog/posts/10688.aspx。
其实说白了就是调用Microsoft.JScript.Vsa.VsaEngine和Microsoft.JScript.Eval来编译并执行一段JS脚本。下面是我写的测试代码:
Code
public static string EvalJavascript(string js)
{
Microsoft.JScript.Vsa.VsaEngine ve = Microsoft.JScript.Vsa.VsaEngine.CreateEngine();
return Microsoft.JScript.Eval.JScriptEvaluate(js, ve).ToString();
}
/// <summary>
/// EvalJavascriptTest 的测试
/// </summary>
[TestMethod()]
public void EvalJavascriptTest()
{
string js = "var gb58b = \"c48429010dbb\"; var acc3 = \"cbaktr0f1\"; function acc() { var acc = daa49.charCodeAt(1) + gb58b.length; return acc; } var daa49 = \"da5af2af139b\"; acc();"; // TODO: 初始化为适当的值
string expected = "109"; // TODO: 初始化为适当的值
string actual;
actual = Utility.EvalJavascript(js);
Assert.AreEqual(expected, actual);
}
现在看来,只要能从app.php?aid=1040上分离出acc()相关的JS脚本,再调用EvalJavascript方法执行就可以了
Code
/// <summary>
/// 获取acc
/// </summary>
/// <param name="parkingHtml">争车位页面HTML代码</param>
/// <returns></returns>
private string GetAcc(string parkingHtml)
{
string[] temp = parkingHtml.Split(new string[] { "acc()" }, StringSplitOptions.RemoveEmptyEntries);
if (temp.Length == 0)
{
throw new Exception("找不到acc()方法");
}
string js = temp[0].Substring(temp[0].LastIndexOf('}') + 1) + " acc() " + temp[1].Substring(0, temp[1].IndexOf("function")) + " acc();";
return Utility.EvalJavascript(js);
}
下面就是具体的停车代码(由于Response也是JSON,所以定义了一个实体ParkResult):
Code
/// <summary>
/// 停一辆车
/// </summary>
/// <param name="parkerFriendInfo">玩家好友(汽车将停在该好友的私家车位上)</param>
/// <param name="carInfo">汽车(将进行的汽车)</param>
/// <param name="parkingInfo">私家车位(汽车将停在该私家车位上)</param>
public void ParkOneCar(ParkerFriendInfo parkerFriendInfo, CarInfo carInfo, ParkingInfo parkingInfo)
{
string parkUrl = "http://www.kaixin001.com/parking/park.php";
string postParams = string.Format("_=&acc={0}&carid={1}&first_fee_parking={2}&neighbor={3}&park_uid={4}&parkid={5}&verify={6}", acc, carInfo.CarId, parkerInfo.FirstFeeParking, parkerFriendInfo.Neighbor, parkerFriendInfo.UId, parkingInfo.ParkId, verify);
HttpHelper helper = new HttpHelper();
string parkResult = helper.GetHtml(parkUrl, postParams, true, Utility.Cookies);
}
下面是对Post Params的介绍:
1. acc:上文获取的acc
2. carid:将进行停车的汽车ID
3. first_fee_parking:玩家的first_fee_parking
4. neighbor:好友是否和玩家是邻居,该数据应来自ParkerFriendInfo
5. park_uid:好友的车库ID,来自ParkerFriendInfo
6. parkid:私家车位ID
7. verify:前文获取的verify
下面是测试代码:
Code
/// <summary>
///ParkOneCar 的测试(在该测试中,将把玩家的第N辆车停到第M个好友的第X个私家车库中)
///</summary>
[TestMethod()]
public void ParkOneCarTest()
{
string loginEmail = UnitTestHelper.LoginEmail;
string loginPassword = UnitTestHelper.LoginPassword;
Utility.Login(loginEmail, loginPassword);
ParkingHelper helper = new ParkingHelper();
helper.GetParkerDetails();
CarInfo carInfo = helper.CarList[2]; // 第N辆车
ParkerFriendInfo parkerFriendInfo = helper.ParkerFriendList[5]; // 第M个好友
List<ParkingInfo> parkingInfoList = helper.GetFirendParkingInfo(parkerFriendInfo.UId);
ParkingInfo parkingInfo = parkingInfoList[0]; // 第X个私家车位
ParkResult result = helper.ParkOneCar(parkerFriendInfo, carInfo, parkingInfo);
Console.WriteLine(result.Error);
Assert.AreEqual<string>("0", result.ErrNo);
}
点击下载示例源码