wx_ext 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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