python模拟百度登陆

本文原地址

目录

说明
环境准备
登陆过程分析
登陆过程完整代码
有效性测试

说明

本文做的是百度二维码扫码登陆,至于为什么要做扫码登陆,主要是因为: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值:STOKENPTOKENBDUSS,这正是授权登陆的关键所在,如下图所示:

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



登陆过程代码

首先定义两个工具函数,一个用来获取毫秒级的时间戳,一个用来将类似于下图的返回信息转换为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-nicka标签,用正则表达式取出,具体如下图

具体代码如下:

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'<a[^>]*class=\"ibx-uc-nick\">([^<]*)</a>'
    myname = re.search(pattern, ibaidu_r.text).group(1)
    print("你的登陆用户名是:%s" % myname)

原文地址:https://www.cnblogs.com/chenqm/p/11122928.html

时间: 2024-11-01 00:57:42

python模拟百度登陆的相关文章

python模拟163登陆获取邮件列表

利用cookielib和urllib2模块模拟登陆163的例子有很多,近期看了<python模拟登陆163邮箱并获取通讯录>一文,受到启发,试着对收件箱.发件箱等进行了分析,并列出了所有邮件列表及状态,包括发件人.收件人.主题.发信时间.已读未读等状态. 1.参考代码:http://hi.baidu.com/fc_lamp/blog/item/2466d1096fcc532de8248839.html%EF%BB%BF 1 #-*- coding:UTF-8 -*- 2 import urll

python模拟浏览器登陆人人网站

想要实现网站的登陆,post方法就是提交数据到网站,所以要post数据来用python实现登陆.当你想要登陆人人时,首先要知道网站的登陆细节(先发送账号和密码,返回cookie值,发送cookie到服务器,返回页面,再使用正则提取你想要的数据),我是通过HTTPfox来抓取http数据包来分析这个网站的登陆流程.同时,我们还要分析抓到的post包的数据结构和header,要根据提交的数据结构和heander来构造自己的post数据和header. 分析结束后,我们要构造自己的HTTP数据包,并发

python模拟浏览器登陆

#! /usr/bin/env python # -*-coding:utf-8 -*- import urllib import urllib2 import cookielib class NetRobot: def __init__(self, baseurl): self.cj = cookielib.CookieJar() self.baseurl = baseurl self.opener = urllib2.build_opener(urllib2.HTTPCookieProces

python模拟浏览器登陆淘宝(设置代理、输入验证码)

终于实现了登陆淘宝,这个验证码机制困惑了我好几天啊. 代码中验证码提供有两种方式,第一种通过webbrowser的open直接在浏览器中打开含有验证码的图片,第二种就是将其以jepg格式存在 C:\\Users\\Administrator\\Desktop\\checkcode.jepg.你可以根据自己主机的用户名更改路径.同时这个代码必须先指定用户名和账号也 可以实时输入账号的密码,小小修改一下代码就可以. 显示根据httpfox分析网页数据,之后再使用正则扣除你想要的数据,将其显示出来.过

python小程序(模拟用户登陆系统)

模拟登陆1.用户输入账号密码进行登陆2.用户信息存在文件内3.用户密码输错三次后锁定用户 知识点:strip().split().while.for循环混用以及布尔值的使用 strip()  方法用于移除字符串头尾指定的字符(默认为空格) 实例1: >> str = "0000000this is string example....wow!!!0000000"; >> print str.strip( '0' ); this is string example

谈网页游戏外挂之用python模拟游戏(热血三国2)登陆

看web看多了,想写写页游的外挂,其实原理是一样的,就是端口不一样协议字段你不知道,而这也提高了点技术门槛,看我们来一点一点突破这些门槛,这次我们来用python发包模拟flash的客户端登陆. 以热血三国2为例,热血三国2是一款balabalaba自己查去吧的游戏. step1 : 在sg2.ledu.com注册个账户  略过...step2 : 登陆游戏,wireshark抓包分析    以双线784服为例,游戏页面地址http://s784.sg2.ledu.com/,现在游戏一般都是联运

python urllib2 模拟网站登陆

1. 可用浏览器先登陆,然后查看网页源码,分析登录表单 2. 使用python urllib2,cookielib 模拟网页登录 import urllib,urllib2,cookielib #urllib2 支持 http,https def loginWeb(site,user,pwd): ''' 模拟网页登陆,登陆网址,用户名,密码不能为空 登录post form 表单逻辑需要对应登录网站,可以使用火狐浏览器firebug插件查看登陆请求的网址和参数 ''' formValue={'ac

Python模拟登陆万能法-微博|知乎

Python模拟登陆让不少人伤透脑筋,今天奉上一种万能登陆方法.你无须精通HTML,甚至也无须精通Python,但却能让你成功的进行模拟登陆.本文讲的是登陆所有网站的一种方法,并不局限于微博与知乎,仅用其作为例子来讲解. 用到的库有"selenium"和"requests".通过selenium进行模拟登陆,然后将Cookies传入requests,最终用requests进行网站的抓取.优点就是不但规避了"selenium"其本身抓取速度慢的问题

Python模拟登陆万能法

此文转自:https://zhuanlan.zhihu.com/p/28587931   转录只是为了方便学习,感谢他的分享 Python模拟登陆让不少人伤透脑筋,今天奉上一种万能登陆方法.你无须精通HTML,甚至也无须精通Python,但却能让你成功的进行模拟登陆.本文讲的是登陆所有网站的一种方法,并不局限于微博与知乎,仅用其作为例子来讲解. 用到的库有"selenium"和"requests".通过selenium进行模拟登陆,然后将Cookies传入reque