├── .idea
├── .name
├── encodings.xml
├── vcs.xml
├── modules.xml
├── wechat2instapaper.iml
├── misc.xml
└── workspace.xml
├── __init__.py
├── CHANGES.md
├── README.md
├── wechat2instapaper.py
├── instapaper.py
└── weixin.py
/.idea/.name:
--------------------------------------------------------------------------------
1 | wechat2instapaper
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/wechat2instapaper.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | ## Wechat2instapaper
2 |
3 | ## Version 0.2
4 |
5 | ## Update:
6 | * 1.Change the frame into [WeixinBot][1].
7 | * 2.Add a new command “#insta” to push all your link to your instapaper.
8 | * 3.Add a new command “#list” whose function is able to show all your list.
9 | * 4.Add a new command “#del”+number whose function is able to delect the item of your list.
10 | * 5.Add a new command “#num” whose function is able to show the number of your list.
11 |
12 |
13 | [1]: https://github.com/Urinx/WeixinBot
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Wechat2instapaper
2 |
3 | ## Version 0.2
4 | ## Update:
5 | * 1.Change the frame into [WeixinBot][1].
6 | * 2.Add a new command “#insta” to push all your links to your instapaper.
7 | * 3.Add a new command “#list” whose function is able to show all your items.
8 | * 4.Add a new command “#del”+number whose function is able to delect the item of your list.
9 | * 5.Add a new command “#num” whose function is able to show the number of your list.
10 |
11 |
12 | ## 1.Based on
13 |
14 | [WeixinBot][2]
15 |
16 | [instapaper ][3]
17 |
18 | ## 2.Environment
19 |
20 | Python 2.7
21 |
22 |
23 |
24 | ## 3.Install
25 |
26 | ```
27 | $ git clone git://github.com/chanjh/wechat2instapaper
28 | $ cd wechat2instapaper
29 | ```
30 |
31 | ## 4.Code & conf
32 |
33 | You should change
34 | ```
35 | ipaper = instapaper.Instapaper('Your Consumer Key', 'Your Secret')
36 | ipaper.login('Username', 'Password')
37 | ```
38 | in wechat2instapaper.py into your own Instapaper data.
39 | You can get consumer key in: [Register New OAuth Application][4]
40 |
41 | ## 5.Run
42 |
43 | `$ python wechat2instapaper.py`
44 |
45 | Use WeChat to scan the QR code and confirm to login.
46 |
47 | ## 6.Share
48 |
49 | Use another WeChat account to send a link to the logined account.And then when you send "#insta" to it,it would save all your links to Instapaper.
50 |
51 | ## 7.More
52 |
53 | Learn more about me and my project on my blog: [ChanTalk][5]
54 |
55 |
56 | [1]: https://github.com/Urinx/WeixinBot
57 | [2]: https://github.com/Urinx/WeixinBot
58 | [3]: https://github.com/rsgalloway/instapaper
59 | [4]: https://www.instapaper.com/main/request_oauth_consumer_token
60 | [5]: http://chanjh.com/
--------------------------------------------------------------------------------
/wechat2instapaper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | # from wxbot import *
5 | from weixin import *
6 | import instapaper
7 | import types
8 |
9 | __author__= "Chanjh "
10 |
11 | __dic__="""
12 | This is a python wrapper for adding new url to the Instapaper.
13 |
14 | http://github.com/chanjh
15 | """
16 |
17 | class MyWXBot(WebWeixin):
18 |
19 | def messageHandle(self, msgBox, content, name):
20 | if content == "#insta":
21 | self.sendAll2insta(msgBox, name)
22 | self.sendMsg(name, "Success!")
23 | elif content == "#list":
24 | self.showAllTheContent(msgBox, name)
25 | elif content[0:4] == "#del":
26 | try:
27 | word = msgBox[ int(content[4:]) ]
28 | del msgBox[ int(content[4:]) ]
29 | self.sendMsg(name, content[4:] + ".已删除")
30 | except:
31 | self.sendMsg(name, "You cannot delect songthing out of range!")
32 | elif content == "#num":
33 | self.sendMsg(name, "一共保存【" + str(len(msgBox)-1) + "】条目")
34 | else:
35 | self.storeTheTextInBox(content, msgBox)
36 | return msgBox
37 |
38 | def showAllTheContent(self, msgBox, name):
39 | for i in range(1,len(msgBox)):
40 | if type(msgBox[i]) is types.StringType or types.DictType:
41 | if type(msgBox[i]) is types.StringType:
42 | word = str(i) + "." + msgBox[i]
43 | else:
44 | word = str(i) + "." + "【标题】:\n" + msgBox[i]['fileName'] + "\n【链接】:\n" + msgBox[i]['url']
45 | self.sendMsg(name, word)
46 | else:
47 | pass
48 |
49 |
50 |
51 | def storeTheTextInBox(self, content, msgBox):
52 | msgBox.append(content)
53 | return msgBox
54 |
55 | def storeTheSharingInBox(self, fileName, url, msgBox):
56 | urlDetail = {'fileName':fileName, 'url':url}
57 | msgBox.append(urlDetail)
58 | return msgBox
59 |
60 |
61 | def sendAll2insta(self, msgBox, name):
62 |
63 | dics = []
64 | i = 0
65 |
66 | while True:
67 | if i > len(msgBox)-1:
68 | break
69 | elif type(msgBox[i]) is types.DictType:
70 | dics.append(msgBox[i])
71 | del msgBox[i]
72 | else:
73 | i+=1
74 |
75 | for i in range(0, len(dics)):
76 | ipaper = instapaper.Instapaper('Your Consumer Key', 'Your Secret')
77 | try:
78 | ipaper.login('Username', 'Password')
79 | result = ipaper.add(dics[i]['url'])
80 | if result == 0:
81 | word = "《" + dics[i]['fileName'] + "》\n【保存失败】"
82 | elif result == 1:
83 | word = "《" + dics[i]['fileName'] + "》\n【保存成功】"
84 | except:
85 | word = u"保存失败,账号密码错误或 API 出错,请检查"
86 |
87 | self.sendMsg(name, word)
88 | print word,msgBox
89 |
90 | def main():
91 | webwx = MyWXBot()
92 |
93 | logger = logging.getLogger(__name__)
94 | import coloredlogs
95 | coloredlogs.install(level='DEBUG')
96 |
97 |
98 | webwx.start()
99 |
100 |
101 | if sys.stdout.encoding == 'cp936':
102 | sys.stdout = UnicodeStreamFilter(sys.stdout)
103 |
104 |
105 | if __name__ == '__main__':
106 | main()
107 |
--------------------------------------------------------------------------------
/instapaper.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import urllib2
4 | import urlparse
5 | import simplejson as json
6 | import oauth2 as oauth
7 | from lxml import etree
8 | from urllib import urlencode
9 |
10 | from HTMLParser import HTMLParser
11 | from re import sub
12 | from sys import stderr
13 | from traceback import print_exc
14 |
15 | __author__= "Chanjh "
16 |
17 | __changeFrom__ = "https://github.com/nickbarnwell/Instapaper-py"
18 |
19 | __doc__ = """
20 | A Python wrapper for adding new url to the Instapaper.
21 |
22 | http://www.instapaper.com/api/full
23 | """
24 |
25 |
26 | _BASE_ = "https://www.instapaper.com"
27 | _API_VERSION_ = "api/1"
28 | _ACCESS_TOKEN_ = "oauth/access_token"
29 | _BOOKMARKS_ADD_ = "bookmarks/add"
30 |
31 |
32 | class Bookmark(object):
33 | def __init__(self, parent, params):
34 | self.parent = parent
35 | self.__text = None
36 | self.__html = None
37 | self.__dict__.update(params)
38 |
39 | @property
40 | def html(self):
41 | if self.__html is None:
42 | response, html = self.parent.http.request(
43 | "/".join([_BASE_, _API_VERSION_, _BOOKMARKS_TEXT_]),
44 | method='POST',
45 | body=urlencode({
46 | 'bookmark_id': self.bookmark_id,
47 | }))
48 | if response.get("status") == "200":
49 | self.__html = html
50 | return self.__html
51 |
52 | @property
53 | def text(self):
54 | if self.__text is None:
55 | self.__text = dehtml(self.html)
56 | return self.__text
57 |
58 | def star(self):
59 | raise NotImplementedError
60 |
61 | def delete(self):
62 | raise NotImplementedError
63 |
64 | def save(self):
65 | raise NotImplementedError
66 |
67 |
68 | class Instapaper(object):
69 | def __init__(self, oauthkey, oauthsec):
70 | self.consumer = oauth.Consumer(oauthkey, oauthsec)
71 | self.client = oauth.Client(self.consumer)
72 | self.token = None
73 | self.http = None
74 |
75 | def login(self, username, password):
76 | response, content = self.client.request(
77 | "/".join([_BASE_, _API_VERSION_, _ACCESS_TOKEN_]),
78 | "POST", urlencode({
79 | 'x_auth_mode': 'client_auth',
80 | 'x_auth_username': username,
81 | 'x_auth_password': password}))
82 | _oauth = dict(urlparse.parse_qsl(content))
83 | self.token = oauth.Token(_oauth['oauth_token'],
84 | _oauth['oauth_token_secret'])
85 | self.http = oauth.Client(self.consumer, self.token)
86 |
87 | def add(self, url):
88 | response, data = self.http.request(
89 | "/".join([_BASE_, _API_VERSION_, _BOOKMARKS_ADD_]),
90 | method='POST',
91 | body=urlencode({
92 | 'url':url
93 | }))
94 | marks = []
95 | items = json.loads(data)
96 | for item in items:
97 | if item.get("type") == "error":
98 | raise Exception(item.get("message"))
99 | return 0
100 | elif item.get("type") == "bookmark":
101 | marks.append(Bookmark(self, item))
102 | return 1
103 |
104 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 | true
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 | 1458316081686
136 |
137 | 1458316081686
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
--------------------------------------------------------------------------------
/weixin.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 | import qrcode
4 | import urllib, urllib2
5 | import cookielib
6 | import requests
7 | import xml.dom.minidom
8 | import json
9 | import time, re, sys, os, random
10 | import multiprocessing
11 | import platform
12 | import logging
13 | from collections import defaultdict
14 | from urlparse import urlparse
15 | from lxml import html
16 |
17 | msgBox = []
18 |
19 | def catchKeyboardInterrupt(fn):
20 | def wrapper(*args):
21 | try:
22 | return fn(*args)
23 | except KeyboardInterrupt:
24 | print '\n[*] 强制退出程序'
25 | logging.debug('[*] 强制退出程序')
26 | return wrapper
27 |
28 | def _decode_list(data):
29 | rv = []
30 | for item in data:
31 | if isinstance(item, unicode):
32 | item = item.encode('utf-8')
33 | elif isinstance(item, list):
34 | item = _decode_list(item)
35 | elif isinstance(item, dict):
36 | item = _decode_dict(item)
37 | rv.append(item)
38 | return rv
39 |
40 | def _decode_dict(data):
41 | rv = {}
42 | for key, value in data.iteritems():
43 | if isinstance(key, unicode):
44 | key = key.encode('utf-8')
45 | if isinstance(value, unicode):
46 | value = value.encode('utf-8')
47 | elif isinstance(value, list):
48 | value = _decode_list(value)
49 | elif isinstance(value, dict):
50 | value = _decode_dict(value)
51 | rv[key] = value
52 | return rv
53 |
54 | class WebWeixin(object):
55 | def __str__(self):
56 | description = \
57 | "=========================\n" + \
58 | "[#] Web Weixin\n" + \
59 | "[#] Debug Mode: " + str(self.DEBUG) + "\n" + \
60 | "[#] Uuid: " + self.uuid + "\n" + \
61 | "[#] Uin: " + str(self.uin) + "\n" + \
62 | "[#] Sid: " + self.sid + "\n" + \
63 | "[#] Skey: " + self.skey + "\n" + \
64 | "[#] DeviceId: " + self.deviceId + "\n" + \
65 | "[#] PassTicket: " + self.pass_ticket + "\n" + \
66 | "========================="
67 | return description
68 |
69 | # def instapaper(self, url):
70 | # ipaper = instapaper.Instapaper('4316ef7422ec43b6b9a991247eafc4f1', '79fd8bb7888d43f489279d98ab830db4')
71 | # ipaper.login('705676521@qq.com', 'wode0408.')
72 | # result,marks = ipaper.add(url)
73 |
74 | def __init__(self):
75 | self.DEBUG = False
76 | self.uuid = ''
77 | self.base_uri = ''
78 | self.redirect_uri= ''
79 | self.uin = ''
80 | self.sid = ''
81 | self.skey = ''
82 | self.pass_ticket = ''
83 | self.deviceId = 'e' + repr(random.random())[2:17]
84 | self.BaseRequest = {}
85 | self.synckey = ''
86 | self.SyncKey = []
87 | self.User = []
88 | self.MemberList = []
89 | self.ContactList = [] # 好友
90 | self.GroupList = [] # 群
91 | self.GroupMemeberList = [] # 群友
92 | self.PublicUsersList = [] # 公众号/服务号
93 | self.SpecialUsersList = [] # 特殊账号
94 | self.autoReplyMode = False
95 | self.syncHost = ''
96 | self.user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36'
97 | self.interactive = False
98 | self.autoOpen = False
99 | self.saveFolder = os.path.join(os.getcwd(), 'saved')
100 | self.saveSubFolders = {'webwxgeticon': 'icons', 'webwxgetheadimg': 'headimgs', 'webwxgetmsgimg': 'msgimgs', 'webwxgetvideo': 'videos', 'webwxgetvoice': 'voices', '_showQRCodeImg': 'qrcodes'}
101 | self.appid = 'wx782c26e4c19acffb'
102 | self.lang = 'zh_CN'
103 | self.lastCheckTs = time.time()
104 | self.memberCount = 0
105 | self.SpecialUsers = ['newsapp', 'fmessage', 'filehelper', 'weibo', 'qqmail', 'fmessage', 'tmessage', 'qmessage', 'qqsync', 'floatbottle', 'lbsapp', 'shakeapp', 'medianote', 'qqfriend', 'readerapp', 'blogapp', 'facebookapp', 'masssendapp', 'meishiapp', 'feedsapp', 'voip', 'blogappweixin', 'weixin', 'brandsessionholder', 'weixinreminder', 'wxid_novlwrv3lqwv11', 'gh_22b87fa7cb3c', 'officialaccounts', 'notification_messages', 'wxid_novlwrv3lqwv11', 'gh_22b87fa7cb3c', 'wxitil', 'userexperience_alarm', 'notification_messages']
106 | self.TimeOut = 20 # 同步最短时间间隔(单位:秒)
107 |
108 |
109 | opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
110 | opener.addheaders = [('User-agent', self.user_agent)]
111 | urllib2.install_opener(opener)
112 |
113 | def loadConfig(self, config):
114 | if config['DEBUG']: self.DEBUG = config['DEBUG']
115 | if config['autoReplyMode']: self.autoReplyMode = config['autoReplyMode']
116 | if config['user_agent']: self.user_agent = config['user_agent']
117 | if config['interactive']: self.interactive = config['interactive']
118 | if config['autoOpen']: self.autoOpen = config['autoOpen']
119 |
120 | def getUUID(self):
121 | url = 'https://login.weixin.qq.com/jslogin'
122 | params = {
123 | 'appid': self.appid,
124 | 'fun': 'new',
125 | 'lang': self.lang,
126 | '_': int(time.time()),
127 | }
128 | data = self._post(url, params, False)
129 | regx = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"'
130 | pm = re.search(regx, data)
131 | if pm:
132 | code = pm.group(1)
133 | self.uuid = pm.group(2)
134 | return code == '200'
135 | return False
136 |
137 | def genQRCode(self):
138 | if sys.platform.startswith('win'):
139 | self._showQRCodeImg()
140 | else:
141 | self._str2qr('https://login.weixin.qq.com/l/' + self.uuid)
142 |
143 | def _showQRCodeImg(self):
144 | url = 'https://login.weixin.qq.com/qrcode/' + self.uuid
145 | params = {
146 | 't' : 'webwx',
147 | '_' : int(time.time())
148 | }
149 |
150 | data = self._post(url, params, False)
151 | QRCODE_PATH = self._saveFile('qrcode.jpg', data, '_showQRCodeImg')
152 | os.startfile(QRCODE_PATH)
153 |
154 | def waitForLogin(self, tip = 1):
155 | time.sleep(tip)
156 | url = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s' % (tip, self.uuid, int(time.time()))
157 | data = self._get(url)
158 | pm = re.search(r'window.code=(\d+);', data)
159 | code = pm.group(1)
160 |
161 | if code == '201': return True
162 | elif code == '200':
163 | pm = re.search(r'window.redirect_uri="(\S+?)";', data)
164 | r_uri = pm.group(1) + '&fun=new'
165 | self.redirect_uri = r_uri
166 | self.base_uri = r_uri[:r_uri.rfind('/')]
167 | return True
168 | elif code == '408':
169 | self._echo('[登陆超时] \n')
170 | else:
171 | self._echo('[登陆异常] \n')
172 | return False
173 |
174 | def login(self):
175 | data = self._get(self.redirect_uri)
176 | doc = xml.dom.minidom.parseString(data)
177 | root = doc.documentElement
178 |
179 | for node in root.childNodes:
180 | if node.nodeName == 'skey':
181 | self.skey = node.childNodes[0].data
182 | elif node.nodeName == 'wxsid':
183 | self.sid = node.childNodes[0].data
184 | elif node.nodeName == 'wxuin':
185 | self.uin = node.childNodes[0].data
186 | elif node.nodeName == 'pass_ticket':
187 | self.pass_ticket = node.childNodes[0].data
188 |
189 | if '' in (self.skey, self.sid, self.uin, self.pass_ticket):
190 | return False
191 |
192 | self.BaseRequest = {
193 | 'Uin': int(self.uin),
194 | 'Sid': self.sid,
195 | 'Skey': self.skey,
196 | 'DeviceID': self.deviceId,
197 | }
198 | return True
199 |
200 | def webwxinit(self):
201 | url = self.base_uri + '/webwxinit?pass_ticket=%s&skey=%s&r=%s' % (self.pass_ticket, self.skey, int(time.time()))
202 | params = {
203 | 'BaseRequest': self.BaseRequest
204 | }
205 | dic = self._post(url, params)
206 | self.SyncKey = dic['SyncKey']
207 | self.User = dic['User']
208 | # synckey for synccheck
209 | self.synckey = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List'] ])
210 |
211 | return dic['BaseResponse']['Ret'] == 0
212 |
213 | def webwxstatusnotify(self):
214 | url = self.base_uri + '/webwxstatusnotify?lang=zh_CN&pass_ticket=%s' % (self.pass_ticket)
215 | params = {
216 | 'BaseRequest': self.BaseRequest,
217 | "Code": 3,
218 | "FromUserName": self.User['UserName'],
219 | "ToUserName": self.User['UserName'],
220 | "ClientMsgId": int(time.time())
221 | }
222 | dic = self._post(url, params)
223 |
224 | return dic['BaseResponse']['Ret'] == 0
225 |
226 | def webwxgetcontact(self):
227 | SpecialUsers = self.SpecialUsers
228 | url = self.base_uri + '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' % (self.pass_ticket, self.skey, int(time.time()))
229 | dic = self._post(url, {})
230 |
231 | self.MemberCount = dic['MemberCount']
232 | self.MemberList = dic['MemberList']
233 | ContactList = self.MemberList[:]
234 | GroupList = self.GroupList[:]
235 | PublicUsersList = self.PublicUsersList[:]
236 | SpecialUsersList = self.SpecialUsersList[:]
237 |
238 | for i in xrange(len(ContactList) - 1, -1, -1):
239 | Contact = ContactList[i]
240 | if Contact['VerifyFlag'] & 8 != 0: # 公众号/服务号
241 | ContactList.remove(Contact)
242 | self.PublicUsersList.append(Contact)
243 | elif Contact['UserName'] in SpecialUsers: # 特殊账号
244 | ContactList.remove(Contact)
245 | self.SpecialUsersList.append(Contact)
246 | elif Contact['UserName'].find('@@') != -1: # 群聊
247 | ContactList.remove(Contact)
248 | self.GroupList.append(Contact)
249 | elif Contact['UserName'] == self.User['UserName']: # 自己
250 | ContactList.remove(Contact)
251 | self.ContactList = ContactList
252 |
253 | return True
254 |
255 | def webwxbatchgetcontact(self):
256 | url = self.base_uri + '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
257 | params = {
258 | 'BaseRequest': self.BaseRequest,
259 | "Count": len(self.GroupList),
260 | "List": [ {"UserName": g['UserName'], "EncryChatRoomId":""} for g in self.GroupList ]
261 | }
262 | dic = self._post(url, params)
263 |
264 | # blabla ...
265 | ContactList = dic['ContactList']
266 | ContactCount = dic['Count']
267 | self.GroupList = ContactList
268 |
269 | for i in xrange(len(ContactList) - 1, -1, -1):
270 | Contact = ContactList[i]
271 | MemberList = Contact['MemberList']
272 | for member in MemberList:
273 | self.GroupMemeberList.append(member)
274 | return True
275 |
276 | def getNameById(self, id):
277 | url = self.base_uri + '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
278 | params = {
279 | 'BaseRequest': self.BaseRequest,
280 | "Count": 1,
281 | "List": [ {"UserName": id, "EncryChatRoomId":""} ]
282 | }
283 | dic = self._post(url, params)
284 |
285 | # blabla ...
286 | return dic['ContactList']
287 |
288 | def testsynccheck(self):
289 | SyncHost = [
290 | 'webpush.weixin.qq.com',
291 | 'webpush2.weixin.qq.com',
292 | 'webpush.wechat.com',
293 | 'webpush1.wechat.com',
294 | 'webpush2.wechat.com',
295 | 'webpush1.wechatapp.com',
296 | # 'webpush.wechatapp.com'
297 | ]
298 | for host in SyncHost:
299 | self.syncHost = host
300 | [retcode, selector] = self.synccheck()
301 | if retcode == '0': return True
302 | return False
303 |
304 | def synccheck(self):
305 | params = {
306 | 'r': int(time.time()),
307 | 'sid': self.sid,
308 | 'uin': self.uin,
309 | 'skey': self.skey,
310 | 'deviceid': self.deviceId,
311 | 'synckey': self.synckey,
312 | '_': int(time.time()),
313 | }
314 | url = 'https://' + self.syncHost + '/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params)
315 | data = self._get(url)
316 | pm = re.search(r'window.synccheck={retcode:"(\d+)",selector:"(\d+)"}', data)
317 | retcode = pm.group(1)
318 | selector = pm.group(2)
319 | return [retcode, selector]
320 |
321 | def webwxsync(self):
322 | url = self.base_uri + '/webwxsync?sid=%s&skey=%s&pass_ticket=%s' % (self.sid, self.skey, self.pass_ticket)
323 | params = {
324 | 'BaseRequest': self.BaseRequest,
325 | 'SyncKey': self.SyncKey,
326 | 'rr': ~int(time.time())
327 | }
328 | dic = self._post(url, params)
329 | if self.DEBUG:
330 | print json.dumps(dic, indent=4)
331 | logging.debug(json.dumps(dic, indent=4))
332 |
333 | if dic['BaseResponse']['Ret'] == 0:
334 | self.SyncKey = dic['SyncKey']
335 | self.synckey = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List'] ])
336 | return dic
337 |
338 | def webwxsendmsg(self, word, to = 'filehelper'):
339 | url = self.base_uri + '/webwxsendmsg?pass_ticket=%s' % (self.pass_ticket)
340 | clientMsgId = str(int(time.time()*1000)) + str(random.random())[:5].replace('.','')
341 | params = {
342 | 'BaseRequest': self.BaseRequest,
343 | 'Msg': {
344 | "Type": 1,
345 | "Content": self._transcoding(word),
346 | "FromUserName": self.User['UserName'],
347 | "ToUserName": to,
348 | "LocalID": clientMsgId,
349 | "ClientMsgId": clientMsgId
350 | }
351 | }
352 | headers = {'content-type': 'application/json; charset=UTF-8'}
353 | data = json.dumps(params, ensure_ascii=False).encode('utf8')
354 | r = requests.post(url, data = data, headers = headers)
355 | dic = r.json()
356 | return dic['BaseResponse']['Ret'] == 0
357 |
358 | def _saveFile(self, filename, data, api=None):
359 | fn = filename
360 | if self.saveSubFolders[api]:
361 | dirName = os.path.join(self.saveFolder, self.saveSubFolders[api])
362 | if not os.path.exists(dirName):
363 | os.makedirs(dirName)
364 | fn = os.path.join(dirName, filename)
365 | logging.debug('Saved file: %s' % fn)
366 | with open(fn, 'wb') as f: f.write(data); f.close()
367 | return fn
368 |
369 | def webwxgeticon(self, id):
370 | url = self.base_uri + '/webwxgeticon?username=%s&skey=%s' % (id, self.skey)
371 | data = self._get(url)
372 | fn = 'img_'+id+'.jpg'
373 | return self._saveFile(fn, data, 'webwxgeticon')
374 |
375 | def webwxgetheadimg(self, id):
376 | url = self.base_uri + '/webwxgetheadimg?username=%s&skey=%s' % (id, self.skey)
377 | data = self._get(url)
378 | fn = 'img_'+id+'.jpg'
379 | return self._saveFile(fn, data, 'webwxgetheadimg')
380 |
381 | def webwxgetmsgimg(self, msgid):
382 | url = self.base_uri + '/webwxgetmsgimg?MsgID=%s&skey=%s' % (msgid, self.skey)
383 | data = self._get(url)
384 | fn = 'img_'+msgid+'.jpg'
385 | return self._saveFile(fn, data, 'webwxgetmsgimg')
386 |
387 | # Not work now for weixin haven't support this API
388 | def webwxgetvideo(self, msgid):
389 | url = self.base_uri + '/webwxgetvideo?msgid=%s&skey=%s' % (msgid, self.skey)
390 | data = self._get(url, api='webwxgetvideo')
391 | fn = 'video_'+msgid+'.mp4'
392 | return self._saveFile(fn, data, 'webwxgetvideo')
393 |
394 | def webwxgetvoice(self, msgid):
395 | url = self.base_uri + '/webwxgetvoice?msgid=%s&skey=%s' % (msgid, self.skey)
396 | data = self._get(url)
397 | fn = 'voice_'+msgid+'.mp3'
398 | return self._saveFile(fn, data, 'webwxgetvoice')
399 |
400 | def getGroupName(self, id):
401 | name = '未知群'
402 | for member in self.GroupList:
403 | if member['UserName'] == id:
404 | name = member['NickName']
405 | if name == '未知群':
406 | # 现有群里面查不到
407 | GroupList = self.getNameById(id)
408 | for group in GroupList:
409 | self.GroupList.append(group)
410 | if group['UserName'] == id:
411 | name = group['NickName']
412 | MemberList = group['MemberList']
413 | for member in MemberList:
414 | self.GroupMemeberList.append(member)
415 | return name
416 |
417 | def getUserRemarkName(self, id):
418 | name = '未知群' if id[:2] == '@@' else '陌生人'
419 | if id == self.User['UserName']: return self.User['NickName'] # 自己
420 |
421 | if id[:2] == '@@':
422 | # 群
423 | name = self.getGroupName(id)
424 | else:
425 | # 特殊账号
426 | for member in self.SpecialUsersList:
427 | if member['UserName'] == id:
428 | name = member['RemarkName'] if member['RemarkName'] else member['NickName']
429 |
430 | # 公众号或服务号
431 | for member in self.PublicUsersList:
432 | if member['UserName'] == id:
433 | name = member['RemarkName'] if member['RemarkName'] else member['NickName']
434 |
435 | # 直接联系人
436 | for member in self.ContactList:
437 | if member['UserName'] == id:
438 | name = member['RemarkName'] if member['RemarkName'] else member['NickName']
439 | # 群友
440 | for member in self.GroupMemeberList:
441 | if member['UserName'] == id:
442 | name = member['DisplayName'] if member['DisplayName'] else member['NickName']
443 |
444 | if name == '未知群' or name == '陌生人': logging.debug(id)
445 | return name
446 |
447 | def getUSerID(self, name):
448 | for member in self.MemberList:
449 | if name == member['RemarkName'] or name == member['NickName']:
450 | return member['UserName']
451 | return None
452 |
453 | def _showMsg(self, message):
454 |
455 | srcName = None
456 | dstName = None
457 | groupName = None
458 | content = None
459 |
460 | msg = message
461 | logging.debug(msg)
462 |
463 | if msg['raw_msg']:
464 | srcName = self.getUserRemarkName(msg['raw_msg']['FromUserName'])
465 | dstName = self.getUserRemarkName(msg['raw_msg']['ToUserName'])
466 | content = msg['raw_msg']['Content'].replace('<','<').replace('>','>')
467 | message_id = msg['raw_msg']['MsgId']
468 |
469 | if content.find('http://weixin.qq.com/cgi-bin/redirectforward?args=') != -1:
470 | # 地理位置消息
471 | data = self._get(content).decode('gbk').encode('utf-8')
472 | pos = self._searchContent('title', data, 'xml')
473 | tree = html.fromstring(self._get(content))
474 | url = tree.xpath('//html/body/div/img')[0].attrib['src']
475 |
476 | for item in urlparse(url).query.split('&'):
477 | if item.split('=')[0] == 'center': loc = item.split('=')[-1:]
478 |
479 | content = '%s 发送了一个 位置消息 - 我在 [%s](%s) @ %s]' % (srcName, pos, url, loc)
480 |
481 | if msg['raw_msg']['ToUserName'] == 'filehelper':
482 | # 文件传输助手
483 | dstName = '文件传输助手'
484 |
485 | if msg['raw_msg']['FromUserName'][:2] == '@@':
486 | # 接收到来自群的消息
487 | if re.search(":
", content, re.IGNORECASE):
488 | [people, content] = content.split(':
')
489 | groupName = srcName
490 | srcName = self.getUserRemarkName(people)
491 | dstName = 'GROUP'
492 | else:
493 | groupName = srcName
494 | srcName = 'SYSTEM'
495 | elif msg['raw_msg']['ToUserName'][:2] == '@@':
496 | # 自己发给群的消息
497 | groupName = dstName
498 | dstName = 'GROUP'
499 |
500 | # 收到了红包
501 | if content == '收到红包,请在手机上查看': msg['message'] = content
502 |
503 | # 指定了消息内容
504 | if 'message' in msg.keys(): content = msg['message']
505 |
506 |
507 | if groupName != None:
508 | print '%s |%s| %s -> %s: %s' % (message_id, groupName.strip(), srcName.strip(), dstName.strip(), content.replace('
','\n'))
509 | logging.info('%s |%s| %s -> %s: %s' % (message_id, groupName.strip(), srcName.strip(), dstName.strip(), content.replace('
','\n')))
510 | else:
511 | print '%s %s -> %s: %s' % (message_id, srcName.strip(), dstName.strip(), content.replace('
','\n'))
512 | logging.info('%s %s -> %s: %s' % (message_id, srcName.strip(), dstName.strip(), content.replace('
','\n')))
513 |
514 | def handleMsg(self, r):
515 | for msg in r['AddMsgList']:
516 | print '[*] 你有新的消息,请注意查收'
517 | logging.debug('[*] 你有新的消息,请注意查收')
518 |
519 | if self.DEBUG:
520 | fn = 'msg' + str(int(random.random() * 1000)) + '.json'
521 | with open(fn, 'w') as f: f.write(json.dumps(msg))
522 | print '[*] 该消息已储存到文件: ' + fn
523 | logging.debug('[*] 该消息已储存到文件: %s' % (fn))
524 |
525 | msgType = msg['MsgType']
526 | name = self.getUserRemarkName(msg['FromUserName'])
527 | content = msg['Content'].replace('<','<').replace('>','>')
528 | msgid = msg['MsgId']
529 |
530 | if msgType == 1:
531 | raw_msg = { 'raw_msg': msg }
532 |
533 | self.messageHandle(msgBox, content, name)
534 |
535 | self._showMsg(raw_msg)
536 | if self.autoReplyMode:
537 | ans = self._xiaodoubi(content)+'\n[微信机器人自动回复]'
538 | if self.webwxsendmsg(ans, msg['FromUserName']):
539 | print '自动回复: '+ans
540 | logging.info('自动回复: '+ans)
541 | else:
542 | print '自动回复失败'
543 | logging.info('自动回复失败')
544 | elif msgType == 3:
545 | image = self.webwxgetmsgimg(msgid)
546 | raw_msg = { 'raw_msg': msg, 'message': '%s 发送了一张图片: %s' % (name, image) }
547 | self._showMsg(raw_msg)
548 | self._safe_open(image)
549 | elif msgType == 34:
550 | voice = self.webwxgetvoice(msgid)
551 | raw_msg = { 'raw_msg': msg, 'message': '%s 发了一段语音: %s' % (name, voice) }
552 | self._showMsg(raw_msg)
553 | self._safe_open(voice)
554 | elif msgType == 42:
555 | info = msg['RecommendInfo']
556 | print '%s 发送了一张名片:' % name
557 | print '========================='
558 | print '= 昵称: %s' % info['NickName']
559 | print '= 微信号: %s' % info['Alias']
560 | print '= 地区: %s %s' % (info['Province'], info['City'])
561 | print '= 性别: %s' % ['未知', '男', '女'][info['Sex']]
562 | print '========================='
563 | raw_msg = { 'raw_msg': msg, 'message': '%s 发送了一张名片: %s' % (name.strip(), json.dumps(info)) }
564 | self._showMsg(raw_msg)
565 | elif msgType == 47:
566 | url = self._searchContent('cdnurl', content)
567 | raw_msg = { 'raw_msg': msg, 'message': '%s 发了一个动画表情,点击下面链接查看: %s' % (name, url) }
568 | self._showMsg(raw_msg)
569 | self._safe_open(url)
570 | elif msgType == 49:
571 | appMsgType = defaultdict(lambda : "")
572 | appMsgType.update({5:'链接', 3:'音乐', 7:'微博'})
573 | # if appMsgType[msg['AppMsgType']] == 5:
574 | self.storeTheSharingInBox(msg['FileName'], msg['Url'], msgBox)
575 |
576 | # else:
577 | # pass
578 | print '%s 分享了一个%s:' % (name, appMsgType[msg['AppMsgType']])
579 | print '========================='
580 | print '= 标题: %s' % msg['FileName']
581 | print '= 描述: %s' % self._searchContent('des', content, 'xml')
582 | print '= 链接: %s' % msg['Url']
583 | print '= 来自: %s' % self._searchContent('appname', content, 'xml')
584 | print '========================='
585 | card = {
586 | 'title': msg['FileName'],
587 | 'description': self._searchContent('des', content, 'xml'),
588 | 'url': msg['Url'],
589 | 'appname': self._searchContent('appname', content, 'xml')
590 | }
591 | raw_msg = { 'raw_msg': msg, 'message': '%s 分享了一个%s: %s' % (name, appMsgType[msg['AppMsgType']], json.dumps(card)) }
592 | self._showMsg(raw_msg)
593 | elif msgType == 51:
594 | raw_msg = { 'raw_msg': msg, 'message': '[*] 成功获取联系人信息' }
595 | self._showMsg(raw_msg)
596 | elif msgType == 62:
597 | video = self.webwxgetvideo(msgid)
598 | raw_msg = { 'raw_msg': msg, 'message': '%s 发了一段小视频: %s' % (name, video) }
599 | self._showMsg(raw_msg)
600 | self._safe_open(video)
601 | elif msgType == 10002:
602 | raw_msg = { 'raw_msg': msg, 'message': '%s 撤回了一条消息' % name }
603 | self._showMsg(raw_msg)
604 | else:
605 | logging.debug('[*] 该消息类型为: %d,可能是表情,图片, 链接或红包: %s' % (msg['MsgType'], json.dumps(msg)))
606 | raw_msg = { 'raw_msg': msg, 'message': '[*] 该消息类型为: %d,可能是表情,图片, 链接或红包' % msg['MsgType'] }
607 | self._showMsg(raw_msg)
608 |
609 | def listenMsgMode(self):
610 | print '[*] 进入消息监听模式 ... 成功'
611 | logging.debug('[*] 进入消息监听模式 ... 成功')
612 | self._run('[*] 进行同步线路测试 ... ', self.testsynccheck)
613 | playWeChat = 0
614 | redEnvelope = 0
615 | while True:
616 | self.lastCheckTs = time.time()
617 | [retcode, selector] = self.synccheck()
618 | if self.DEBUG: print 'retcode: %s, selector: %s' % (retcode, selector)
619 | logging.debug('retcode: %s, selector: %s' % (retcode, selector))
620 | if retcode == '1100':
621 | print '[*] 你在手机上登出了微信,债见'
622 | logging.debug('[*] 你在手机上登出了微信,债见')
623 | break
624 | if retcode == '1101':
625 | print '[*] 你在其他地方登录了 WEB 版微信,债见'
626 | logging.debug('[*] 你在其他地方登录了 WEB 版微信,债见')
627 | break
628 | elif retcode == '0':
629 | if selector == '2':
630 | r = self.webwxsync()
631 | if r is not None: self.handleMsg(r)
632 | elif selector == '6':
633 | # TODO
634 | redEnvelope += 1
635 | print '[*] 收到疑似红包消息 %d 次' % redEnvelope
636 | logging.debug('[*] 收到疑似红包消息 %d 次' % redEnvelope)
637 | elif selector == '7':
638 | playWeChat += 1
639 | print '[*] 你在手机上玩微信被我发现了 %d 次' % playWeChat
640 | logging.debug('[*] 你在手机上玩微信被我发现了 %d 次' % playWeChat)
641 | r = self.webwxsync()
642 | elif selector == '0':
643 | time.sleep(1)
644 | if (time.time() - self.lastCheckTs) <= 20: time.sleep(time.time() - self.lastCheckTs)
645 |
646 | def sendMsg(self, name, word, isfile = False):
647 | id = self.getUSerID(name)
648 | if id:
649 | if isfile:
650 | with open(word, 'r') as f:
651 | for line in f.readlines():
652 | line = line.replace('\n','')
653 | self._echo('-> '+name+': '+line)
654 | if self.webwxsendmsg(line, id):
655 | print ' [成功]'
656 | else:
657 | print ' [失败]'
658 | time.sleep(1)
659 | else:
660 | if self.webwxsendmsg(word, id):
661 | print '[*] 消息发送成功'
662 | logging.debug('[*] 消息发送成功')
663 | else:
664 | print '[*] 消息发送失败'
665 | logging.debug('[*] 消息发送失败')
666 | else:
667 | print '[*] 此用户不存在'
668 | logging.debug('[*] 此用户不存在')
669 |
670 | def sendMsgToAll(self, word):
671 | for contact in self.ContactList:
672 | name = contact['RemarkName'] if contact['RemarkName'] else contact['NickName']
673 | id = contact['UserName']
674 | self._echo('-> '+name+': '+word)
675 | if self.webwxsendmsg(word, id):
676 | print ' [成功]'
677 | else:
678 | print ' [失败]'
679 | time.sleep(1)
680 |
681 | @catchKeyboardInterrupt
682 | def start(self):
683 | self._echo('[*] 微信网页版 ... 开动'); print; logging.debug('[*] 微信网页版 ... 开动')
684 | while True:
685 | self._run('[*] 正在获取 uuid ... ', self.getUUID)
686 | self._echo('[*] 正在获取二维码 ... 成功'); print; logging.debug('[*] 微信网页版 ... 开动'); self.genQRCode()
687 | print '[*] 请使用微信扫描二维码以登录 ... '
688 | if not self.waitForLogin():
689 | continue
690 | print '[*] 请在手机上点击确认以登录 ... '
691 | if not self.waitForLogin(0):
692 | continue
693 | break
694 |
695 | self._run('[*] 正在登录 ... ', self.login)
696 | self._run('[*] 微信初始化 ... ', self.webwxinit)
697 | self._run('[*] 开启状态通知 ... ', self.webwxstatusnotify)
698 | self._run('[*] 获取联系人 ... ', self.webwxgetcontact)
699 | self._echo('[*] 应有 %s 个联系人,读取到联系人 %d 个' % (self.MemberCount, len(self.MemberList))); print
700 | self._echo('[*] 共有 %d 个群 | %d 个直接联系人 | %d 个特殊账号 | %d 公众号或服务号' % (len(self.GroupList), len(self.ContactList), len(self.SpecialUsersList), len(self.PublicUsersList) )); print
701 | self._run('[*] 获取群 ... ', self.webwxbatchgetcontact)
702 | logging.debug('[*] 微信网页版 ... 开动')
703 | if self.DEBUG: print self
704 | logging.debug(self)
705 |
706 | if self.interactive and raw_input('[*] 是否开启自动回复模式(y/n): ') == 'y':
707 | self.autoReplyMode = True
708 | print '[*] 自动回复模式 ... 开启'
709 | logging.debug('[*] 自动回复模式 ... 开启')
710 | else:
711 | print '[*] 自动回复模式 ... 关闭'
712 | logging.debug('[*] 自动回复模式 ... 关闭')
713 |
714 | listenProcess = multiprocessing.Process(target=self.listenMsgMode)
715 | listenProcess.start()
716 |
717 | while True:
718 | text = raw_input('')
719 | if text == 'quit':
720 | listenProcess.terminate()
721 | print('[*] 退出微信')
722 | logging.debug('[*] 退出微信')
723 | exit()
724 | elif text[:2] == '->':
725 | [name, word] = text[2:].split(':')
726 | if name == 'all': self.sendMsgToAll(word)
727 | else: self.sendMsg(name, word)
728 | elif text[:3] == 'm->':
729 | [name, file] = text[3:].split(':')
730 | self.sendMsg(name, file, True)
731 | elif text[:3] == 'f->':
732 | print '发送文件'
733 | logging.debug('发送文件')
734 | elif text[:3] == 'i->':
735 | print '发送图片'
736 | logging.debug('发送图片')
737 |
738 | def _safe_open(self, path):
739 | if self.autoOpen:
740 | if platform.system() == "Linux":
741 | os.system("xdg-open %s &" % path)
742 | else:
743 | os.system('open %s &' % path)
744 |
745 | def _run(self, str, func, *args):
746 | self._echo(str)
747 | if func(*args): print '成功'; logging.debug('%s... 成功' % (str))
748 | else: print('失败\n[*] 退出程序'); logging.debug('%s... 失败' % (str)); logging.debug('[*] 退出程序'); exit()
749 |
750 | def _echo(self, str):
751 | sys.stdout.write(str)
752 | sys.stdout.flush()
753 |
754 | def _printQR(self, mat):
755 | for i in mat:
756 | BLACK = '\033[40m \033[0m'
757 | WHITE = '\033[47m \033[0m'
758 | print ''.join([BLACK if j else WHITE for j in i])
759 |
760 | def _str2qr(self, str):
761 | qr = qrcode.QRCode()
762 | qr.border = 1
763 | qr.add_data(str)
764 | mat = qr.get_matrix()
765 | self._printQR(mat) # qr.print_tty() or qr.print_ascii()
766 |
767 | def _transcoding(self, data):
768 | if not data: return data
769 | result = None
770 | if type(data) == unicode:
771 | result = data
772 | elif type(data) == str:
773 | result = data.decode('utf-8')
774 | return result
775 |
776 | def _get(self, url, api=None):
777 | request = urllib2.Request(url = url)
778 | request.add_header('Referer', 'https://wx.qq.com/')
779 | if api == 'webwxgetvoice': request.add_header('Range', 'bytes=0-')
780 | if api == 'webwxgetvideo': request.add_header('Range', 'bytes=0-')
781 | response = urllib2.urlopen(request)
782 | data = response.read()
783 | logging.debug(url)
784 | return data
785 |
786 | def _post(self, url, params, jsonfmt = True):
787 | if jsonfmt:
788 | request = urllib2.Request(url = url, data = json.dumps(params))
789 | request.add_header('ContentType', 'application/json; charset=UTF-8')
790 | else:
791 | request = urllib2.Request(url = url, data = urllib.urlencode(params))
792 | response = urllib2.urlopen(request)
793 | data = response.read()
794 | if jsonfmt: return json.loads(data, object_hook=_decode_dict)
795 | return data
796 |
797 | def _xiaodoubi(self, word):
798 | url = 'http://www.xiaodoubi.com/bot/chat.php'
799 | try:
800 | r = requests.post(url, data = {'chat': word})
801 | return r.content
802 | except:
803 | return "让我一个人静静 T_T..."
804 |
805 | def _simsimi(self, word):
806 | key = ''
807 | url = 'http://sandbox.api.simsimi.com/request.p?key=%s&lc=ch&ft=0.0&text=%s' % (key, word)
808 | r = requests.get(url)
809 | ans = r.json()
810 | if ans['result'] == '100': return ans['response']
811 | else: return '你在说什么,风太大听不清列'
812 |
813 | def _searchContent(self, key, content, fmat = 'attr'):
814 | if fmat == 'attr':
815 | pm = re.search(key+'\s?=\s?"([^"<]+)"', content)
816 | if pm: return pm.group(1)
817 | elif fmat == 'xml':
818 | pm = re.search('<{0}>([^<]+){0}>'.format(key),content)
819 | if not pm: pm = re.search('<{0}><\!\[CDATA\[(.*?)\]\]>{0}>'.format(key),content)
820 | if pm: return pm.group(1)
821 | return '未知'
822 |
823 | class UnicodeStreamFilter:
824 | def __init__(self, target):
825 | self.target = target
826 | self.encoding = 'utf-8'
827 | self.errors = 'replace'
828 | self.encode_to = self.target.encoding
829 |
830 | def write(self, s):
831 | if type(s) == str:
832 | s = s.decode('utf-8')
833 | s = s.encode(self.encode_to, self.errors).decode(self.encode_to)
834 | self.target.write(s)
835 |
836 | def flush(self):
837 | self.target.flush()
838 |
839 | # if sys.stdout.encoding == 'cp936':
840 | # sys.stdout = UnicodeStreamFilter(sys.stdout)
841 |
842 |
843 | # if __name__ == '__main__':
844 |
845 | # logger = logging.getLogger(__name__)
846 | # import coloredlogs
847 | # coloredlogs.install(level='DEBUG')
848 |
849 | # webwx = WebWeixin()
850 | # webwx.start()
851 |
--------------------------------------------------------------------------------