目录

说明

本文做的是百度二维码扫码登陆,至于为什么要做扫码登陆,主要是因为:1,用账号密码登陆时,在测试过程中,如果清除cookie,会弹出验证码,这个倒是无所谓,要命的是在登陆过程中有可能出发百度的账号保护机制,就算输入验证码,百度还会强制要求手机短信进行二次验证,这个触发机制目前还不明确。

准备环境

准备python3环境以及安装requests类库,chorme浏览器。关于requests类库的基本用法可参考链接:爬虫利器requests

登陆过程分析

需要知道的是:百度是以cookie来对用户的身份进行校验的,当登陆成功以后,可以免验证访问百度相关的所有站点,包括百度贴吧,百度云盘等。模拟登陆成功的标志就是我们拿到用于验证身份的cookie。所以,我们的主要目的就是寻找哪些请求设置了cookie

第一步:打开chorme浏览器,清除百度相关的所有cookie,如当时已经登陆的话,删除cookie后将处于未登陆状态。如下图所示,删除图中所有的cookie:

第二步:再次访问百度首页,并清除现有cookie,保证点击登陆按钮之前是没有任何cookie产生的。之后摁F12键,进入浏览器开发者模式,点击登陆按钮,选择二维码登陆,查看请求记录。如下图所示:

可以发现:除去css/img等资源后,主要的链接有:

序号

链接

1

uni_login_wrapper.js...

2

_blank.html

3

?getapi&tpl=mn...

4

getqrcode?lp=pc...

5

viewlog?ak=1e3f2...

6

?loginhistory&token=a7...

7

unicast?channel_id=d15...

查看uni_login_wrapper...这个链接的具体信息,可以看到,它的响应头中设置了BAIDUID这个cookie,并且可以发现,后面的所有链接的请求中都带有BAIDUID这个cookie

查看_balnk.html可以发现,它的响应头中没有设置任何cookie

查看?getapi这个链接,我们可以发现,它的响应头中设置了HOSUPPORT=1这个cookie,并且返回了一个json数组,里面有一个token,它的请求参数与响应分别如下图:

这个请求的主要作用就是为了获得token,它是后续?loginhistory?token=...请求的参数。

查看getqrcode?lp=pc..这个链接,可以发现,它的响应头中没有设置cookie,但是,它的返回信息中附带了一个链接,这个链接正是二维码图片的请求地址,如下图所示。访问其中的imgurl即可得到二维码。其中还有一个值sign,这个值是后续unicast?channel_id=34...这个请求中的channel_id。

查看viewlog?ak=...这个请求可以看到,它的响应头中设置了pplogid这个cookie,测试发现,这个cookie并不是关键性的,可有可无,如下图:

查看?loginhistory?token=...这个请求可以发现,它设置了PASSID、UBI、HISTORY这三个cookie

查看unicast?channel_id=...这个请求,可以发现,只要我们一直没有扫描二维码,客户端会不断发送这个请求,这个请求正是用来检测我们是否扫描了二维码。,如下图所示

第三步:用百度APP扫描二维码,继续分析后续请求,扫描之后,会出现三个关键请求,如下图所示:

从上一步已经知道unicast?channel_id=...这个请求是为了判断我们是否已经扫描了二维码,可以判定,如果扫描成功,它必定会返回一个用于认证的重要信息。两次请求的反回值分别如下:

从这几张图可以看出,这个返回的v与登陆请求qrbdusslogin?v=..&bduss=...中的参数bduss值相同,与之对应。

继续分析最后的登陆请求,即qrbdusslogin?v=..budss=...,观察它的响应头可以发现其中有几个cookie值:STOKEN、PTOKEN、BDUSS,这正是授权登陆的关键所在,如下图所示:

至此,获得上述几个值后,登陆成功。

登陆过程代码

首先定义两个工具函数,一个用来获取毫秒级的时间戳,一个用来将类似于下图的返回信息转换为json,方便信息提取

[外链图片转存失败(img-IiKBvGHH-1562065335192)(/public/static/extimg/article/2019/1561993367666qrurl.png)]

# 获取毫秒级时间戳

def get_cur_timestamp():

return int(round((time.time()) * 1000))

# 将callback转换为json

def parsecallback_tojson(callbackstr):

return json.loads(re.search(r'\(.*\)', callbackstr).group().replace("(", "").replace(")", ""))

网站一般还对请求头有所限制,所以还需定义请求头,将其保存在config.py文件中。

# -*- coding: utf-8 -*-

headers = {

'passport_headers':{

'Host': 'passport.baidu.com',

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',

'Refer': 'https://www.baidu.com/?tn=62095104_7_oem_dg'

},

'tieba_headers':{

'Host': 'tieba.baidu.com',

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',

'Refer': 'https://www.baidu.com/?tn=62095104_7_oem_dg',

'Origin': 'https://tieba.baidu.com'

}

}

** 获取BAIDUID: ** 根据上面的分析,首先获取BAIDUID,并定义一个login_cookies封装请求cookie。请求所需要的参数都可以通过浏览器的开发者摸式看到,这里不再细说。

# 封装登陆用的cookie

login_cookies = {}

headers = config.headers['passport_headers']

init_url='https://passport.baidu.com/passApi/js/uni_login_wrapper.jscdnversion=1561973784431&_=1561973762531'

init_r = requests.get(init_url, headers=headers, verify=False)

# 获取BAIDUID

init_cookies = init_r.cookies

login_cookies['BAIDUID'] = init_cookies['BAIDUID']

** 获取token: ** 利用正则表达式直接从返回结果中提取,其中tpl、apiver、class、loginversion、logintype这几个参数都是固定的,tt是当前的时间戳,callback是接收返回信息的参数,格式是固定的,可以写死。

# 获取token

token_url = 'https://passport.baidu.com/v2/api/?getapi'

t_params = {

'tpl': 'mn',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'class': 'login',

'gid': gid,

'loginversion': 'v4',

'logintype': 'dialogLogin',

'traceid': None,

'callback': 'bd__cbs__5kjmhe'

}

token_r = requests.get(token_url, headers=headers, params=t_params, cookies=init_cookies, verify=False)

token = re.search(r'[\w]{32}', token_r.text).group()

** 请求验证码,并保存到本地,解析signcode ** :其中gid是随机生成的格式固定的字符串,tt、_都是时间戳,其它参数是固定的,在这个步骤中需要解析出signcode这个参数,它是与当前生成的二维码唯一对应的字符串,用于拼接二维码图片地址和后面的扫码校验。

# 获取验证码地址

qrcode_url = 'https://passport.baidu.com/v2/api/getqrcode'

qr_params = {

'lp': 'pc',

'qrloginfrom': 'pc',

'gid': '6F11F8D-EDD5-4A78-8B51-42D86D2DA7F4',

'callback': 'tangram_guid_1561697778375',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'tpl': 'mn',

'_': get_cur_timestamp()

}

qrcode_r = requests.get(qrcode_url, headers=headers, params=qr_params, cookies=init_cookies, verify=False)

# 从返回信息中解析出signcode

signcode = re.search(r'[\w]{32}', qrcode_r.text).group()

qrimg_url = 'https://passport.baidu.com/v2/api/qrcode?sign=%s&lp=pc&qrloginfrom=pc' % signcode

# 将验证码保存进入图片

with open('qrcode.jpg', 'wb') as f:

qr_r = requests.get(qrimg_url, headers=headers, cookies=login_cookies, verify=False)

f.write(qr_r.content)

** history请求 ** 获取passid、ubi、history三个cookie,并封装到auth_cookies中

# 获取passid,ubi,history参数

login_cookies['HOSUPPORT'] = '1'

loginhistory_url = 'https://passport.baidu.com/v2/api/?loginhistory'

loginhistory_params = {

'token': token,

'tpl': 'mn',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'loginversion': 'v4',

'gid': gid,

'traceid': None,

'callback': 'bd__cbs__um4fp5'

}

loginhistory_r = requests.get(loginhistory_url, params=loginhistory_params, headers=headers,

cookies=login_cookies, verify=False)

loginhistory_cookiestr = loginhistory_r.headers['Set-Cookie']

passid = None

ubi = None

history = None

# 获取PASSID

paasid_searchres = re.search(r'PASSID=(\w*[^;])', loginhistory_cookiestr)

if paasid_searchres:

passid = paasid_searchres.group(1)

# 获取UBI

ubi_searchres = re.search(r'UBI=([\w%-]*[^;])', loginhistory_cookiestr)

if ubi_searchres:

ubi = ubi_searchres.group(1)

# 获取HISTORY

history_searchres = re.search(r'HISTORY=(\w-*[^;])', loginhistory_cookiestr)

if history_searchres:

history = history_searchres.group(1)

login_cookies['PASSID'] = passid

login_cookies['UBI'] = ubi

login_cookies['HISTORY'] = history

** 扫码,获取BDUSSD参数: ** 上面的步骤中已经将二维码保存到本地,此时构建unicast轮询是否已经扫描二维码,如果扫描了,就获取返回的bdussd参数。

# 获取扫码登陆信息,判断是否已经扫码

channel_url = 'https://passport.baidu.com/channel/unicast'

chanel_param = {

'channel_id': signcode,

'tpl': 'mn',

'gid': gid,

'callback': 'tangram_guid_1561776159383',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'_': get_cur_timestamp()

}

while True:

channel_r = requests.get(channel_url, headers=headers, cookies=login_cookies, verify=False, params=chanel_param)

channel_r_json = parsecallback_tojson(channel_r.text)

# 获取bdussd,此处巨坑,判定扫码之后需再次请求一次否则获取不到bdussd

if (channel_r_json['errno'] == 0) and (json.loads(channel_r_json['channel_v'])['status']) == 1:

channel_r = requests.get(channel_url, headers=headers, cookies=login_cookies, verify=False,params=chanel_param)

bdussd = json.loads(parsecallback_tojson(channel_r.text)['channel_v'])['v']

break

** 获取登陆授权cookie **:利用上步得到的bduss进行登陆请求,获取授权信息,并将其写入本地auth_cookies.txt文件中

# 利用bdussd进行登陆

login_url = 'https://passport.baidu.com/v3/login/main/qrbdusslogin'

login_params = {

'v': get_cur_timestamp(),

'bduss': bdussd,

'u': 'https://www.baidu.com/?tn=62095104_7_oem_dg',

'qrcode': '1',

'pl': 'mn',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'traceid': None,

'callback': 'bd__cbs__raxv3h'

}

login_r = requests.get(login_url, headers=headers, params=login_params, cookies=login_cookies, verify=False)

# 解析授权cookie

auth_cookies = {}

loginsuccess_cookiestr = login_r.headers['Set-Cookie']

BDUSS = re.search(r'BDUSS=([\w%-]*[^;])', loginsuccess_cookiestr).group(1)

STOKEN = re.search(r'STOKEN=([\w%-]*[^;])', loginsuccess_cookiestr).group(1)

PTOKEN = re.search(r'PTOKEN=([\w%-]*[^;])', loginsuccess_cookiestr).group(1)

auth_cookies['BDUSS'] = BDUSS

auth_cookies['STOKEN'] = STOKEN

auth_cookies['PTOKEN'] = PTOKEN

with open('auth_cookies.txt', 'w') as f:

f.write(json.dumps(auth_cookies))

至此,整个登陆流程完成。

完整代码以及登陆有效性验证

# -*- coding: utf-8 -*-

import requests

import time

import config

import re

import json

# 获取毫秒级时间戳

def get_cur_timestamp():

return int(round((time.time()) * 1000))

# 将callback转换为json

def parsecallback_tojson(callbackstr):

return json.loads(re.search(r'\(.*\)', callbackstr).group().replace("(", "").replace(")", ""))

class QRLogin:

@staticmethod

def get_auth_cookie():

# 封装登陆用的cookie

login_cookies = {}

# 随机生成的字符串、格式固定

gid = '6F11F8D-EDD5-4A78-8B51-42D86D2DA7F4'

headers = config.headers['passport_headers']

init_url='https://passport.baidu.com/passApi/js/uni_login_wrapper.js?cdnversion=1561973784431&_=1561973762531'

init_r = requests.get(init_url, headers=headers, verify=False)

# 获取BAIDUID

init_cookies = init_r.cookies

login_cookies['BAIDUID'] = init_cookies['BAIDUID']

# 获取token

token_url = 'https://passport.baidu.com/v2/api/?getapi'

t_params = {

'tpl': 'mn',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'class': 'login',

'gid': gid,

'loginversion': 'v4',

'logintype': 'dialogLogin',

'traceid': None,

'callback': 'bd__cbs__5kjmhe'

}

token_r = requests.get(token_url, headers=headers, params=t_params, cookies=login_cookies, verify=False)

token = re.search(r'[\w]{32}', token_r.text).group()

# 获取验证码地址

qrcode_url = 'https://passport.baidu.com/v2/api/getqrcode'

qr_params = {

'lp': 'pc',

'qrloginfrom': 'pc',

'gid': gid,

'callback': 'tangram_guid_1561697778375',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'tpl': 'mn',

'_': get_cur_timestamp()

}

qrcode_r = requests.get(qrcode_url, headers=headers, params=qr_params, cookies=login_cookies, verify=False)

signcode = re.search(r'[\w]{32}', qrcode_r.text).group()

qrimg_url = 'https://passport.baidu.com/v2/api/qrcode?sign=%s&lp=pc&qrloginfrom=pc' % signcode

# 将验证码保存进入图片

with open('qrcode.jpg', 'wb') as f:

qr_r = requests.get(qrimg_url, headers=headers, cookies=init_cookies, verify=False)

f.write(qr_r.content)

# 获取passid,ubi,history参数

login_cookies['HOSUPPORT'] = '1'

loginhistory_url = 'https://passport.baidu.com/v2/api/?loginhistory'

loginhistory_params = {

'token': token,

'tpl': 'mn',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'loginversion': 'v4',

'gid': gid,

'traceid': None,

'callback': 'bd__cbs__um4fp5'

}

loginhistory_r = requests.get(loginhistory_url, params=loginhistory_params, headers=headers, cookies=login_cookies, verify=False)

loginhistory_cookiestr = loginhistory_r.headers['Set-Cookie']

passid = None

ubi = None

history = None

# 获取PASSID

paasid_searchres = re.search(r'PASSID=(\w*[^;])', loginhistory_cookiestr)

if paasid_searchres:

passid = paasid_searchres.group(1)

# 获取UBI

ubi_searchres = re.search(r'UBI=([\w%-]*[^;])', loginhistory_cookiestr)

if ubi_searchres:

ubi = ubi_searchres.group(1)

# 获取HISTORY

history_searchres = re.search(r'HISTORY=(\w-*[^;])', loginhistory_cookiestr)

if history_searchres:

history = history_searchres.group(1)

login_cookies['PASSID'] = passid

login_cookies['UBI'] = ubi

login_cookies['HISTORY'] = history

# 获取扫码登陆信息,判断是否已经扫码

channel_url = 'https://passport.baidu.com/channel/unicast'

chanel_param = {

'channel_id': signcode,

'tpl': 'mn',

'gid': gid,

'callback': 'tangram_guid_1561776159383',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'_': get_cur_timestamp()

}

while True:

channel_r = requests.get(channel_url, headers=headers, cookies=login_cookies, verify=False, params=chanel_param)

channel_r_json = parsecallback_tojson(channel_r.text)

# 获取bdussd,此处巨坑,判定扫码之后需再次请求一次否则获取不到bdussd

if (channel_r_json['errno'] == 0) and (json.loads(channel_r_json['channel_v'])['status']) == 1:

channel_r = requests.get(channel_url, headers=headers, cookies=login_cookies, verify=False,params=chanel_param)

bdussd = json.loads(parsecallback_tojson(channel_r.text)['channel_v'])['v']

break

# 利用bdussd进行登陆

login_url = 'https://passport.baidu.com/v3/login/main/qrbdusslogin'

login_params = {

'v': get_cur_timestamp(),

'bduss': bdussd,

'u': 'https://www.baidu.com/?tn=62095104_7_oem_dg',

'qrcode': '1',

'pl': 'mn',

'apiver': 'v3',

'tt': get_cur_timestamp(),

'traceid': None,

'callback': 'bd__cbs__raxv3h'

}

login_r = requests.get(login_url, headers=headers, params=login_params, cookies=login_cookies, verify=False)

# 解析授权cookie

auth_cookies = {}

loginsuccess_cookiestr = login_r.headers['Set-Cookie']

BDUSS = re.search(r'BDUSS=([\w%-]*[^;])', loginsuccess_cookiestr).group(1)

STOKEN = re.search(r'STOKEN=([\w%-]*[^;])', loginsuccess_cookiestr).group(1)

PTOKEN = re.search(r'PTOKEN=([\w%-]*[^;])', loginsuccess_cookiestr).group(1)

auth_cookies['BDUSS'] = BDUSS

auth_cookies['STOKEN'] = STOKEN

auth_cookies['PTOKEN'] = PTOKEN

with open('auth_cookies.txt', 'w') as f:

f.write(json.dumps(auth_cookies))

return auth_cookies

if __name__ == '__main__':

print(QRLogin.get_auth_cookie())

有效性测试

利用之前获取到的授权cookie访问百度个人中心页面,如果能取到用户名,则说明登陆成功。获取用户名可以通过检查元素,找到class=ibx-uc-nick的a标签,用正则表达式取出,具体如下图

具体代码如下:

def check():

headers = {

'Host': 'i.baidu.com',

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',

'Refer': 'https://www.baidu.com/?tn=62095104_7_oem_dg',

'Origin': 'https://baidu.com'

}

# 这个函数会暂时阻塞,直到扫码为止

auth_cookies = QRLogin.get_auth_cookie()

ibaidu_url = 'https://i.baidu.com'

ibaidu_r = requests.get(ibaidu_url, cookies=auth_cookies, headers=headers)

pattern = r']*class=\"ibx-uc-nick\">([^'

myname = re.search(pattern, ibaidu_r.text).group(1)

print("你的登陆用户名是:%s" % myname)

python自动登录百度_python模拟百度登陆相关推荐

  1. python自动登录教程_python+selenium实现163邮箱自动登陆的方法

    本文介绍了 让我们先来预览一下代码运行效果吧: 首先分析163邮箱登陆页面的网页结构(按F12或单击鼠标右键选择审查元素) 1.定位到登陆框(注意登录框是一个iframe,如果不定位到iframe的话 ...

  2. python 自动登录方法_Python自动登录126邮箱的方法

    本文实例讲述了Python自动登录126邮箱的方法.分享给大家供大家参考.具体实现方法如下: import sys, urllib2, urllib,cookielib import re cooki ...

  3. python自动登录校园网_python 脚本自动登陆校园网

    学校的校园网每次重开电脑时都要重新打开浏览器进行网页登录,繁琐的操作比较麻烦,于是便写了个python的脚本进行自动登录,下面说下具体的操作过程: 1. 方法说明 博主采用的python的 reque ...

  4. python自动登录教程_python实现校园网自动登录的示例讲解

    因为最近想用树莓派搞个远程监控系统,又因为学校的网需要从网页登录而树莓派又不方便搞个显示器带着,所以寻思着搞个能够自动登录校园网的脚本程序,省去了每次都要打开浏览器输入账号密码的烦恼. 1.工具 火狐 ...

  5. python自动登录教程_Python 实现自动登录+点击+滑动验证功能

    需要用到的库有selenium,还需要安装Chrome浏览器驱动,具体如何安装我就不详述了 在这里我模拟了csdn的登录过程 ** 1**.首先打开网页,用户名+密码登录,然后定位用户名输入框,和密码 ...

  6. python 自动登录网站_python实现网站用户名密码自动登录功能

    一.概述 公司需要通过网页用户认证登录实现上网,网络设备判断当前帐号12小时没有没上网将会自动断开帐号上网,每天早上上班第一件事就是打开用户认证网页输入. 用户名与密码,有时候要家里通过teamvie ...

  7. python 自动登录方法_Python实现自动登录百度空间的方法

    location.href="/zhouciming/home" rel="external nofollow" ;

  8. python自动登录教程_Python实现自动登录百度空间的方法,python自动登录

    location.href="/zhouciming/home" rel="external nofollow" ;

  9. python脚本根据cookies自动登录网站_python模拟登录并且保持cookie的方法详解

    前言 最近在爬行 nosec.org 的数据,看了下需要模拟登录拿到cookie后才能访问想抓的数据,重要的是 nosec.org 的登录页面 form 中有个 authenticity_token ...

  10. python自动投递简历_python模拟登录前程无忧,发送简历

    主要想模拟登录,抓取相关公司,发送简历. 已经实现验证码手动输入,抓取相关公司,发送简历这个功能现在在想如何实现. import requests from bs4 import BeautifulS ...

最新文章

  1. java treemap用法_JAVA作业,使用TreeMapK,V类
  2. 浏览器安全检查己通过_小米薄荷浏览器URl欺骗漏洞(CVE-2019-10875)的安全修复被绕过...
  3. lua的一些api文档总结吧
  4. java运行环境_Windows系统java运行环境配置 | 吴文辉博客
  5. L1-015. 跟奥巴马一起画方块-PAT团体程序设计天梯赛GPLT
  6. vector二维的长度
  7. flare3d_FLSL
  8. Putty连接TPYBorad v102 开发板教程
  9. java jshell_java9系列(一)安装及jshell使用
  10. 服务器建网站要数据库,云服务器建网站需要数据库
  11. phpMyAdmin4.8.1漏洞复现及利用
  12. 入门级服务器的选购——DIY篇
  13. EntityComponentSystemSamples学习笔记
  14. 我的阿里云盘资源搜索引擎首次试运行
  15. QA:GMS认证、CTS测试、GTS测试、谷歌认证、安卓认证,Android
  16. MATLAB导入EXCEL数据D=xlsread()的一种情况
  17. 区块链三加一 “成才”路上提个醒:区块链培训机构鱼龙混杂
  18. OpenWorm项目
  19. 【Win11】重装系统教程
  20. 网络安全审计系统浅谈

热门文章

  1. scrapy 官方文档(入门必备)
  2. 如何下载朝阳区卫星地图高清版大图
  3. SD/TF卡驱动(一)--------SD卡相关简介
  4. 如何在知网下载PDF格式的硕博毕业论文?
  5. 计算机操作系统有几种基本管理,操作系统有哪些管理功能
  6. 卡巴斯基密码管理器新版面世,再也不必担心账户安全
  7. JavaScript中常见的设计模式
  8. 我们最畅销的30本好书,都在这了
  9. 电工/模电/数电/电气控制/PLC/单片机综合实验装置
  10. linux搭建ntp发包教程,linux 搭建本地ntp服务器