一、概要

目的:实现一个具有web微信类似功能的项目

框架:Django

模块:render、HttpResponse、BeautifulSoup、re、time、requests、json、random

特点:web微信和其他的不太一样,这里不需要账号和密码,只需要扫描网页提供的二维码即可

二、具体步骤

1、登录页面

既然是要实现web版的微信,那么我们就要知道web微信都干了些什么。打开一个网页,右键点击检查,在地址栏输入web微信(https://wx.qq.com/)回车,我们会看到一个等待扫描的二维码页面。我们先来看一下这个二维码是如何来的,我们会看到二维码的标签有个src="https://login.weixin.qq.com/qrcode/oc8PLqKx0w==", 因为每次请求的时候二维码都会变化,我们猜测这个src中最后一个'/'后面的值是变化的,我们再去Network中去找到这个返回值。检查后我们会发现一个请求名为jsloginappid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwxbin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=1487297537475的response中有个uuid的值和我们需要的值类似。我们把这个求情的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&_=1487297850694,这个请求的方式是"GET"。观察后发现这个URL里的大部分的参数都是状态值,只有一个'_'我们猜测是时间戳。现在我们就可以试试能不能获取到二维码。

代码:

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="width: 300px; margin: 0 auto">
<!--二维码路径-->
<img src="https://login.weixin.qq.com/qrcode/{{ code }}">
</div>
<!--注释掉的部分是稍后请求扫码状态的函数-->
<!--<script src="/static/jquery-3.1.1.js"></script>
<script>
$(function () {
polling();
});
function polling() {
$.ajax({
url: '/long_polling/',
type: 'GET',
dataType: 'json',
success: function (arg) {
if (arg.status == 408){
polling()
}else if (arg.status == 201){
console.log(123);
$('img').attr('src', arg.data);
polling()
}else {
location.href = '/index/'
}
}
})
}
</script>-->
</body>
</html>

login.html

 from django.shortcuts import render

 from django.shortcuts import HttpResponse

 from bs4 import BeautifulSoup

 import re

 import time

 import requests

 import json

 import random

 CURRENT_TIME = None
QCODE = None
LOGIN_COOKIE_DICT = {}
TICKET_COOKIE_DICT = {}
TICKET_DICT = {}
TIPS = 1
BASE_URL = ''
BASE_SYNC_URL = ''
USER_ID = ''
USER_INFO = {}
USER_LIST_DIC = {}
# 这里用不到的全局变量后面会用到 def login(request):
# 登录页面,显示登录的二维码
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}'
global CURRENT_TIME
CURRENT_TIME = str(time.time())
q_code_url = base_qcode_url.format(CURRENT_TIME)
respons = requests.get(q_code_url)
# 二维码后缀
global QCODE
QCODE = re.findall('uuid = "(.*)";', respons.text)[0] # 拿括号里的内容的列表 return render(request, 'login.html', {'code': QCODE})

Views 获取二维码函数

这样我们可以看到一个二维码界面。接下来分析web微信做了什么:先给我们一个二维码,等待我们扫描,我们扫描后二维码会变成我们的头像,在手机端点击确认之后页面刷新,登录成功。

2、扫描并确认登录

我们扫描的时候是手机端给微信服务器发送了一个确认的请求。然后微信服务器将这个状态返回到web。但我们知道HTTP是无状态的,那么服务器如何将状态发送给我们的,我们猜测会有一个请求一直在发送。观察几分钟,会发现每隔25s左右会有一个请求发送,请求的地址为:https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=******&tip=0&r=******&_=******。我们看下这个请求的response,然后测试扫描和确认登录后这个返回值会不会有变化。当没有扫描二维码的时候返回值是window.code=408,扫描二维码之后是window.code=201,确认登录后是window.code=200。这个url里loginicon和tip是状态值,uuid我们猜测是刚才的二维码uuid,'_'是的值是一个时间戳,那么还剩下r我们没有值,检查之后我们发现并没有类似的返回值,我们先它作为一个随机值看,请求方式"GET",在请求的时候,直接将我们看到的数复制。然后我们去测试一下。在登录的HTML中我们在加载好页面之后执行一个类似于web等待扫描的长轮循函数,到views函数中去发送这个请求。我们将第一步HTML代码中注释掉的部分恢复。并在views中添加登录的代码。这里需要注意,在扫描或登录之后需要改变tip值为1,避免重复请求。确认登录之后我们将cookies进行保存。之后的请求中需要用到。

代码:

 def long_polling(request):
ret = {'status': 408, 'data': None} try:
global TIPS
base_login_url = 'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip={1}&' \
'r=-940286750&_={2}' login_url = base_login_url.format(QCODE, TIPS, CURRENT_TIME) response_login = requests.get(login_url) if 'window.code=201' in response_login.text:
TIPS = 0
avatar = re.findall("userAvatar = '(.*)';", response_login.text)
ret['status'] = 201
ret['data'] = avatar
elif 'window.code=200' in response_login.text:
ret['status'] = 200
# 扫码点击确认后获取cookie
LOGIN_COOKIE_DICT.update(response_login.cookies.get_dict())
# 获取redirect的url
base_ticket_url = re.findall('redirect_uri="(.*)";', response_login.text)[0]
# 不同的微信号在初始话数据的时候有不同的地址,需要甄别
global BASE_URL
global BASE_SYNC_URL
if base_ticket_url.startswith('https://wx2.qq.com'):
BASE_URL = 'https://wx2.qq.com'
BASE_SYNC_URL = 'https://webpush.wx2.qq.com'
else:
BASE_URL = 'https://wx.qq.com'
BASE_SYNC_URL = 'https://webpush.wx.qq.com'
# 组成获取票据的url
ticket_url = base_ticket_url + '&fun=new&version=v2&lang=zh_CN'
# 获取票据同时获取cookies response_ticket = requests.get(url=ticket_url, cookies=LOGIN_COOKIE_DICT)
TICKET_COOKIE_DICT.update(response_ticket.cookies.get_dict())
# 分析票据
soup = BeautifulSoup(response_ticket.text, 'html.parser')
for tag in soup.find():
TICKET_DICT[tag.name] = tag.string
except Exception as e:
print(e)
return HttpResponse(json.dumps(ret))

Views 扫描登录函数

我们在获取返回值的时候有一些在之后会用到,需要保存,并且web微信在确认登录后,会跳转页面,新页面会有两个,一个是:https://wx.qq.com/,另一个是:https://wx2.qq.com/。需要区别对待,如果这里不正确的话不能获取到信息。

登录成功后需要获取用户的基本信息,以及最近联系人列表。这是我们下一步要做的,初始化用户数据。

3、初始化用户数据

web微信在登录成功后会跳转一个页面,我们模仿这个方式,在确认登录之后,跳转URL,显示用户数据。我们再回到web微信检查Network看用户数据是哪个请求的response。可以找到一个webwxinit开头的请求,内部有初始化的数据。URL:https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=****&pass_ticket=****,这个URL有的参数我们是没有的,那么就要看看在这个请求之前是否有其他请求返回这些数据。可以发现一个webwxnewloginpage开头的请求,它有一个票据的返回数据,正是我们需要的。拿到数据,获取票据的时候需要重新赋值一个cookies。后边会用到。获取票据的代码我们写在登录的那个函数中。使用BeautifulSoup重构数据。然后去请求用户数据初始化。然后将初始化的数据拿出展示在页面。初始化用户数据的时候用的是POST请求,数据这里需要通过这个请求去看需要发送什么样的数据,以及在headers里检查数据类型是什么类型。所以我们发送POST请求的时候,在数据这边,是以"json"为key的。数据中有一个设备ID,可以参考前几次请求的ID填写。另外几条都在webwxnewloginpage的response中。

代码:

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1>个人信息</h1>
<a style="font-size: 20px; color: #1c5a9c">{{ info.User.NickName }}</a>
<a id="from_user_id">{{ info.User.UserName }}</a>
<p><input id="user_id" type="text" placeholder="请输入用户ID"></p>
<p><input id="msg_content" type="text" placeholder="请输入内容"></p>
<input id="send_msg" onclick="send_msg(this)" type="button" value="发送">
</div>
<div id="msg_box" style="height: 300px; width: 800px; border: solid 1px gray; overflow: auto"> </div>
<h1>最近联系人</h1>
{% for item in info.ContactList %}
<p>
<a style="font-size: 20px; color: #2F72AB">{{ item.NickName }}</a><a>{{ item.UserName }}</a>
<a>{{ item.Signature }}</a>
</p>
{% endfor %}
<div>
<div id="get_list" onclick="get_list()" style="cursor: pointer">获取全部好友</div>
<div class="empty"></div>
</div>
<h1>公众号</h1>
{% for item in info.MPSubscribeMsgList %}
<p>
<a style="font-size: 20px; color: #8a6d3b;">{{ item.NickName }}</a><a style="display: none">{{ item.UserName }}</a>
</p>
<p>
{% for i in item.MPArticleList %}
<div>
<a style="font-size: 18px">{{ i.Title }}</a>
<a href="{{ i.Url }}">{{ i.Digest }}</a>
</div> {% endfor %}
</p>
{% endfor %} <!--注释的部分是在获取好友列表以及发送和接收消息的时候用到的-->
<!--<script src="/static/jquery-3.1.1.js"></script>
<script>
<!--在页面加载好之后启动获取消息的函数-->
$(function () {
get_msg()
});
<!--获取好友列表函数-->
function get_list() {
$.ajax({
url: '/get_list',
type: 'GET',
dataType: 'json',
success: function (arg) {
var list = $("#get_list").siblings()[0];
if ($(list).hasClass('empty')){
var tag = '';
for (var i in arg.MemberList){
tag += "<div><a>" + arg.MemberList[i].NickName + "</a><a>[" + arg.MemberList[i].UserName + "]</a><a>[" + arg.MemberList[i].Province + arg.MemberList[i].City +"]</a></dib>";
}
$(list).append(tag);
$(list).removeClass();
}
}
})
}
<!--获取消息函数-->
function send_msg(self) {
var to_uid = $('#user_id').val();
var msg = $('#msg_content').val();
$.ajax({
url: '/send_msg',
type: 'GET',
dataType: 'json',
data: {'to_uid': to_uid, 'msg': msg},
success: function (arg) {
console.log(arg);
}
})
}
function get_msg() {
$.ajax({
url: '/get_msg',
type: 'GET',
dataType: 'json',
success: function (arg) {
if (arg.status){
var tag = "<div>" + arg.msg.user_id + "</div><div>" + arg.msg.msg_info + "</div>";
console.log(tag);
$('#msg_box').append(tag)
}
console.log(arg);
get_msg()
}
})
}
</script>-->
</body>
</html>

index.html

def index(request):
# 初始化用户数据 base_index_url = '{0}/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket={1}&r={2}' index_url = base_index_url.format(BASE_URL, TICKET_DICT['pass_ticket'], int(time.time())) user_cookies = {} user_cookies.update(LOGIN_COOKIE_DICT) user_cookies.update(TICKET_COOKIE_DICT) response_init = requests.post(url=index_url,
cookies=LOGIN_COOKIE_DICT,
json={
'BaseRequest': {
'DeviceID': "e199625221824018",
'Sid': TICKET_DICT['wxsid'],
'Skey': TICKET_DICT['skey'],
'Uin': TICKET_DICT['wxuin']
}
}) response_init.encoding = 'utf-8' user_init_data = json.loads(response_init.text) USER_INFO.update(user_init_data) return render(request, 'index.html', {'info': user_init_data})

Views 用户数据初始化函数

这样可以获取近期联系过的好友、群、公众号,还有一些公众号的信息。下一步我们要获取全部的好友。需要发送另一个请求获取。

4、获取好友列表

我们接着去看登录成功的web微信请求,查找返回全部好友信息的那一条: webwxgetcontact, URL:https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket=****&r=1487313589641&seq=0&skey=****,这个请求是get请求,链接中passticket和skey可以在票据中拿到,r是时间戳,seq是状态。在发送这个请求的时候我们加上登录成功后的cookie和获取票据时的cookie就可以了。然后将请求到的数据渲染到页面上。

代码:

我们将index.html中的get_list函数恢复。

 def get_list(request):
all_user_cookies = {} base_get_list_url = '{0}/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket={1}&r={2}&seq=0&skey={3}' get_list_url = base_get_list_url.format(BASE_URL, TICKET_DICT['pass_ticket'], int(time.time()), TICKET_DICT['skey']) all_user_cookies.update(LOGIN_COOKIE_DICT) # all_user_cookies.update(TICKET_COOKIE_DICT) response_list = requests.get(get_list_url, cookies=all_user_cookies) # 我们在获取数据的时候使用response_list.text会默认编码,但是一般我们指定使用'utf-8'进行编码 response_list.encoding = 'utf-8' list_info = response_list.text return HttpResponse(list_info)

Views 获取好友列表函数

这样可以将我们想看到的数据显示到页面上。接下来应该选择一个好友,然后给他发送消息了。

5、发送微信消息

我们回到web微信,发送一个消息,然后看Network里有什么变化。我们会看到一个webwxsendmsg开头的请求,URL:https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=****,同样,URL中的passticket去票据中取。这个请求是post请求,去查看数据。有三部分:第一部分是我们在获取好友列表的时候用过的,可以直接粘过来。第二部分需要我们去找。ClientMsgId和LocalID可以用时间戳,FromUserName、ToUserName、Content都可以在前端传过来,其中FromUserName也可以在之前初始化数据中找到,Type直接写1即可。我们只实现文字类型的传输。第三部分很简单,只有一个状态值。按照格式复制就可以了。

代码:

我们将index.html中的send_list函数恢复。

 def send_msg(request):
base_send_url = '{0}/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={1}'
send_url = base_send_url.format(BASE_URL, TICKET_DICT['pass_ticket'])
from_uid = USER_INFO['User']['UserName']
to_uid = request.GET.get('to_uid')
msg = request.GET.get('msg') # current_time = str(int(time.time() * 1000)) + str(random.random())[:5].replace('.', '') form_data = {
'BaseRequest': {
'DeviceID': "e199625221824018",
'Sid': TICKET_DICT['wxsid'],
'Skey': TICKET_DICT['skey'],
'Uin': TICKET_DICT['wxuin']
},
'Msg': {
'ClientMsgId': str(time.time()),
'Content': '%(content)s',
'FromUserName': from_uid,
'LocalID': str(time.time()),
'ToUserName': to_uid,
'Type': 1
},
'Scene': 0
} all_cookies = {} all_cookies.update(LOGIN_COOKIE_DICT) all_cookies.update(TICKET_COOKIE_DICT) form_data_str = json.dumps(form_data) form_data_str = form_data_str % {'content': msg} form_data_bytes = bytes(form_data_str, encoding='utf-8') response_send = requests.post(
url=send_url,
data=form_data_bytes,
cookies=all_cookies,
headers={
'Content-Type': 'application/json',
}
) return HttpResponse("ok")

Views 发送消息函数

需要注意的是,在发送消息的时候,我们要先将data进行json.dumps,之后再将发送消息的部分进行bytes转换。否则,汉字会变为ascii编码格式发出。是因为我们在json的时候,会将汉字转换为ascii编码格式,再发送前还会进行一次bytes类型转换。这样就把源数据改变了。也可以在dumps的时候加上一个ensure_ascii=False参数阻止转变成ascii编码格式。这样我们就剩最后一步没有做了。

6、接收微信消息

接收消息,其实就是服务器将别人发送的消息发送给我们,那么之前说过http是无状态的,说到这里,应该都已经想到了,我们还是要做一个长轮循来监听消息。在web界面登录成功后我们还会看到一个一直在发送的请求,去检查它。没错就是synccheck开头的那个。URL:https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=1487320137207&skey=***&sid=****&uin=****&deviceid=****&synckey=****,请求方式:GET,对用get请求方式,URL后面的数据我们也可以通过在requests请求的的时候在参数中添加params传递。在这里r对应的是时间戳,skey、sid、uin都可以在票据中取到。deviceid使用我们之前使用过的就好。synckey稍微有一点麻烦,需要我们构造。其数据可以通过用户初始化数据取到。这个请求发送过去之后,会返回一个值,来告诉浏览器是否有消息发送过来。当收到有消息过来的时候我们就要发送另一个请求:webwxsync开头的那个,URL:https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=****&skey=****&pass_ticket=****,方式是post,URL中的三个参数都可以从票据中获取。post的数据有也都是我们用过的,只有一个"SyncKey",需要到用户初始数据中取,找到那个key就可以拿到。拿到数据之后使用"utf-8"进行编码,之后使用json.loads,将拿到的数据进行分析。首先看数据中的"StatusNotifyCode"是否为0,如果不是,那么数据不做处理,是因为,我们在手机客户端点进一个群的时候就会有数据返回,但是是历史消息,这个我们不要,当有即时消息发送过来的时候刚才的那个key对应的数据为0。然后将数据拿到返回到页面显示即可。

代码:

我们将index.html中的get_msg函数恢复。

def get_msg(request):
ret = {"status": False, "msg": ''}
# 构造synckey
synckey = []
for i in USER_INFO['SyncKey']['List']:
synckey.append(str(i['Key']) + '_' + str(i['Val']))
synckey_str = "|".join(synckey) synckey_url = '%s/cgi-bin/mmwebwx-bin/synccheck' % BASE_SYNC_URL current_time = str(time.time()) all_cookies = {} all_cookies.update(LOGIN_COOKIE_DICT) all_cookies.update(TICKET_COOKIE_DICT) respons_synckey = requests.get(
url=synckey_url,
cookies=all_cookies,
params={
'r': current_time,
'skey': TICKET_DICT['skey'],
'sid': TICKET_DICT['wxsid'],
'uin': TICKET_DICT['wxuin'],
'deviceid': "e199625221824018",
'synckey': synckey_str
}
) content = ""
if 'selector:"2"' in respons_synckey.text:
base_get_msg_url = '{0}/cgi-bin/mmwebwx-bin/webwxsync?sid={1}&skey={2}&pass_ticket={3}'
get_msg_url = base_get_msg_url.format(BASE_URL, TICKET_DICT['wxsid'], TICKET_DICT['skey'], TICKET_DICT['pass_ticket'])
form_data = {
'BaseRequest': {
'DeviceID': "e199625221824018",
'Sid': TICKET_DICT['wxsid'],
'Skey': TICKET_DICT['skey'],
'Uin': TICKET_DICT['wxuin']
},
'SyncKey': USER_INFO['SyncKey'],
'rr': current_time
} respons_get_msg = requests.post(
url=get_msg_url,
json=form_data
) respons_get_msg.encoding = 'utf-8'
res_fetch_msg_dict = json.loads(respons_get_msg.text)
USER_INFO['SyncKey'] = res_fetch_msg_dict['SyncKey'] # 有消息来到,需要更新SyncKey状态否则会一直是有消息的状态 print(res_fetch_msg_dict) for item in res_fetch_msg_dict['AddMsgList']:
if item['StatusNotifyCode'] == 0:
print(item['Content'], ":::::", item['FromUserName'], "---->", item['ToUserName'], )
ret["status"] = True
ret['msg'] = {'user_id': item['FromUserName'], 'msg_info': item['Content']} return HttpResponse(json.dumps(ret))

Views 获取消息函数

这里需要注意的是,在接收消息后,将用户初始化数据中的"SyncKey"更新为发送的消息中的"SyncKey",如果不更新的话,这条数据就会一直被取到。

Web微信模拟的更多相关文章

  1. 模拟登陆web微信的流程和参数细节

    这几天在用python写了一个模拟登陆web微信,发送和接受信息的程序.发现步骤不多,但需要的参数太多了 整个过程中,务必保证session.headers.cookie一致,不然的话,中间会出现登陆 ...

  2. Python 爬虫五 进阶案例-web微信登陆与消息发送

    首先回顾下网页微信登陆的一般流程 1.打开浏览器输入网址 2.使用手机微信扫码登陆 3.进入用户界面 1.打开浏览器输入网址 首先打开浏览器输入web微信网址,并进行监控: https://wx.qq ...

  3. 爬虫概要及web微信请求分析

    一.爬虫概要 1.网络爬虫是什么 百度百科:网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常 ...

  4. 实现手机扫描二维码页面登录,类似web微信-第一篇,业务分析

    转自:http://www.cnblogs.com/fengyun99/p/3541249.html 关于XMPP组件的文章,先休息两天,好歹已经完整的写了一份. 这两天,先实现一套关于web微信扫描 ...

  5. 基于Flask 实现Web微信登陆

    网页版微信登陆网址 https://login.wx.qq.com/ 获取微信登陆的二维码 在浏览器中访问登陆接口 https://login.wx.qq.com/ 我们查找二维码的图片可以看到 其中 ...

  6. requests+django+bs4实现一个web微信的功能

    前言: 今天我们利用requests模块+django+bs4浏览器来实现一个web微信的基本功能,主要实现的功能如下 a.实现返回二维码 b.实现手机扫码后二维码变成变成头像 c.实现手机点击登陆成 ...

  7. 基于Flask开发web微信

    1. 获取二维码 app.py import re import time import requests from flask import Flask,render_template app = ...

  8. web微信开发总结

    这两天使用Django开发了web微信,实现了显示联系人以及收发消息的功能. 总结下这过程中使用到的一些知识. 1 http请求 通过chrome浏览器自带的开发者工具查看每次请求的信息,分析请求,包 ...

  9. day37 爬虫2(web微信、高性能相关、Scrapy)

    s16day37 爬虫2 参考博客:http://www.cnblogs.com/wupeiqi/articles/6229292.html 课堂代码:https://github.com/liyon ...

随机推荐

  1. Delphi Create(nil), Create(self), Create(Application)的区别

    最近的项目中经常在程序中动态创建控件,势必用到Create. 但是随之而来的问题就是动态创建的控件是否可以正确的释放内存? 以及 Create(nil), Create(self), Create(A ...

  2. LCD学习

    LCD简介(1)显示器,常见显示器(2)LCD(Liquid Crystal Display),液晶显示器,原理介绍(3)LCD应用领域(4)LED OLED1.17.1.2.电子显示器的原理(1)像 ...

  3. 皮尔逊相关系数(Pearson Correlation Coefficient, Pearson's r)

    Pearson's r,称为皮尔逊相关系数(Pearson correlation coefficient),用来反映两个随机变量之间的线性相关程度. 用于总体(population)时记作ρ (rh ...

  4. 【JVM】关于类加载器准备阶段的一道面试题目

    一个经典的延伸问题 我们来看一个经典的延伸问题,准备阶段谈到静态变量,那么对于常量和不同静态变量有什么区别? 需要明确的是,没有人能够精确的理解和记忆所有信息,如果碰到这种问题,有直接答案当然最好:没 ...

  5. properties文件操作

    properties文件操作类 可以使用java.util.Properties读取.properties文件中的内容 import java.io.InputStream; import java. ...

  6. Python【初识篇】简介

    python是什么? 为什么学python? python在权威语言排序网站上的热度 python历史排名 python应用领域 哪些公司在用python python官方简介 上面的话简单的总结来说 ...

  7. Vue+koa2开发一款全栈小程序(6.个人中心)

    1.用户信息的获取和展示 1.初始化数据库 cd到server目录下,执行 node tools/initdb.js 登录mysql控制界面,查看初始化以后生成的表 show databases; u ...

  8. mysql/mariadb主从复制

    主从复制简介 MySQL数据库的主从复制方案,是其自带的功能,并且主从复制并不是复制磁盘上的数据库文件,而是通过binlog日志复制到需要同步的从服务器上. MySQL数据库支持单向.双向.链式级联, ...

  9. 《Java》第四周学习总结

    20175301 李锦然 一:本周学习内容 1:学习第五章视频 2:做实验 第五章主要讲的是子类与父类的关系,子类的继承与多态,final类super类等内容 仓库地址https://gitee.co ...

  10. Spring Security 之方法级的安全管控

    默认情况下, Spring Security 并不启用方法级的安全管控. 启用方法级的管控后, 可以针对不同的方法通过注解设置不同的访问条件. Spring Security 支持三种方法级注解, 分 ...