weixin_public 0.0.1 → 0.0.2
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.
- data/Gemfile +4 -1
- data/README.md +37 -26
- data/Rakefile +8 -0
- data/lib/weixin_public/version.rb +1 -1
- data/lib/weixin_public.rb +80 -25
- data/test/avatar.jpg +0 -0
- data/test/test_helper.rb +3 -0
- data/test/weixin_test.rb +45 -0
- data/weixin_public.gemspec +2 -0
- metadata +31 -5
- data/.gitignore +0 -17
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
# Weixin公众账号接口
|
|
2
|
+
|
|
3
|
+
根据Weixin公众账号Web管理控制台协议工作,本接口实现仅供参考。
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
2013-4-30:首次发布
|
|
7
|
+
2013-5-10:接口修改为HTTPS模式工作,对于无法登录的情况增加sig和cert参数辅助登录冲,部分代码重构
|
|
8
|
+
```ruby
|
|
9
|
+
说明:一般情况下,如果登录时返回400,Error-6的错误的错误,请在登录时增加sig和cert参数,可以通过网页登录后在cookie里获取这两个参数的值填到参数里。没有sig参数的web page登录会弹出验证码,有时没这两个参数,或者没有sig时也能成功。
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Demo
|
|
13
|
+
```ruby
|
|
14
|
+
require 'weixin_public.rb'
|
|
15
|
+
client = WeixinPublicClient::WeixinPubClient.new('x@gmail.com','123')
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
群发文本消息:
|
|
19
|
+
```ruby
|
|
20
|
+
client.get_fans.each do |fan|
|
|
21
|
+
client.send_message("hello",fan.fakeId)
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
获取指定用户的对话信息:
|
|
26
|
+
```ruby
|
|
27
|
+
fakeId = '1234'
|
|
28
|
+
msgs = client.get_messages(fakeId)
|
|
29
|
+
msgs.each {|m| p "#{m.dateTime} << #{m.content}"}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
图片,音频:
|
|
33
|
+
```ruby
|
|
34
|
+
fileId = client.avatar_upload('pix.jpg')
|
|
35
|
+
client.send_message(fileId,fan.fakeId)
|
|
36
|
+
```
|
|
19
37
|
## Usage
|
|
20
38
|
|
|
21
|
-
TODO: Write usage instructions here
|
|
22
|
-
|
|
23
|
-
## Contributing
|
|
24
39
|
|
|
25
|
-
1
|
|
26
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
27
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
|
29
|
-
5. Create new Pull Request
|
|
40
|
+
微信的消息类型分为文本,图片,音频,视频,AppMsg,对应接口中的类型为1,2,3,4,10。AppMsg类型的消息是富文本,包含图片信息,一般通过管理台事先编辑好,发送时需要调用send_post函数。其它类型的消息调用send_message即可。图片,音频,视频消息发送前需要先通过avatar_upload上传,取得返回的fileId后,使用fileId作为send_message的参数。
|
data/Rakefile
CHANGED
data/lib/weixin_public.rb
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
require "weixin_public/version"
|
|
2
|
-
|
|
3
|
-
|
|
4
2
|
require 'digest'
|
|
5
|
-
require 'faraday'
|
|
6
3
|
require 'json'
|
|
4
|
+
require 'openssl'
|
|
7
5
|
require 'net/http'
|
|
8
6
|
require 'nokogiri'
|
|
9
|
-
require '
|
|
10
|
-
|
|
11
|
-
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
|
7
|
+
require 'faraday'
|
|
12
8
|
|
|
13
9
|
module WeixinPublic
|
|
14
10
|
|
|
15
11
|
class WeixinObject
|
|
16
12
|
def initialize(params)
|
|
17
|
-
|
|
13
|
+
params.each { |var,val| self.send "#{var}=", val if self.class.instance_methods.include?(var.to_sym)}
|
|
18
14
|
end
|
|
19
15
|
end
|
|
20
16
|
|
|
@@ -55,8 +51,10 @@ class WeixinPubClient
|
|
|
55
51
|
|
|
56
52
|
|
|
57
53
|
def login(username,pwd)
|
|
54
|
+
puts "login with#{username}-#{pwd}"
|
|
58
55
|
pwd = Digest::MD5.hexdigest(pwd)
|
|
59
|
-
|
|
56
|
+
|
|
57
|
+
@cookie = @cert?"cert=#{@cert}":""
|
|
60
58
|
params = {"username"=>username,"pwd"=>pwd,"imgcode"=>'',"f"=>'json'}
|
|
61
59
|
ret = request(:post,'/cgi-bin/login?lang=zh_CN',params,nil)
|
|
62
60
|
return 'login failed' if !ret.headers["set-cookie"]
|
|
@@ -81,17 +79,6 @@ class WeixinPubClient
|
|
|
81
79
|
end
|
|
82
80
|
ret
|
|
83
81
|
end
|
|
84
|
-
|
|
85
|
-
def get_posts
|
|
86
|
-
return if !@cookie && login(@username,@password) =~ /failed/
|
|
87
|
-
ret = request(:get,"/cgi-bin/operate_appmsg?sub=list&t=wxm-appmsgs-list-new&type=10&pageIdx=0&pagesize=10&subtype=3&f=json",{},nil)
|
|
88
|
-
doc = Nokogiri::HTML(ret.body)
|
|
89
|
-
posts = doc.css('#json-msglist').to_s
|
|
90
|
-
posts = JSON.parse(posts[posts.index(/{/)..posts.rindex(/}/)])["list"]
|
|
91
|
-
ret = []
|
|
92
|
-
posts.each {|po| ret << AppMsg.new(po)}
|
|
93
|
-
ret
|
|
94
|
-
end
|
|
95
82
|
|
|
96
83
|
def get_messages(fakeId,download=false)
|
|
97
84
|
return if !@cookie && login(@username,@password) =~ /failed/
|
|
@@ -104,8 +91,8 @@ class WeixinPubClient
|
|
|
104
91
|
messages.each do |m|
|
|
105
92
|
next if m["type"]=="10" || m["fakeId"]!=fakeId
|
|
106
93
|
if m["type"]!="10" then
|
|
107
|
-
|
|
108
|
-
|
|
94
|
+
ret << WeixinMessage.new(m)
|
|
95
|
+
ret[-1].dateTime = Time.at(m["dateTime"].to_i)
|
|
109
96
|
end
|
|
110
97
|
if download then
|
|
111
98
|
download_file(ret[-1])
|
|
@@ -114,6 +101,33 @@ class WeixinPubClient
|
|
|
114
101
|
ret
|
|
115
102
|
end
|
|
116
103
|
|
|
104
|
+
def get_messages_number_new(lastmsgid)
|
|
105
|
+
return if !@cookie && login(@username,@password) =~ /failed/
|
|
106
|
+
res = request(:post,"/cgi-bin/getnewmsgnum?t=ajax-getmsgnum&lastmsgid=#{lastmsgid}")
|
|
107
|
+
ret = JSON.parse(res.body)["newTotalMsgCount"]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def get_messages_today(lastmsgid=0,step=50)
|
|
111
|
+
return if !@cookie && login(@username,@password) =~ /failed/
|
|
112
|
+
offset = 0
|
|
113
|
+
ret = []
|
|
114
|
+
loop do
|
|
115
|
+
params = {"t"=>"ajax-message","lang"=>"zh_CN","count"=>'50',"timeline"=>'1','day'=>'0','cgi'=>'getmessage','offset'=>offset}
|
|
116
|
+
res = request(:post,"/cgi-bin/getmessage",params,nil)
|
|
117
|
+
messages = JSON.parse(res.body)
|
|
118
|
+
n = 0
|
|
119
|
+
messages.each do |m|
|
|
120
|
+
break if m["id"].to_i <= lastmsgid
|
|
121
|
+
ret << WeixinMessage.new(m)
|
|
122
|
+
ret[-1].dateTime = Time.at(m["dateTime"].to_i)
|
|
123
|
+
n = n+1
|
|
124
|
+
end
|
|
125
|
+
break if n < step
|
|
126
|
+
offset = offset + step
|
|
127
|
+
end
|
|
128
|
+
ret
|
|
129
|
+
end
|
|
130
|
+
|
|
117
131
|
def download_file(message)
|
|
118
132
|
url="/cgi-bin/downloadfile?msgid=#{message.id}&source="
|
|
119
133
|
avatar_download(message.filePath,url)
|
|
@@ -129,10 +143,9 @@ class WeixinPubClient
|
|
|
129
143
|
body["fileid"]=content
|
|
130
144
|
end
|
|
131
145
|
ret = request(:post,"/cgi-bin/singlesend?t=ajax-response&lang=zh_CN",body,"https://mp.weixin.qq.com/cgi-bin/singlemsgpage")
|
|
132
|
-
puts ret.body
|
|
133
146
|
end
|
|
134
147
|
|
|
135
|
-
def
|
|
148
|
+
def send_appmsg(appmsgid,reciever)
|
|
136
149
|
return if !@cookie && login(@username,@password) =~ /failed/
|
|
137
150
|
body = {"error"=>false,"ajax"=>1,"f"=>"json","tofakeid"=>reciever,"fid"=>appmsgid,"appmsgid"=>appmsgid,"type"=>10}
|
|
138
151
|
ret = request(:post,"/cgi-bin/singlesend?t=ajax-response&lang=zh_CN",body,"https://mp.weixin.qq.com/cgi-bin/singlemsgpage")
|
|
@@ -140,7 +153,7 @@ class WeixinPubClient
|
|
|
140
153
|
|
|
141
154
|
|
|
142
155
|
def avatar_upload(avatar,type="image/png")
|
|
143
|
-
return if !@cookie && login(@username,@password) =~ /failed/
|
|
156
|
+
return nil if !@cookie && login(@username,@password) =~ /failed/
|
|
144
157
|
payload = { :uploadFile => Faraday::UploadIO.new(avatar, type)}
|
|
145
158
|
@conn_multipart.headers["Cookie"] = @cookie
|
|
146
159
|
@conn_multipart.headers["Referer"]="http://mp.weixin.qq.com/cgi-bin/indexpage"
|
|
@@ -148,13 +161,55 @@ class WeixinPubClient
|
|
|
148
161
|
return ret.body.to_s[/\'.*?\'/m][1..-2] if ret.body =~ /suc/m
|
|
149
162
|
return nil
|
|
150
163
|
end
|
|
151
|
-
|
|
164
|
+
|
|
165
|
+
def create_appmsg(title,avatar,content,desc="")
|
|
166
|
+
return nil if !@cookie && login(@username,@password) =~ /failed/
|
|
167
|
+
if avatar =~ /^http/ then
|
|
168
|
+
end
|
|
169
|
+
fileid = avatar_upload(avatar)
|
|
170
|
+
return nil if !fileid
|
|
171
|
+
params = {:error=>false,:count=>1,:title0=>title,:digest0=>desc,:content0=>content,:fileid0=>fileid,:ajax=>1,:sub=>"create"}
|
|
172
|
+
ret = request(:post,"/cgi-bin/operate_appmsg?t=ajax-response&lang=zh_CN",params,"https://mp.weixin.qq.com/cgi-bin/operate_appmsg")
|
|
173
|
+
print ret.body
|
|
174
|
+
lst=get_appmsg_lst
|
|
175
|
+
return lst[0].appId if lst
|
|
176
|
+
return nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def get_appmsg_lst
|
|
180
|
+
return nil if !@cookie && login(@username,@password) =~ /failed/
|
|
181
|
+
ret = request(:get,"/cgi-bin/operate_appmsg?sub=list&t=wxm-appmsgs-list-new&type=10&pageIdx=0&pagesize=10&subtype=3&f=json",{},nil)
|
|
182
|
+
doc = Nokogiri::HTML(ret.body)
|
|
183
|
+
posts = doc.css('#json-msglist').to_s
|
|
184
|
+
posts = JSON.parse(posts[posts.index(/{/)..posts.rindex(/}/)])["list"]
|
|
185
|
+
ret = []
|
|
186
|
+
posts.each {|po| ret << AppMsg.new(po)}
|
|
187
|
+
ret
|
|
188
|
+
end
|
|
189
|
+
|
|
152
190
|
def avatar_download(file,url)
|
|
153
191
|
puts "download-#{url}"
|
|
154
192
|
ret = request(:get,url,{},nil)
|
|
155
193
|
File.open(file, 'wb') { |fp| fp.write(ret.body) }
|
|
156
194
|
end
|
|
157
195
|
|
|
196
|
+
#type:1 -edit mode 2 -dev mode 4 -auto-reply
|
|
197
|
+
def operadvancedfunc(type=1,on_off = 0)
|
|
198
|
+
return nil if !@cookie && login(@username,@password) =~ /failed/
|
|
199
|
+
ret = request(:post,"/cgi-bin/operadvancedfunc?op=switch&lang=zh_CN",{:flag=>on_off,:type=>type,:ajax=>1},nil)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def switch_dev_mode
|
|
203
|
+
operadvancedfunc(4,0)
|
|
204
|
+
operadvancedfunc(1,0)
|
|
205
|
+
operadvancedfunc(2,1)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def set_dev_callback(url, token)
|
|
209
|
+
return nil if !@cookie && login(@username,@password) =~ /failed/
|
|
210
|
+
ret = request(:post,"/cgi-bin/callbackprofile?t=ajax-response&lang=zh_CN",{:url=>url,:callback_token=>token,:ajax=>1},nil)
|
|
211
|
+
end
|
|
212
|
+
|
|
158
213
|
def request(method,url,params,referer)
|
|
159
214
|
@conn.headers["Cookie"] = @cookie
|
|
160
215
|
@conn.headers["Referer"] = referer if referer
|
data/test/avatar.jpg
ADDED
|
Binary file
|
data/test/test_helper.rb
ADDED
data/test/weixin_test.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'weixin_public'
|
|
3
|
+
#require File.expand_path('../../lib/weixin_public.rb', __FILE__)
|
|
4
|
+
require 'openssl'
|
|
5
|
+
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
|
6
|
+
class WeixinPublicTest < Test::Unit::TestCase
|
|
7
|
+
def setup
|
|
8
|
+
@client = WeixinPublic::WeixinPubClient.new('xyz@gmail.com','abc')
|
|
9
|
+
@fakeId = "1234567" #=>user who you want to send a message
|
|
10
|
+
@pic_file = "avatar.jpg"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ntest_fans
|
|
14
|
+
@client.get_fans.each {|f| p "#{f.fakeId}-#{f.nickName}"}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ntest_create_appmsg
|
|
18
|
+
@client.create_appmsg(Time.new.to_s,'/home/liteng/teng.png','conetnt')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ntest_app_lst
|
|
22
|
+
po = @client.get_appmsg_lst.each{|m| print "#{m.appId}-#{m.time}\n"}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ntest_send
|
|
26
|
+
puts @client.send_message("hello",@fakeId)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ntest_send
|
|
30
|
+
puts @client.send_appmsg("hello",@fakeId)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def ntest_read
|
|
34
|
+
@client.get_messages(@fakeId).each {|m| p "#{m.dateTime} << #{m.content}"}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ntest_upload
|
|
38
|
+
puts @client.avatar_upload(@pic_file)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_set_callback
|
|
42
|
+
@client.operadvancedfunc(2,1)
|
|
43
|
+
@client.set_dev_callback("http://wxpt2.cfapps.io/","abc")
|
|
44
|
+
end
|
|
45
|
+
end
|
data/weixin_public.gemspec
CHANGED
metadata
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: weixin_public
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease:
|
|
5
|
-
version: 0.0.
|
|
5
|
+
version: 0.0.2
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- goxplanet
|
|
@@ -10,7 +10,7 @@ autorequire:
|
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
12
|
|
|
13
|
-
date: 2013-
|
|
13
|
+
date: 2013-07-08 00:00:00 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: bundler
|
|
@@ -34,6 +34,28 @@ dependencies:
|
|
|
34
34
|
version: "0"
|
|
35
35
|
type: :development
|
|
36
36
|
version_requirements: *id002
|
|
37
|
+
- !ruby/object:Gem::Dependency
|
|
38
|
+
name: nokogiri
|
|
39
|
+
prerelease: false
|
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: "0"
|
|
46
|
+
type: :runtime
|
|
47
|
+
version_requirements: *id003
|
|
48
|
+
- !ruby/object:Gem::Dependency
|
|
49
|
+
name: faraday
|
|
50
|
+
prerelease: false
|
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
52
|
+
none: false
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: "0"
|
|
57
|
+
type: :runtime
|
|
58
|
+
version_requirements: *id004
|
|
37
59
|
description: "weixin public client "
|
|
38
60
|
email: otec.teng@gmail.com
|
|
39
61
|
executables: []
|
|
@@ -43,13 +65,15 @@ extensions: []
|
|
|
43
65
|
extra_rdoc_files: []
|
|
44
66
|
|
|
45
67
|
files:
|
|
46
|
-
- .gitignore
|
|
47
68
|
- Gemfile
|
|
48
69
|
- LICENSE.txt
|
|
49
70
|
- README.md
|
|
50
71
|
- Rakefile
|
|
51
72
|
- lib/weixin_public.rb
|
|
52
73
|
- lib/weixin_public/version.rb
|
|
74
|
+
- test/avatar.jpg
|
|
75
|
+
- test/test_helper.rb
|
|
76
|
+
- test/weixin_test.rb
|
|
53
77
|
- weixin_public.gemspec
|
|
54
78
|
homepage: ""
|
|
55
79
|
licenses:
|
|
@@ -78,5 +102,7 @@ rubygems_version: 1.8.10
|
|
|
78
102
|
signing_key:
|
|
79
103
|
specification_version: 3
|
|
80
104
|
summary: weixin public client,working with web page interface ,using HTTPS
|
|
81
|
-
test_files:
|
|
82
|
-
|
|
105
|
+
test_files:
|
|
106
|
+
- test/avatar.jpg
|
|
107
|
+
- test/test_helper.rb
|
|
108
|
+
- test/weixin_test.rb
|