wx_ext 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,383 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'digest'
4
+ require 'rest_client'
5
+ require 'json'
6
+ require 'nokogiri'
7
+
8
+ module WxExt
9
+ # 微信扩展接口, 模拟登陆微信公众平台
10
+ # @author FuShengYang
11
+ class WeiXin
12
+ attr_accessor :account, :password, :home_url, :token, :user_name, \
13
+ :ticket_id, :ticket, :cookies, :operation_seq
14
+ def initialize(account, password)
15
+ @account = account
16
+ @password = password
17
+ @home_url = 'https://mp.weixin.qq.com'
18
+ @token = nil
19
+ @ticket = nil
20
+ @user_name = nil
21
+ @ticket_id = nil
22
+ @cookies = {}
23
+ @operation_seq = ''
24
+ end
25
+
26
+ # 模拟登陆微信公众平台, 初始化 access_token, cookies
27
+ #
28
+ # @return [Hash] 使用用户名和密码登陆微信公众平台获取access_token, 过期时间是7200s
29
+ def login
30
+ password = Digest::MD5.hexdigest @password
31
+ login_headers = {
32
+ referer: 'https://mp.weixin.qq.com/'
33
+ }
34
+ login_params = {
35
+ username: @account,
36
+ pwd: password,
37
+ imgcode: '',
38
+ f: 'json'
39
+ }
40
+
41
+ resource = RestClient::Resource.new(@home_url, headers: login_headers)
42
+ res = resource['cgi-bin/login'].post login_params
43
+ @cookies = res.cookies
44
+ return_hash = {
45
+ status: 0,
46
+ msg: 'ok'
47
+ }
48
+ # {"base_resp"=>{"ret"=>0, "err_msg"=>"ok"}, "redirect_url"=>"/cgi-bin/home?t=home/index&lang=zh_CN&token=1869497342"}
49
+ # {"base_resp":{"ret":-8,"err_msg":"need verify code"}}
50
+ # {"base_resp":{"ret":-23,"err_msg":"acct\/password error"}}
51
+ # {"base_resp":{"ret":-21,"err_msg":"user not exist"}}
52
+ # https://mp.weixin.qq.com/cgi-bin/verifycode?username=tuodan@thecampus.cc&r=1415774604450
53
+ res_hash = JSON.parse res.to_s
54
+ sta = res_hash['base_resp']['ret'].to_s
55
+ if sta == '0'
56
+ token_reg = /.*token=(\d+)\".*/
57
+ @token = $1 if token_reg =~ res.to_s
58
+ elsif sta == '-8'
59
+ return_hash = {
60
+ status: -8,
61
+ msg: 'need_varify_code'
62
+ }
63
+ elsif sta == '-23'
64
+ return_hash = {
65
+ status: -23,
66
+ msg: 'password_error'
67
+ }
68
+ elsif sta == '-21'
69
+ return_hash = {
70
+ status: -21,
71
+ msg: 'user_not_exist'
72
+ }
73
+ else
74
+ return_hash = {
75
+ status: -1,
76
+ msg: 'system_error'
77
+ }
78
+ end
79
+ return_hash
80
+ end
81
+
82
+ # 初始化 ticket, cookies, operation_seq, user_name 等等信息
83
+ def init
84
+ msg_send_url = 'https://mp.weixin.qq.com/cgi-bin/masssendpage'\
85
+ "?t=mass/send&token=#{@token}&lang=zh_CN"
86
+ msg_send_page = RestClient.get msg_send_url, cookies: @cookies
87
+ @cookies = @cookies.merge msg_send_page.cookies
88
+
89
+ ticket_reg = /.*ticket\s*:\s*\"(\w+)\".*user_name\s*:\s*\"(.*)\",.*nick_name\s*:\s*\"(.*)\".*/m
90
+ operation_seq_reg = /.*operation_seq\s*:\s*\"(\d+)\".*/
91
+ @operation_seq = $1 if operation_seq_reg =~ msg_send_page.to_s
92
+ if ticket_reg =~ msg_send_page.to_s
93
+ @ticket = $1
94
+ @user_name = @ticket_id= $2
95
+ true
96
+ else
97
+ false
98
+ end
99
+ end
100
+
101
+ # 上传图片素材到素材中心
102
+ def upload_file(file, file_name, folder = '/cgi-bin/uploads')
103
+ upload_url = 'https://mp.weixin.qq.com/cgi-bin/filetransfer'\
104
+ '?action=upload_material&f=json&writetype=doublewrite'\
105
+ "&groupid=1&ticket_id=#{@ticket_id}"\
106
+ "&ticket=#{@ticket}&token=#{@token}&lang=zh_CN"
107
+ response = RestClient.post upload_url, file: file, \
108
+ Filename: file_name, \
109
+ folder: folder
110
+ JSON.parse response.to_s
111
+ end
112
+
113
+ # 发送单条图文消息到素材中心
114
+ def upload_single_msg(single_msg_params)
115
+ post_single_msg_uri = 'cgi-bin/operate_appmsg'\
116
+ '?t=ajax-response&sub=create&type=10&token'\
117
+ "=#{@token}&lang=zh_CN"
118
+ headers = {
119
+ referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit'\
120
+ '&action=edit&type=10&isMul=0&isNew=1&lang=zh_CN'\
121
+ "&token=#{@token}"
122
+ }
123
+ resource = RestClient::Resource.new(@home_url, headers: headers,
124
+ cookies: @cookies)
125
+ res = resource[post_single_msg_uri].post single_msg_params
126
+ # {"ret":"0", "msg":"OK"}
127
+ JSON.parse res.to_s
128
+ end
129
+
130
+ # 发送多图文到素材中心
131
+ def upload_multi_msg(msg_params)
132
+ uri = 'cgi-bin/operate_appmsg?t=ajax-response&sub=create&type=10'\
133
+ "&token=#{@token}&lang=zh_CN"
134
+ headers = {
135
+ referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg'\
136
+ '?t=media/appmsg_edit&action=edit&type=10'\
137
+ "&isMul=1&isNew=1&lang=zh_CN&token=#{@token}"
138
+ }
139
+ resource = RestClient::Resource.new(@home_url, headers: headers,
140
+ cookies: @cookies)
141
+ post_msg_res = resource[uri].post msg_params
142
+ # {"ret":"0", "msg":"OK"}
143
+ JSON.parse post_msg_res.to_s
144
+ end
145
+
146
+ # 图文预览功能
147
+ def preview_msg(msg_params_with_name)
148
+ uri = 'cgi-bin/operate_appmsg?sub=preview&t=ajax-appmsg-preview'\
149
+ "&type=10&token=#{@token}&lang=zh_CN"
150
+ headers = {
151
+ referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit'\
152
+ "&action=edit&type=10&isMul=0&isNew=1&lang=zh_CN&token=#{@token}"
153
+ }
154
+ resource = RestClient::Resource.new(@home_url, headers: headers,
155
+ cookies: @cookies)
156
+
157
+ res = resource[uri].post msg_params_with_name
158
+ # {"ret":"0", "msg":"preview send success!", "appMsgId":"201796045", "fakeid":""}
159
+ JSON.parse res.to_s
160
+ end
161
+
162
+ # 群发图文消息
163
+ def broadcast_msg(msg_params)
164
+ uri = "cgi-bin/masssend?t=ajax-response&token=#{@token}&lang=zh_CN"
165
+ headers = {
166
+ referer: 'https://mp.weixin.qq.com/cgi-bin/masssendpage'\
167
+ "?t=mass/send&token=#{token}&lang=zh_CN",
168
+ host: 'mp.weixin.qq.com'
169
+ }
170
+ resource = RestClient::Resource.new(@home_url, headers: headers,
171
+ cookies: @cookies)
172
+ post_msg_res = resource[uri].post msg_params
173
+ # {"ret":"0", "msg":"OK"}
174
+ JSON.parse post_msg_res.to_s
175
+ end
176
+
177
+ # 获取所有的图文列表
178
+ def get_app_msg_list(msg_begin = 0, msg_count = 10)
179
+ url = 'https://mp.weixin.qq.com/cgi-bin/appmsg?type=10&action=list'\
180
+ "&begin=#{msg_begin}&count=#{msg_count}&f=json&token=#{@token}"\
181
+ "&lang=zh_CN&token=#{@token}&lang=zh_CN&f=json&ajax=1"\
182
+ "&random=#{rand}"
183
+ msg_json = RestClient.get url, cookies: @cookies
184
+ JSON.parse msg_json.to_s
185
+ end
186
+
187
+ # 轮训新消息条数
188
+ def get_new_msg_num(last_msg_id)
189
+ uri = 'cgi-bin/getnewmsgnum?f=json&t=ajax-getmsgnum'\
190
+ "&lastmsgid=#{last_msg_id}&token=#{@token}&lang=zh_CN"
191
+ post_params = {
192
+ ajax: 1,
193
+ f: 'json',
194
+ lang: 'zh_CN',
195
+ random: rand,
196
+ token: @token
197
+ }
198
+ post_headers = {
199
+ referer: 'https://mp.weixin.qq.com/cgi-bin/message?t=message/list'\
200
+ "&count=20&day=7&token=#{@token}&lang=zh_CN"
201
+ }
202
+ resource = RestClient::Resource.new(@home_url, headers: post_headers,
203
+ cookies: @cookies)
204
+ res = resource[uri].post post_params
205
+ JSON.parse res.to_s
206
+ end
207
+
208
+ # 获取联系人信息
209
+ def get_contact_info(fakeid)
210
+ uri = 'cgi-bin/getcontactinfo?t=ajax-getcontactinfo'\
211
+ "&lang=zh_CN&fakeid=#{fakeid}"
212
+ post_params = {
213
+ ajax: 1,
214
+ f: 'json',
215
+ lang: 'zh_CN',
216
+ random: rand,
217
+ token: @token
218
+ }
219
+ post_headers = {
220
+ referer: 'https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index'\
221
+ "&pagesize=10&pageidx=0&type=0&token=#{@token}&lang=zh_CN"
222
+ }
223
+ resource = RestClient::Resource.new(@home_url, headers: post_headers,
224
+ cookies: @cookies)
225
+ res = resource[uri].post post_params
226
+ JSON.parse res.to_s
227
+ end
228
+
229
+ # 获取国家列表
230
+ def get_country_list
231
+ url = 'https://mp.weixin.qq.com/cgi-bin/getregions'\
232
+ "?t=setting/ajax-getregions&id=0&token=#{@token}&lang=zh_CN"\
233
+ "&token=#{@token}&lang=zh_CN&f=json&ajax=1&random=#{rand}"
234
+ resource = RestClient::Resource.new(url, cookies: @cookies)
235
+ res = resource.get
236
+ JSON.parse res.to_s
237
+ end
238
+
239
+ # 获取每日可推送消息数
240
+ def get_day_msg_count
241
+ url = 'https://mp.weixin.qq.com/cgi-bin/masssendpage'\
242
+ "?t=mass/send&token=#{@token}&lang=zh_CN"
243
+ res = RestClient.get(url, cookies: @cookies)
244
+ day_msg_count = 0
245
+ reg = /.*mass_send_left\s*:\s*can_verify_apply\s*\?\s*\'(\d*)\'\*/
246
+ day_msg_count = $1 if reg =~ res.to_s
247
+ day_msg_count.to_i
248
+ end
249
+
250
+ # 获取 total_count, count, day, frommsgid, can_search_msg, offset, action=search, keyword, last_msg_id, filterivrmsg=0/1 和 msg_items
251
+ def get_msg_items(count = 20, day = 7, filterivrmsg = 1, action='', keyword='', frommsgid='', offset='')
252
+ url = 'https://mp.weixin.qq.com/cgi-bin/message?t=message/list'\
253
+ "&action=#{action}&keyword=#{keyword}&frommsgid=#{frommsgid}&offset=#{offset}&count=#{count}"\
254
+ "&day=#{day}filterivrmsg=#{filterivrmsg}&token=#{@token}&lang=zh_CN"
255
+ resource = RestClient::Resource.new(url, cookies: @cookies)
256
+ res = resource.get
257
+ reg = /.*total_count\s*:\s*(\d*).*latest_msg_id\s*:\s*\'(\d*)\'.*list\s*:\s*\((.*)\)\.msg_item,.*filterivrmsg\s*:\s*\"(\d*)\".*/m
258
+ return_hash = {
259
+ status: -1,
260
+ msg: 'system_error'
261
+ }
262
+ if reg =~ res.to_s
263
+ return_hash = {
264
+ status: 0,
265
+ msg: 'ok',
266
+ total_count: $1,
267
+ latest_msg_id: $2,
268
+ count: 20,
269
+ day: 7,
270
+ frommsgid: '',
271
+ can_search_msg: '1',
272
+ offset: '',
273
+ action: '',
274
+ keyword: '',
275
+ msg_items: JSON.parse($3)['msg_item'],
276
+ filterivrmsg: $4
277
+ }
278
+ end
279
+ return_hash
280
+ end
281
+
282
+ # 获取粉丝数目
283
+ def get_fans_count
284
+ url = 'https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index'\
285
+ "&pagesize=10&pageidx=0&type=0&token=#{ @token }&lang=zh_CN"
286
+ res = RestClient.get(url, cookies: @cookies)
287
+ reg = /.*pageIdx\s*:\s*(\d*).*pageCount\s*:\s*(\d*).*pageSize\s*:\s*(\d*).*groupsList\s*:\s*\((.*)\)\.groups,.*friendsList\s*:\s*\((.*)\)\.contacts,.*totalCount\s*:\s*\'(\d*)\'\s*\*\s*.*/m
288
+ return_hash = {
289
+ status: -1,
290
+ msg: 'system_error'
291
+ }
292
+ if reg =~ res.to_s
293
+ return_hash = {
294
+ status: 0,
295
+ msg: 'ok',
296
+ page_index: $1,
297
+ page_count: $2,
298
+ page_size: $3,
299
+ group_list: JSON.parse($4)['groups'],
300
+ friends_list: JSON.parse($5)['contacts'],
301
+ total_count: $6
302
+ }
303
+ end
304
+ return_hash
305
+ end
306
+
307
+ # {"base_resp":{"ret":10706,"err_msg":"customer block"}} 48小时内的才行
308
+ # {"base_resp":{"ret":0,"err_msg":"ok"}}
309
+ # 快速回复
310
+ def quick_reply(content, quickreplyid, tofakeid)
311
+ post_uri = 'cgi-bin/singlesend'\
312
+ "?t=ajax-response&f=json&token=#{ @token }&lang=zh_CN"
313
+ params = {
314
+ ajax: 1,
315
+ content: content,
316
+ f: 'json',
317
+ imgcode: '',
318
+ lang: 'zh_CN',
319
+ mask: false,
320
+ quickreplyid: quickreplyid,
321
+ random: rand,
322
+ tofakeid: tofakeid,
323
+ token: @token,
324
+ type: 1
325
+ }
326
+ headers = {
327
+ referer: 'https://mp.weixin.qq.com/cgi-bin/message'\
328
+ "?t=message/list&count=20&day=7&token=#{ @token }&lang=zh_CN"
329
+ }
330
+ resource = RestClient::Resource.new(@home_url, headers: headers,
331
+ cookies: @cookies)
332
+ res = resource[post_uri].post params
333
+ JSON.parse res.to_s
334
+ end
335
+
336
+ # https://mp.weixin.qq.com/cgi-bin/setstarmessage?t=ajax-setstarmessage&token=1664040225&lang=zh_CN
337
+ # { "ret":0, "msg":"sys ok"}
338
+ # 收藏消息
339
+ def collect_msg(msgid)
340
+ uri = "cgi-bin/setstarmessage?t=ajax-setstarmessage&token=#{ @token }&lang=zh_CN"
341
+ params = {
342
+ ajax: 1,
343
+ f: 'json',
344
+ lang: 'zh_CN',
345
+ msgid: msgid,
346
+ random: rand,
347
+ token: @token,
348
+ value: 1
349
+ }
350
+ headers = {
351
+ referer: 'https://mp.weixin.qq.com/cgi-bin/message'\
352
+ "?t=message/list&token=#{ @token }&count=20&day=7"
353
+ }
354
+ resource = RestClient::Resource.new(@home_url, headers: headers,
355
+ cookies: @cookies)
356
+ res = resource[uri].post params
357
+ JSON.parse res.to_s
358
+ end
359
+
360
+ # 取消收藏消息
361
+ def un_collect_msg(msgid)
362
+ uri = "cgi-bin/setstarmessage?t=ajax-setstarmessage&token=#{ @token }&lang=zh_CN"
363
+ params = {
364
+ ajax: 1,
365
+ f: 'json',
366
+ lang: 'zh_CN',
367
+ msgid: msgid,
368
+ random: rand,
369
+ token: @token,
370
+ value: 0
371
+ }
372
+ headers = {
373
+ referer: 'https://mp.weixin.qq.com/cgi-bin/message'\
374
+ "?t=message/list&token=#{ @token }&count=20&day=7"
375
+ }
376
+ resource = RestClient::Resource.new(@home_url, headers: headers,
377
+ cookies: @cookies)
378
+ res = resource[uri].post params
379
+ # { "ret":0, "msg":"sys ok"}
380
+ JSON.parse res.to_s
381
+ end
382
+ end
383
+ end