1. 新建一个django项目 wechat
2. 在wechat项目下新建一个文件夹 static
3. 在wechat应用下的settings.py文件新增静态文件路径
STATICFILS_DIRS = (
os.path.join(BASE_DIR,\'static\')
)
4. 将jquery拷贝到static文件夹中
5. 新建一个应用 web
6. 在wechat应用下的urls.py文件中配置路由
from django.conf.urls import url
from django.contrib import admin
from web import views
urlpatterns = [
url(r\'^admin/\', admin.site.urls),
url(r\'^login/$\', views.login),
url(r\'^polling/$\', views.long_polling),
url(r\'^index/$\', views.index),
url(r\'^contact_list/$\', views.contact_list),
url(r\'^send_msg/$\', views.send_msg),
url(r\'^get_msg/$\', views.get_msg),
]
7. 在web应用下的views.py文件中书写相关函数
1 import re 2 import time 3 import json 4 import requests 5 from django.shortcuts import render 6 from django.shortcuts import HttpResponse 7 # 当前时间戳 8 CURRENT_TIME = None 9 QCODE = None 10 11 LOGIN_COOKIE_DICT = {} 12 TICKET_COOKIE_DICT = {} 13 TICKET_DICT = {} 14 TIPS = 1 15 16 USER_INIT_DATA = {} 17 BASE_URL = "http://wx.qq.com" 18 BASE_SYNC_URL = "https://webpush.weixin.qq.com" 19 20 def login(request): 21 base_qcode_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&_={0}\' 22 global CURRENT_TIME 23 CURRENT_TIME = str(time.time()) 24 q_code_url = base_qcode_url.format(CURRENT_TIME) 25 response = requests.get(q_code_url) 26 # 二维码后缀 27 code = re.findall(\'uuid = "(.*)";\',response.text)[0] 28 global QCODE 29 QCODE = code 30 return render(request, \'login.html\', {\'code\': code}) 31 32 def long_polling(request): 33 print(\'polling....\') 34 ret = {\'status\': 408, \'data\': None} 35 # https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=IZpsHyzTNw==&tip=1&r=-897465901&_=1486956149964 36 # 408,201,200 37 try: 38 global TIPS 39 base_login_url = \'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip={1}&r=-897465901&_={2}\' 40 login_url = base_login_url.format(QCODE,TIPS,CURRENT_TIME) 41 response_login = requests.get(login_url) 42 if "window.code=201" in response_login.text: 43 TIPS = 0 44 avatar = re.findall("userAvatar = \'(.*)\';",response_login.text)[0] 45 ret[\'data\'] = avatar 46 ret[\'status\'] = 201 47 elif \'window.code=200\' in response_login.text: 48 # 扫码点击确认后,获取cookie 49 LOGIN_COOKIE_DICT.update(response_login.cookies.get_dict()) 50 redirect_uri = re.findall(\'redirect_uri="(.*)";\', response_login.text)[0] 51 global BASE_URL 52 global BASE_SYNC_URL 53 if redirect_uri.startswith(\'https://wx2.qq.com\'): 54 BASE_URL = \'https://wx2.qq.com\' 55 BASE_SYNC_URL = \'https://webpush.wx2.qq.com\' 56 else: 57 BASE_URL = "http://wx.qq.com" 58 BASE_SYNC_URL = "https://webpush.weixin.qq.com" 59 60 redirect_uri += \'&fun=new&version=v2&lang=zh_CN\' 61 62 # 获取票据,Cookie,返回值 63 response_ticket = requests.get(redirect_uri, cookies=LOGIN_COOKIE_DICT) 64 TICKET_COOKIE_DICT.update(response_ticket.cookies.get_dict()) 65 print(response_ticket.text) 66 from bs4 import BeautifulSoup 67 soup = BeautifulSoup(response_ticket.text,\'html.parser\') 68 for tag in soup.find(): 69 TICKET_DICT[tag.name] = tag.string 70 71 ret[\'status\'] = 200 72 73 # https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AZfYKn7CWTeZE_iMTHwv7GFB@qrticket_0&uuid=IeFZHVi6Jw==&lang=zh_CN&scan=1 74 # https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AepqqS0wvk1UN6bCGiaHHWXQ@qrticket_0&uuid=we1gq4TyyA==&lang=zh_CN&scan=1486957549" 75 except Exception as e: 76 print(e) 77 return HttpResponse(json.dumps(ret)) 78 79 80 def index(request): 81 # 初始化用户基本信息 82 # https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-909239606&lang=zh_CN&pass_ticket=Tpc2XEec%252BJ0q2qNRw6nqWzGSsQ3jM2LZtBCVJZfjvMTDxjiyJ9mO5eRtCNOveeXO 83 84 85 user_init_url = \'%s/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket=%s&r=%s\' % (BASE_URL, TICKET_DICT[\'pass_ticket\'], int(time.time())) 86 87 form_data = { 88 \'BaseRequest\': { 89 \'DeviceID\': \'e531777446530354\', 90 \'Sid\': TICKET_DICT[\'wxsid\'], 91 \'Skey\': TICKET_DICT[\'skey\'], 92 \'Uin\': TICKET_DICT[\'wxuin\'] 93 } 94 } 95 all_cookie_dict = {} 96 all_cookie_dict.update(LOGIN_COOKIE_DICT) 97 all_cookie_dict.update(TICKET_COOKIE_DICT) 98 99 response_init = requests.post(user_init_url, json=form_data, cookies=all_cookie_dict) 100 response_init.encoding = \'utf-8\' 101 user_init_data = json.loads(response_init.text) 102 # for k,v in user_init_data.items(): 103 # print(k,v) 104 USER_INIT_DATA.update(user_init_data) 105 """ 106 form_data = { 107 \'BaseRequest\':{ 108 \'DeviceID\': \'e531777446530354\', 109 \'Sid\': TICKET_DICT[\'wxsid\'], 110 \'Skey\': TICKET_DICT[\'skey\'], 111 \'Uin\': TICKET_DICT[\'wxuin\'] 112 } 113 } 114 all_cookie_dict = {} 115 all_cookie_dict.update(LOGIN_COOKIE_DICT) 116 all_cookie_dict.update(TICKET_COOKIE_DICT) 117 118 response_init = requests.post(user_init_url,json=form_data,) 119 response_init.encoding = \'utf-8\' 120 print(response_init.text) 121 """ 122 123 return render(request, \'index.html\',{\'data\': user_init_data}) 124 125 126 def contact_list(request): 127 """ 128 获取联系人列表 129 :param request: 130 :return: 131 """ 132 # https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket={0}&r={1}&seq=0&skey={2} 133 base_url = "{0}/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket={1}&r={2}&seq=0&skey={3}" 134 url = base_url.format(BASE_URL, TICKET_DICT[\'pass_ticket\'], str(time.time()), TICKET_DICT[\'skey\']) 135 136 all_cookie_dict = {} 137 all_cookie_dict.update(LOGIN_COOKIE_DICT) 138 all_cookie_dict.update(TICKET_COOKIE_DICT) 139 response = requests.get(url,cookies=all_cookie_dict) 140 response.encoding = \'utf-8\' 141 contact_list_dict = json.loads(response.text) 142 return render(request, \'contact_list.html\',{\'obj\': contact_list_dict}) 143 144 145 def send_msg(request): 146 147 from_user_id = USER_INIT_DATA[\'User\'][\'UserName\'] 148 to_user_id = request.POST.get(\'user_id\') 149 msg = request.POST.get(\'user_msg\') 150 151 send_url = BASE_URL + "/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket=" + TICKET_DICT[\'pass_ticket\'] 152 form_data = { 153 \'BaseRequest\': { 154 \'DeviceID\': \'e531777446530354\', 155 \'Sid\': TICKET_DICT[\'wxsid\'], 156 \'Skey\': TICKET_DICT[\'skey\'], 157 \'Uin\': TICKET_DICT[\'wxuin\'] 158 }, 159 \'Msg\':{ 160 "ClientMsgId": str(time.time()), 161 "Content": \'%(content)s\', 162 "FromUserName": from_user_id, 163 "LocalID": str(time.time()), 164 "ToUserName": to_user_id, 165 "Type": 1 166 }, 167 \'Scene\':0 168 } 169 import json 170 # 字符串 171 form_data_str = json.dumps(form_data) 172 # 进行格式化 173 form_data_str = form_data_str %{\'content\':msg} 174 175 # 转换成字节 176 form_data_bytes = bytes(form_data_str,encoding=\'utf-8\') 177 178 all_cookie_dict = {} 179 all_cookie_dict.update(LOGIN_COOKIE_DICT) 180 all_cookie_dict.update(TICKET_COOKIE_DICT) 181 182 response = requests.post(send_url, data=form_data_bytes, cookies=all_cookie_dict, headers={ 183 \'Content-Type\': \'application/json\'}) 184 print(response.text) 185 186 return HttpResponse(\'ok\') 187 188 def get_msg(request): 189 sync_url = BASE_SYNC_URL + "/cgi-bin/mmwebwx-bin/synccheck" 190 191 sync_data_list = [] 192 for item in USER_INIT_DATA[\'SyncKey\'][\'List\']: 193 temp = "%s_%s" % (item[\'Key\'], item[\'Val\']) 194 sync_data_list.append(temp) 195 sync_data_str = "|".join(sync_data_list) 196 nid = int(time.time()) 197 sync_dict = { 198 "r": nid, 199 "skey": TICKET_DICT[\'skey\'], 200 "sid": TICKET_DICT[\'wxsid\'], 201 "uin": TICKET_DICT[\'wxuin\'], 202 "deviceid": "e531777446530354", 203 "synckey": sync_data_str 204 } 205 all_cookie = {} 206 all_cookie.update(LOGIN_COOKIE_DICT) 207 all_cookie.update(TICKET_COOKIE_DICT) 208 response_sync = requests.get(sync_url, params=sync_dict, cookies=all_cookie) 209 print(response_sync.text) 210 if \'selector:"2"\' in response_sync.text: 211 fetch_msg_url = "%s/cgi-bin/mmwebwx-bin/webwxsync?sid=%s&skey=%s&lang=zh_CN&pass_ticket=%s" % (BASE_URL, TICKET_DICT[\'wxsid\'], TICKET_DICT[\'skey\'], TICKET_DICT[\'pass_ticket\']) 212 213 form_data = { 214 \'BaseRequest\': { 215 \'DeviceID\': \'e531777446530354\', 216 \'Sid\': TICKET_DICT[\'wxsid\'], 217 \'Skey\': TICKET_DICT[\'skey\'], 218 \'Uin\': TICKET_DICT[\'wxuin\'] 219 }, 220 \'SyncKey\': USER_INIT_DATA[\'SyncKey\'], 221 \'rr\': str(time.time()) 222 } 223 response_fetch_msg = requests.post(fetch_msg_url, json=form_data) 224 response_fetch_msg.encoding = \'utf-8\' 225 res_fetch_msg_dict = json.loads(response_fetch_msg.text) 226 USER_INIT_DATA[\'SyncKey\'] = res_fetch_msg_dict[\'SyncKey\'] 227 for item in res_fetch_msg_dict[\'AddMsgList\']: 228 print(item[\'Content\'], ":::::", item[\'FromUserName\'], "---->", item[\'ToUserName\'], ) 229 return HttpResponse(\'ok\')
8. 在templates文件夹下新建login.html、index.html、contact_list.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <div style="width: 300px;margin: 0 auto;"> 9 <!-- 二维码图片路径 --> 10 <img id="qcode" style="width: 300px;height: 300px;" src="https://login.weixin.qq.com/qrcode/{{ code }}"> 11 </div> 12 <script src="/static/jquery-1.12.4.js"></script> 13 <script> 14 $(function () { 15 polling(); 16 }); 17 18 function polling(){ 19 $.ajax({ 20 url: \'/polling/\', 21 type: "GET", 22 dataType: \'json\', 23 success: function(arg){ 24 if(arg.status == 408){ 25 polling(); 26 }else if(arg.status == 201){ 27 // 获取图片接着发 28 $(\'#qcode\').attr(\'src\', arg.data); 29 polling(); 30 }else { 31 window.location.href = \'/index/\' 32 } 33 } 34 }) 35 } 36 </script> 37 </body> 38 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <h1>个人信息</h1> 9 <div> 10 <img src="https://wx.qq.com{{ data.User.HeadImgUrl }}"> 11 </div> 12 <div> 13 {{ data.User.NickName }} - {{ data.User.UserName }} 14 </div> 15 <h1>联系人列表</h1> 16 <ul> 17 {% for row in data.ContactList%} 18 <li>{{ row.UserName }} - {{ row.NickName }}</li> 19 {% endfor %} 20 <li><a href="/contact_list/">获取更多联系人</a></li> 21 </ul> 22 23 <h1>公众号</h1> 24 {% for row in data.MPSubscribeMsgList%} 25 <div style="font-weight: bolder">{{ row.NickName }}</div> 26 {% for i in row.MPArticleList %} 27 <div> 28 <div><a href="{{ i.Url }}">{{ i.Title }}</a></div> 29 <div style="color: #dddddd">{{ i.Digest }}</div> 30 </div> 31 32 {% endfor %} 33 34 {% endfor %} 35 36 </body> 37 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <h1>发送消息</h1> 9 <div> 10 <p><input id="user_id" type="text" placeholder="请输入用户唯一ID" /></p> 11 <p><input id=\'user_msg\' type="text" placeholder="请输入内容" /></p> 12 <input id="sendMsg" type="button" value="提交" /> 13 </div> 14 <ul> 15 {% for row in obj.MemberList %} 16 <li>{{ row.NickName }} - {{ row.UserName }} -{{ row.Province }}</li> 17 {% endfor %} 18 </ul> 19 <script src="/static/jquery-1.12.4.js"></script> 20 <script> 21 $(function () { 22 bindSendMessage(); 23 fetchMessage(); 24 }); 25 function bindSendMessage() { 26 $(\'#sendMsg\').click(function () { 27 $.ajax({ 28 url: \'/send_msg/\', 29 type: \'POST\', 30 data: {\'user_id\': $(\'#user_id\').val(), \'user_msg\': $(\'#user_msg\').val()}, 31 success:function () { 32 33 } 34 }) 35 }); 36 } 37 38 function fetchMessage(){ 39 $.ajax({ 40 url: \'/get_msg/\', 41 type: \'GET\', 42 success:function (arg) { 43 fetchMessage(); 44 } 45 }) 46 } 47 </script> 48 </body> 49 </html>