WinXin机器人实现

2024-06-23 17:08
文章标签 实现 机器人 winxin

本文主要是介绍WinXin机器人实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载自csdn

陈国林

前辈的博客,非常感谢



一. 引言

      我们都知道,微信提供了多种登录的方式,包括手机端、电脑端以及web端。

      web端的登录,我们用Python程序完全可以模拟出来~~(如果你不知道,那也没关系,稍微了解下Python request session即可)

      而所谓的机器人实际上就是后台一个智能的程序,类似“微软小冰”,“iPhone siri”。今天我们要用的是一个开放的机器人API,“图灵机器人”

      下面就让我们一步步分析如何,通过模拟web端微信登录+“图灵机器人” 实现一个微信机器人


二. 深入分析

      1. web版微信不是用用户名密码而是用扫描二维码登录,如何实现的呢?

          让我们登录https://wx.qq.com/,查看此时的网络请求情况 如下图所示

          1). 实际上客户端会先发送一个js get请求,请求url为https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=1469852355025

仔细分析这个请求,会发现有已下几个参数

appid: wx782c26e4c19acffb //这个值不变,表示来自微信网页版

redirect_uri: https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage //这个也是一个固定值

fun: new //固定值位new

lang: zh_CN //表示中文

_: 1469852355025 //13位时间戳

2).然后服务端返回数据,window.QRLogin.code = 200; window.QRLogin.uuid = "IatVataLfQ==";

2. 多刷新几次,你会发现服务端的返回值中window.QRLogin.uuid的值每次都在变化。

实际上uuid是服务端用来标识一次登录的通信id

       

       


        2. 当我们拿到uuid后,就需要获取二维码,继续查看当前的网络请求

            1). 客户端继续发送一个js get 请求,url为https://login.weixin.qq.com/qrcode/IatVataLfQ==

仔细分析这个请求,会发现qrcode后跟着的值就是从上一个请求拿到的uuid值

2). 当拿到二维码之后,还需用微信客户端进行扫描(god,都有客户端了为什么还需用用web登录~~~~)

        3. ok,拿出手机扫描屏幕的二维码,继续查看网络请求

           1).  当我们在APP上点击登录按钮之后,实际上客户端是向服务端发送了一个js的get 请求,url为https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=od5FW4ipFw==&tip=0&r=-979422099&_=1469857970642

仔细分析这个请求,会发现有以下几个参数

uuid: od5FW4ipFw== //从上面请求得到的数据

tip: 0 //表示等待用户扫描确认

r: -979422099 //随机9位数字

_: 1469857970642 //13位时间戳

2). 这个请求,返回结果如下所示

window.code=200;
window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AUyRV3zm5RBTWt-mEvvDz8oz@qrticket_0&uuid=od5FW4ipFw==&lang=zh_CN&scan=1469858238";

code=200表示的是成功,redirect_uri表示需要我们继续请求的url

      

      

       4. 继续上一个请求得到的redirect_uri

1). ok,分析这个uri请求https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AUyRV3zm5RBTWt-mEvvDz8oz@qrticket_0&uuid=od5FW4ipFw==&lang=zh_CN&scan=1469858238&fun=new&version=v2,对应参数如下所示

uuid: 同前面

scan: 1469858238 //表示用户扫描的时间戳,10位

其它参数保持不变即可

2). 这个请求会返回,我们登陆所需要的信息,返回值是一个xml数据,如下所示

<error><ret>0</ret><message>OK</message><skey>@crypt_b13bcf4_edeadfd5xxxxd5e6b289b614fac25e5ac</skey><wxsid>HON+SKvxxxxTihHV</wxsid><wxuin>8xxxx5640</wxuin><pass_ticket>um3UATy9MNzcwDDkVT4xxxxMn5B25G%2FcYIAVbpHnF8vU23yMflmUCFsZkMKbIJIP</pass_ticket><isgrayscale>1</isgrayscale></error>

(为了我的隐私,我把返回值做了一定的打码~~)

ret: 表示请求返回状态码,0表示成功

skey和wxsid以及wxuin都是具体微信用户的信息,不会变的,在后续的通信过程中需要用到

pass_ticket: 这个值在初始化登录页面的时候需要用到

      5. 现在我们已经拿到了用户认证相关的信息,包括skey和wxsid以及wxuin,需要初始化登录页面

什么是初始化登录页面,也就是我们平时登录APP客户端看到的那个页面,我们需要发送一个请求到服务端拿到数据,获取到常用的联系人和微信公众号

如下图所示,这个请求是一个post请求,需要我们带一些用户认证相关的信息到服务端

1). ok,让我们分析一下这个请求url: https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-979155549&pass_ticket=um3UATy9MNzcwDDkVT4xxxxMn5B25G%252FcYIAVbpHnF8vU23yMflmUCFsZkMKbIJIP

r: 随机的9位数据

pass_ticke: 从上一步请求返回值中获取的数据

2). post请求所需要的data,如下所示

{
          'BaseResponse': {
              'Uin': wxuin,
              'Sid': wxsid,
              'Skey': skey,
              'DeviceID': //15位随机串 'e'+str(random.random())[2:17]
          }
        }

3). 请求返回数据,如下所示

Ret: 0表示返回成功,ContactList表示的是联系人列表。

返回数据包含了当前登录账户的相关信息,比如wxuid,昵称 ...

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. {  
  2. "BaseResponse": {  
  3. "Ret": 0,  
  4. "ErrMsg": ""  
  5. }  
  6. ,  
  7. "Count": 10,  
  8. "ContactList": [{  
  9. "Uin": 0,  
  10. "UserName": "filehelper",  
  11. "NickName": "xxxx",  
  12. "HeadImgUrl": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=653892799&username=filehelper&skey=@crypt_b13bcf4_edeadfd5615d5e6b289b614fac25e5ac",  
  13. "ContactFlag": 1,  
  14. "MemberCount": 0,  
  15. "MemberList": [],  
  16. "RemarkName": "",  
  17. "HideInputBarFlag": 0,  
  18. "Sex": 0,  
  19. "Signature": "",  
  20. "VerifyFlag": 0,  
  21. "OwnerUin": 0,  
  22. "PYInitial": "WJCSZS",  
  23. "PYQuanPin": "wenjianchuanshuzhushou",  
  24. "RemarkPYInitial": "",  
  25. "RemarkPYQuanPin": ""   
  26.  ...  

6. 登录成功,接下来我们要做的就是开启消息状态通知。

ok,继续看此时的网络请求,会发现客户端向服务端发送了一个post请求

https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?pass_ticket=um3UATy9MNzcwDDkVT42sVxMn5xxxx%252FcYIAVbpHnF8vU23yMflmUCFsZkMKbIJIP

1). 对于这个请求,相信大家都不会感到陌生,就只有一个参数pass_ticket,同上

2). post请求,需要的data模式如下

{
          'BaseResponse': {
              'Uin': wxuin,
              'Sid': wxsid,
              'Skey': skey,
              'DeviceID': //15位随机串 'e'+str(random.random())[2:17]
          }
          'ClientMsgId': 13位时间戳,
          'Code': 3  //固定值
          'FromUserName':  userNmae, //从初始化登录信息那边取到
          'ToUserName': userNmae, //从初始化登录信息那边取到
       }

3. 请求返回一个json数据

{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MsgID": "4049260553244269433"
}

Ret:0表示的是请求返回成功状态

     

        7. ok,到目前为止我们以及成功登录了微信并且开启了消息通知

            让我继续查看网页客户端,会发现有非常多如下图所示的请求。从请求名称中,我们知道这些请求在进行 同步刷新,轮询检查服务端的消息

            1). 分析下,当前get请求,https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=1469858460705&skey=%40crypt_b13bcf4_edeadfdxxxxx5e6b289b614fac25e5ac&sid=HON%2BSKxxxxxxxxxV&uin=828xxxx40&deviceid=e477405243870570&synckey=1_653921573%7C2_653921810%7C3_653921702%7C11_653919729%7C13_653890051%7C201_1469858241%7C1000_1469856425%7C1001_1469851411&_=1469857970652

a. r --> 13位时间戳
       b. skey 同上,需要url quote
       c. sid 同上
       d. devicedid 同上
       e. synckey由 初始化登录页面信息返回串中Sync的list列表组成, 需要url quote
       f. _ 13位时间戳

2). 请求返回json数据,如下所示window.synccheck={retcode:"0",selector:"0"}

retcode:
        a. 0 正常
        b. 1100 失败/登出微信
        c. 1101 从其它设备登录微信网页版
       selector:
        a. 0 正常
        b. 2 新的消息
        c. 7 手机操作了微信

        

        

       8. ok,万事具备,只需要知道如何获取消息和发送消息即可了。

           让我们先看一下,当我们在网页上收到消息的时候,不断轮询的同步刷新请求会返回,window.synccheck={retcode:"0",selector:"2"} 或者是 window.synccheck={retcode:"0",selector:"6"}

           1). 这个时候,我们发现客户端会向服务端发送一个post请求,拉取新的消息数据,如下图所示

                post请求: https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=HONxxxxxqSwTihHV&skey=@crypt_b13bcf4_edeadfd5615d5xxxxx9b614fac25e5ac&pass_ticket=um3UATy9MNzcwDDkVTxxxxxMn5B25G%252FcYI

请求所带的参数同上

2). 请求会返回json数据,包含具体的消息数据和类型

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. {  
  2. "BaseResponse": {  
  3. "Ret": 0,  
  4. "ErrMsg": ""  
  5. }  
  6. ,  
  7. "AddMsgCount": 1,  
  8. "AddMsgList": [{  
  9. "MsgId": "4937824389423381364",  
  10. "FromUserName": "@ca2e7ef4exxxxxd71ab5fd68ac405b70",  
  11. "ToUserName": "@c26fa48f87634xxxxxx1ada0a4fa30f",  
  12. "MsgType": 1,  
  13. "Content": "[投降]",  
  14. "Status": 3,  
  15. "ImgStatus": 1,  
  16. "CreateTime": 1469861910,  
  17. "VoiceLength": 0,  
  18. "PlayLength": 0,  
  19. "FileName": "",  
  20. "FileSize": "",  
  21. "MediaId": "",  
  22. "Url": "",  
  23. "AppMsgType": 0,  
  24. "StatusNotifyCode": 0,  
  25. "StatusNotifyUserName": "",  
  26. "RecommendInfo": {  
  27. "UserName": "",  
  28. "NickName": "",  
  29. "QQNum": 0,  
  30. "Province": "",  
  31. "City": "",  
  32. "Content": "",  
  33. "Signature": "",  
  34. "Alias": "",  
  35. "Scene": 0,  
  36. "VerifyFlag": 0,  
  37. "AttrStatus": 0,  
  38. "Sex": 0,  
  39. "Ticket": "",  
  40. "OpCode": 0  
  41. }  
  42. ,  
  43. "ForwardFlag": 0,  
  44. "AppInfo": {  
  45. "AppID": "",  
  46. "Type": 0  
  47. }  
  48. ,  
  49. "HasProductId": 0,  
  50. "Ticket": "",  
  51. "ImgHeight": 0,  
  52. "ImgWidth": 0,  
  53. "SubMsgType": 0,  
  54. "NewMsgId": 4937824389423381364  
  55. }  
  56. ],  
  57. "ModContactCount": 0,  
  58. "ModContactList": [],  
  59. "DelContactCount": 0,  
  60. "DelContactList": [],  
  61. "ModChatRoomMemberCount": 0,  
  62. "ModChatRoomMemberList": [],  
  63. "Profile": {  
  64. "BitFlag": 0,  
  65. "UserName": {  
  66. "Buff": ""  
  67. }  
  68. ,  
  69. "NickName": {  
  70. "Buff": ""  
  71. }  
  72. ,  
  73. "BindUin": 0,  
  74. "BindEmail": {  
  75. "Buff": ""  
  76. }  
  77. ,  
  78. "BindMobile": {  
  79. "Buff": ""  
  80. }  
  81. ,  
  82. "Status": 0,  
  83. "Sex": 0,  
  84. "PersonalCard": 0,  
  85. "Alias": "",  
  86. "HeadImgUpdateFlag": 0,  
  87. "HeadImgUrl": "",  
  88. "Signature": ""  
  89. }  
  90. ,  
  91. "ContinueFlag": 0,  
  92. "SyncKey": {  
  93. "Count": 8,  
  94. "List": [{  
  95. "Key": 1,  
  96. "Val": 653921573  
  97. }  
  98. ,{  
  99. "Key": 2,  
  100. "Val": 653921823  
  101. }  
  102. ,{  
  103. "Key": 3,  
  104. "Val": 653921702  
  105. }  
  106. ,{  
  107. "Key": 11,  
  108. "Val": 653919729  
  109. }  
  110. ,{  
  111. "Key": 13,  
  112. "Val": 653890051  
  113. }  
  114. ,{  
  115. "Key": 201,  
  116. "Val": 1469861910  
  117. }  
  118. ,{  
  119. "Key": 1000,  
  120. "Val": 1469856425  
  121. }  
  122. ,{  
  123. "Key": 1001,  
  124. "Val": 1469851411  
  125. }  
  126. ]  
  127. }  
  128. ,  
  129. "SKey": ""  
  130. }  
a. BaseResponse,Ret位0表示返回成功
       b. AddMsgCount 表示新消息个数
       c. AddMsgList 表示新消息列表
          MsgType   说明
          1     文本消息
          3     图片消息
          34    语音消息
          37    VERIFYMSG
          40    POSSIBLEFRIEND_MSG
          42    共享名片
          43    视频通话消息
          47    动画表情
          48    位置消息
          49    分享链接
          50    VOIPMSG
          51    微信初始化消息
          52    VOIPNOTIFY
          53    VOIPINVITE
          62    小视频
          9999  SYSNOTICE
          10000     系统消息
          10002     撤回消息



           10.  最后让我们来看一下,如何发送一个消息

                  1). 当我发送一个消息给好友的时候,实际是执行了一次post请求,如下图

                       url: https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=um3UATy9MNzcwDDkVT42sVxxxxxxxxG%252FcYIAVbpHnF8vU23yMflmUCFsZkMKbIJIP

2). post请求需要的data如下所示

{
          'BaseResponse': {
              'Uin': wxuin,
              'Sid': wxsid,
              'Skey': skey,
              'DeviceID': //15位随机串 'e'+str(random.random())[2:17]
          }
          'Type': //消息类型,同上
          'Content': //消息内容
          'FromUserName':  //发送用户
          'ToUserName': //接受用户
          'LocalID':  //13位时间戳+4位随机数
          'ClientMsgId': //同LocalId
        }

3). 当发送成功之后,服务端返回json数据

{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MsgID": "2882629525509760458",
"LocalID": "14698626523310328"
}

Ret:0表示发送成功



  ok,到此我们就知道了整个微信网页版从登陆到数据发送的整个过程。

  现在我们只剩下最后一步,机器人了。

  我们要实现的是,收到消息后自动根据消息进行回复。

  这个我们只需要在收到消息的时候,利用收到的消息调用“图灵机器人”API获取智能回答的数据,然后发送给朋友即可。

 

  图灵机器人,http://www.tuling123.com/

  

  欢迎来拍砖,github源码: https://github.com/chenguolin/weixin_robot


二. 效果分析

     我申请了个图灵机器人,取名为[【呆萌小白】

     下面是简单的和机器人的对话(无聊~~)

     

     


这篇关于WinXin机器人实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087761

相关文章

C#高效实现在Word文档中自动化创建图表的可视化方案

《C#高效实现在Word文档中自动化创建图表的可视化方案》本文将深入探讨如何利用C#,结合一款功能强大的第三方库,实现在Word文档中自动化创建图表,为你的数据呈现和报告生成提供一套实用且高效的解决方... 目录Word文档图表自动化:为什么选择C#?从零开始:C#实现Word文档图表的基本步骤深度优化:C

nginx跨域访问配置的几种方法实现

《nginx跨域访问配置的几种方法实现》本文详细介绍了Nginx跨域配置方法,包括基本配置、只允许指定域名、携带Cookie的跨域、动态设置允许的Origin、支持不同路径的跨域控制、静态资源跨域以及... 目录一、基本跨域配置二、只允许指定域名跨域三、完整示例四、配置后重载 nginx五、注意事项六、支持

Qt实现对Word网页的读取功能

《Qt实现对Word网页的读取功能》文章介绍了几种在Qt中实现Word文档(.docx/.doc)读写功能的方法,包括基于QAxObject的COM接口调用、DOCX模板替换及跨平台解决方案,重点讨论... 目录1. 核心实现方式2. 基于QAxObject的COM接口调用(Windows专用)2.1 环境

MySQL查看表的历史SQL的几种实现方法

《MySQL查看表的历史SQL的几种实现方法》:本文主要介绍多种查看MySQL表历史SQL的方法,包括通用查询日志、慢查询日志、performance_schema、binlog、第三方工具等,并... 目录mysql 查看某张表的历史SQL1.查看MySQL通用查询日志(需提前开启)2.查看慢查询日志3.

Java实现字符串大小写转换的常用方法

《Java实现字符串大小写转换的常用方法》在Java中,字符串大小写转换是文本处理的核心操作之一,Java提供了多种灵活的方式来实现大小写转换,适用于不同场景和需求,本文将全面解析大小写转换的各种方法... 目录前言核心转换方法1.String类的基础方法2. 考虑区域设置的转换3. 字符级别的转换高级转换

使用Python实现局域网远程监控电脑屏幕的方法

《使用Python实现局域网远程监控电脑屏幕的方法》文章介绍了两种使用Python在局域网内实现远程监控电脑屏幕的方法,方法一使用mss和socket,方法二使用PyAutoGUI和Flask,每种方... 目录方法一:使用mss和socket实现屏幕共享服务端(被监控端)客户端(监控端)方法二:使用PyA

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配