C# winForm中调用javascript文件中的方法
目前有很多的SNS社区或类SNS的网站,例如开心、51、校内等,但是发现大多数社区在邀请好友的时候都没有提供对QQ邮箱或者QQ空间好友列表获取的功能,不过似乎海内支持,但是网上相关QQ的文章还不是很多,希望这篇文章能给你带来一些帮助。
QQ空间及邮箱登陆的校验方式:
QQ空间及邮箱登陆的时候,用户输入的密码首先会被页面中的一段Js加密,然后加密过后的密码会加上验证码形成一个新的字串,接着这个新的字串被MD5(32位)加密,加密过后形成最终的密码,这就是我们为什么经常会发现我们在提交的时候我们的密码框中的密码个数会增长的原因,接着在你提交的时候,当前的这个请求会将前一次获取验证码返回的set-cookie值加入到当前请求头的cookie中以保持验证码请求与当前请求的一致性,然后再一并将新的密码和用户名Post到QQ的服务器上去。
好了,看了上面的QQ校验方式以后,我们再来看看怎样使用代码来登录QQ空间及邮箱来获取我们需要的好友和联系人。
QQ空间及邮箱自动登录获取联系人的解决方案:
QQ空间及邮箱登陆首先我们需要将用户输入的密码进行Js加密,但是我们在使用代码登录的时候我们并没有使用到浏览器,那我们怎样驱动Js呢?不用怕,在Java和.NET中都有相应的方式在服务器代码端驱动JS,这里着重讲一下.NET的方法:
首先到微软的网站上下载Windows Script Control,它是一个ActiveX(R) 控件。下载安装完成后,新建一个C#应用程序项目,在解决方案资源管理器中选中引用节点, 右键点击选择添加引用菜单,弹出添加引用对话框,单击浏览找到安装Windows Script Control的目录,选取msscript.ocx文件确定。那么在引用节点下会增加一个MSScriptControl组件,下面是他Interop 后的所有对象。
<!--[if !vml]--><!--[endif]-->
ScriptControl 对支持 ActiveX(TM) Script 的宿主 Script 引擎提供简单接口。接下来我们对被转化成ScriptControlClass类的ScriptControl的属性和方法进行一些说明。
属性
AllowUI 属性:应用于 ScriptControl 本身或 Scirpt 引擎显示的用户界面元素,可读写。
CodeObject 属性:返回对象,该对象用于调用指定模块的公用成员。只读。
Error 属性:返回 Error 对象,其中包含所发生的最后一个错误的相关详细信息。只读。
Language 属性:设置或返回正在使用的 Script 语言名称。可读写。
Modules 属性:为 ScriptControl 对象返回模块集合。只读。
Procedures 属性:返回在指定模块中定义的过程集合。只读。
SitehWnd 属性:设置或返回窗口的 hWnd,通过执行 Script 代码,此窗口用于显示对话框和其他用户界面元素。可读写。
State 属性:设置或返回 ScriptControl 对象的模式。可读写。
Timeout 属性:设置或返回时间(毫秒),此时间后用户可选择中止 Script 代码的执行或允许代码继续执行。可读写。
UseSafeSubset 属性:设置或返回 Boolean 值,指明宿主应用程序是否有保密性要求。如果宿主应用程序需要安全控制,则 UseSafeSubset 为 True,否则为 False。可读写。
方法
AddCode 方法:向模块添加指定代码。可多次调用 AddCode 方法。
AddObject 方法:使主机对象模型对 Script 引擎可用。
Eval 方法:计算表达式并返回结果。
ExecuteStatement 方法:执行指定的语句。
Reset 方法:放弃所有已经添加到 ScriptControl 中的 Script 代码和对象。
Run 方法:运行指定过程。
事件
Error 事件:出现运行时错误时,发生此事件。
Timeout 事件:当超出了 Timeout 属性指定的时间且用户在结果对话框中选定了 End 时,发生此事件。
说明:
AllowUI 属性如果设置为false,则显示对话框之类的语句不起作用,如在 VBScript 中MsgBox 语句,JavaScript中的alert等,并且如果执行的脚本超出TimeOut设置的毫秒数,也不会跳出超出时间提醒的对话框,反之则相反;重新设 置 Language 属性会清空AddCode加载的代码;对于TimeOut属性,发生超时时,ScriptControl 检查对象的 AllowUI 属性,确定是否允许显示用户界面元素。
为了使控件更容易使用,用ScriptEngine类封装一下,下面是完整代码:
using System;
using MSScriptControl;
using System.Text;
namespace ScriptNameSpace
{
/// <summary>
/// 脚本类型
/// </summary>
public enum ScriptLanguage
{
/// <summary>
/// JScript脚本语言
/// </summary>
JScript,
/// <summary>
/// VBscript脚本语言
/// </summary>
VBscript,
/// <summary>
/// JavaScript脚本语言
/// </summary>
JavaScript
}
/// <summary>
/// 脚本运行错误代理
/// </summary>
public delegate void RunErrorHandler();
/// <summary>
/// 脚本运行超时代理
/// </summary>
public delegate void RunTimeoutHandler();
/// <summary>
/// ScriptEngine类
/// </summary>
public class ScriptEngine
{
private ScriptControl msc;
//定义脚本运行错误事件
public event RunErrorHandler RunError;
//定义脚本运行超时事件
public event RunTimeoutHandler RunTimeout;
/// <summary>
///构造函数
/// </summary>
public ScriptEngine()
: this(ScriptLanguage.VBscript)
{ }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="language">脚本类型</param>
public ScriptEngine(ScriptLanguage language)
{
this.msc = new ScriptControlClass();
this.msc.UseSafeSubset = true;
this.msc.Language = language.ToString();
((DScriptControlSource_Event)this.msc).Error += new DScriptControlSource_ErrorEventHandler(ScriptEngine_Error);
((DScriptControlSource_Event)this.msc).Timeout += new DScriptControlSource_TimeoutEventHandler(ScriptEngine_Timeout);
}
/// <summary>
/// 运行Eval方法
/// </summary>
/// <param name="expression">表达式</param>
/// <param name="codeBody">函数体</param>
/// <returns>返回值object</returns>
public object Eval(string expression, string codeBody)
{
msc.AddCode(codeBody);
return msc.Eval(expression);
}
/// <summary>
/// 运行Eval方法
/// </summary>
/// <param name="language">脚本语言</param>
/// <param name="expression">表达式</param>
/// <param name="codeBody">函数体</param>
/// <returns>返回值object</returns>
public object Eval(ScriptLanguage language, string expression, string codeBody)
{
if (this.Language != language)
this.Language = language;
return Eval(expression, codeBody);
}
/// <summary>
/// 运行Run方法
/// </summary>
/// <param name="mainFunctionName">入口函数名称</param>
/// <param name="parameters">参数</param>
/// <param name="codeBody">函数体</param>
/// <returns>返回值object</returns>
public object Run(string mainFunctionName, object[] parameters, string codeBody)
{
this.msc.AddCode(codeBody);
return msc.Run(mainFunctionName, ref parameters);
}
/// <summary>
/// 运行Run方法
/// </summary>
/// <param name="language">脚本语言</param>
/// <param name="mainFunctionName">入口函数名称</param>
/// <param name="parameters">参数</param>
/// <param name="codeBody">函数体</param>
/// <returns>返回值object</returns>
public object Run(ScriptLanguage language, string mainFunctionName, object[] parameters, string codeBody)
{
if (this.Language != language)
this.Language = language;
return Run(mainFunctionName, parameters, codeBody);
}
/// <summary>
/// 放弃所有已经添加到 ScriptControl 中的 Script 代码和对象
/// </summary>
public void Reset()
{
this.msc.Reset();
}
/// <summary>
/// 获取或设置脚本语言
/// </summary>
public ScriptLanguage Language
{
get { return (ScriptLanguage)Enum.Parse(typeof(ScriptLanguage), this.msc.Language, false); }
set { this.msc.Language = value.ToString(); }
}
/// <summary>
/// 获取或设置脚本执行时间,单位为毫秒
/// </summary>
public int Timeout
{
get { return 0; }
}
/// <summary>
/// 设置是否显示用户界面元素
/// </summary>
public bool AllowUI
{
get { return this.msc.AllowUI; }
set { this.msc.AllowUI = value; }
}
/// <summary>
/// 宿主应用程序是否有保密性要求
/// </summary>
public bool UseSafeSubset
{
get { return this.msc.UseSafeSubset; }
set { this.msc.UseSafeSubset = true; }
}
/// <summary>
/// RunError事件激发
/// </summary>
private void OnError()
{
if (RunError != null)
RunError();
}
/// <summary>
/// OnTimeout事件激发
/// </summary>
private void OnTimeout()
{
if (RunTimeout != null)
RunTimeout();
}
private void ScriptEngine_Error()
{
OnError();
}
private void ScriptEngine_Timeout()
{
OnTimeout();
}
}
}
在找到.NET驱动JS的方法以后,那么我们还需要找到QQ用来加密的那个JS文件,具体的JS文件大家可以到QQ的登录页面去DownLoad,如果不知道是哪一个JS大家可以通过抓包的方式去找到,这里就不再赘述了。下面我们就可以用MSScriptControl来驱动JS获取第一次加密的密码了,方法如下:
/// <summary>
/// 得到第一次加密后的密码
/// </summary>
/// <param name="jsFilePath">js文件</param>
/// <param name="funcName">加密的方法名</param>
/// <param name="paramers">加密方法需要传进的参数(一个是密码,另一个是页面上可获取的一个标志码)</param>
/// <returns>加密过后的密码</returns>
private object GetPassword(string jsFilePath, string funcName, params object[] paramers)
{
StreamReader reader = new StreamReader(jsFilePath);
string sScript = reader.ReadToEnd();
ScriptEngine se = new ScriptEngine(ScriptLanguage.JavaScript);
object obj = se.Run(funcName, paramers, sScript);
return obj;
}
通过上面的这个函数我们就可以对密码进行第一次加密了,下一步我们需要获取验证码。
我们可以使用HttpWebRequest类来Get请求这个地址:http://ptlogin2.qq.com/getimage来获取验证码,不过一定要记住把这次请求返回的cookie保存下来,我们可以将它保存到CookieContainer对象中,以便将这次返回的cookie加入到登录POST请求的头当中保持前后请求的一致性。
现在我们将获得的验证码转化成流或者其他的方式供不同的平台输出,我们发现QQ空间及邮箱的验证码生成的图像不是太复杂,所以可以考虑使用图像识别的方式自动的获取图像对应的字符(现在有很多第三方验证码识别软件),当然为了成功率考虑,最好还是让用户手动的输入。
好了有了验证码了,我们现在就将验证码字符加上刚刚我们加过密的密码形成新字串,再通过MD5加密
string pwd=FormsAuthentication.HashPasswordForStoringInConfigFile(this.Password, "MD5").ToLower()
形成最终我们需要的密码。
最后我们就可以将用户输入的用户名、密码一并POST到QQ相应的地址上去,这样我们就成功登陆QQ空间或邮箱了。登录成功过后你当然就可以获取联系人好友等等的操作了。
好了,文章就写到这了,希望对大家有用。^^ Brave chen
C# winForm中调用javascript文件中的方法的更多相关文章
- CUDA常见问题之无法在c文件中调用cu文件中定义的函数
当在C源文件中调用cu文件中定义的函数时,会出现undefined reference的问题,而在C++源文件中调用cu文件中定义的函数时则不会出现这个问题. 出现上述问题的原因是,nvcc编译器采用 ...
- VS开发】C中调用C++文件中定义的function函数
[VS开发]C中调用C++文件中定义的function函数 标签(空格分隔): [VS开发] 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 精要一揽 C调用 ...
- asp.net中调用javascript自定义函数的方法(包括引入JavaScript文件)总结
通常javascript代码可以与HTML标签一起直接放在前 端页面中,但如果JS代码多的话一方面不利于维护,另一方面也对搜索引擎不友好,因为页面因此而变得臃肿:所以一般有良好开发习惯的程序员都会把 ...
- Delphi 中调用JS文件中的方法
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- C++学习——在C文件中调用C++文件中的函数
1.CPP文件中的内容 #include "mytest.h" #include <iostream> using namespace std; int add(con ...
- 一步一步学Silverlight 2系列(21):如何在Silverlight中调用JavaScript
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- 在winform中调用js文件并输出结果
在winform中调用js文件并输出结果默认分类 2007-10-19 16:35:06 阅读25 评论0 字号:大中小 由于项目需要在winform中调一个强大的js,所以把这个tip记录在此: 1 ...
- JavaScript文件中调用AngularJS内部方法或改变$scope变量
需要在其他JavaScript文件中调用AngularJS内部方法或改变$scope变量,同时还要保持双向数据绑定: 首先获取AngularJS application: 方法一:通过controll ...
- java代码中fastjson生成字符串和解析字符串的方法和javascript文件中字符串和json数组之间的转换方法
1.java代码中fastjson生成字符串和解析字符串的方法 List<TemplateFull> templateFulls = new ArrayList<TemplateFu ...
随机推荐
- 利用scrapy下载图片保存到本地
1.先声明一下,起始位置已经是将所有的图片链接都能到pipelines.py中 2.创建一个类,继承于ImagesPipeline,因此也就需要导入ImagesPipeline from scrapy ...
- 多点搜的bfs
Problem L. 跑图Time limit: 1000msMemory limit: 65536KBDescription跑图是 RPG 游戏中很烦躁的事情.玩家需要跑到距离他最近的传送点的位置. ...
- 简单的Windows应用程序命名规则
读书:<高质量C++编程指南> 作者对“匈牙利”命名规则做了合理的简化,下述的命名规则简单易用,比较适合于Windows应用软件的开发. l [规则3-2-1]类名和函数名用大写字母开头的 ...
- Java 如何实现线程间通信?(notify、join、CountdownLatch、CyclicBarrier、FutureTask、Callable )
转自:https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247486499&idx=1&sn=d3f2d6959df ...
- linux kernel笔记
文章目录 关于linux内核中的__attribute__关键字 Linux kernel启动参数 gdt / ldt PCB 关于linux内核中的__attribute__关键字 part I: ...
- Write your own Terraform provider: Part 1
转自:https://container-solutions.com/write-terraform-provider-part-1/ This is the first part of a seri ...
- Using C++11 function & bind
The example of callback in C++11 is shown below. #include <functional> void MyFunc1(int val1, ...
- S老师 Shader 学习
Mesh Filter : 存储一个Mesh(网格,模型的网格,就是模型的由哪些三角面组成,组成一个什么样子的模型,三角面的一些顶点信息) Mesh Renderer:用来渲染一个模型的外观,就是样子 ...
- RTMP、RTSP、HTTP可用的地址
香港卫视: rtmp://live.hkstv.hk.lxdns.com/live/hks1 香港财经,rtmp://202.69.69.180:443/webcast/bshdlive-pc 韩国 ...
- AD10 没有原理图是否可以修改 PCB
AD10 没有原理图是否可以修改 PCB 有朋友问 AD 是否可以在没有原理的情况下修改 PCB 呢? 答案是肯定的,可以. 比如增加元件和网络,可以先增加元件封装,再打开网络管理给焊盘加上网络. 相 ...