python模拟登录练习(二)

花了4个晚上终于把模拟登录新浪微博学习完了,相对于知乎迷你登录,微博登录的过程确实难度大了很多,好多知识点都不懂,所以虽然把代码都码了一遍,但很多都是照猫画虎,其实还有很多地方不是十分清楚。代码中写了很多注解(对向我一样的初学者来说应该很有必要),所以看以来不是很简洁,其实源码查不到150行。

希望本文能对向我一样的初学者能起到一点借鉴作用

写以下我这几天自学的过程:
一、第一天直接看xchaoinfo的源码,完全看不懂,好不好。看了15分钟直接放弃,转百度看图文教程,还好网上的教程不算少(其实方法都一样,代码也基本没多少差别,应该起初都出自同一作者),
网上从抓包介绍,好吧又不会,那就学吧~~~
这样一天就过去了,感觉什么都没学到
二、第二天继续抓包,还是没什么进展,期间换了各种抓包工具,都不太会用,感觉网上介绍的看方法用这些抓包工具都没发抓到,这样一天快要过去的时候,想想还是用浏览器的F12吧,这样就用了火狐浏览器(因为之前一致用chrome的F12看源码,也抓不到js文件),下载了firebug,用起来还是一头雾水,晚上想想还是睡觉吧,睡觉前又百度了firebug的用法,本来也没抱希望有什么用,可是突然奇迹发生了,多次尝试了之后找到了教程中的js文件,太晚了,睡觉!!!
自学真的很痛苦,可能很简单的问题会难住好几天。
三、第三天,继续看js文件,抓post的各种属性,看着教程试着理解密码加密的方法,差不多的时候继续回去啃源码,中间碰到不会的模块google和自己用idle一点点测试,理解个大概继续往下啃,啃到一般就睡觉了。
四、第四天的继续下面的代码,后面的表单登录相对简单,因为之前有相关的学习经验,进过两个小时,终于测试成功了。
下面把源码贴出来给自己留个纪念,也给需要的书友提供一点思路。

"""
新浪微博模拟登录练习,本教程参考了很多网上的教程,很多教程的源码都差不多,本文的代码主要修改自author : "xchaoinfo" github的源码
新浪微博的模拟登录对新手来说比较困难(我就是初学者,以前没有任何编程基础,因为对现在的工作状态不满意,2017年开始自学python)


author : xcaojianhong
qq:1254798548
date:2017.02.21
"""

import time
import base64   #加密模块
import rsa  #加密模块
import binascii #二进制模块
import requests #是的,本次练习还是用的requests库,本意是学习scrapy爬虫,可是找不到模拟登录的详细的教程,只能先搁置了
import re   #正则模块,不太会用
import random   #我不是太理解为甚要rondom模块
import http.cookiejar
from PIL import Image #这个只用到简单的方法,高级的本人也不会
from urllib.parse import quote_plus #涉及编码问题,需要用到该模块


'''
如果没有开启登录保护,不用输入验证码就可以登录
如果开启登录保护,需要输入验证码,PIL库就是用了打开验证码的图片用的,就只是打开,还是需要手动输入的,不是完成自动验证
'''


# 构造 Request headers,这个不解释了,很多基础教程中都会有的,一般网站都有反爬虫的机制,最常见的就是识别是不是浏览器访问的,这个就是用来模拟浏览器的
user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
headers = {
    'User-Agent': user_agent
}

session = requests.session()    #实例化一个session类,session类能够自动处理cookies
session.cookies = http.cookiejar.LWPCookieJar(filename = 'cookies') #用于保存cookies,对爬取后需爬去有用
index_url = "http://weibo.com/login.php" #这个是微博登录的原始的url

# 访问初始页面带上 cookies
try:
    session.get(index_url,headers=headers,timeout=2)        #为什么用延时参数不太清楚,我自己写的话就只写excpet后面的一句
except:
    session.get(index_url,headers=headers)

try:
    input = raw_input #这个自行百度两个input的差异,因为我也不太清楚
except:
    pass


# 下面开始困难了,我光抓包就花了两个晚上才看懂网上讲的方法是怎么回事,期间换了很多抓包的工具,最后还是觉得firebug好用
def get_su(username):
    """
    1.输入账号,会先在js中通过encodeURIComponent进行编码,对应python的urllib.parse.quote_plus方法,问我怎么知道的,是因为源码中的注释说的
    密码的加密方法在ssologin.js文件中,为我为什么知道,网上教程说的,自己分析的话我估计2天都不一定能找到。
    在js里面有这样的代码:
    username = sinaSSOEncoder.base64.encode(urlencode(username))
    urlencode函数中用了encodeURIComponent编码,具体代码就不贴了,自己仔细看能找到。这里能看到用户名用了base64进行加密

    2.其实我也不知道怎么解释,为什么要先对username_quote进行utf-8编码,然后才base64加密,照着写就行了,我在python中测试不编码加密会报错,具体原因不清楚
    """
    username_quote = quote_plus(username)   #详细解释看1
    username_base64 = base64.b64encode(username_quote.encode('utf-8'))  #详细解释看2
    # print(username_base64.decode('utf-8')) 测试用
    return username_base64.decode('utf-8') #解码成utf-8格式字符串


# 预登陆获得 servertime, nonce, pubkey, rsakv 这些属性在后面密码加密过程中需要用到
def server_data(su):
    """
    3.通过抓包分析我们看到,https://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack
    &su=ODg4ODg4OA==&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.18)&_=1487602221124这个url的response是一个json格式的文本,其中包含
    servertime, nonce, pubkey, rsakv这些属性,这正是我们需要的,&su=ODg4ODg4OA==,这个su并不是get_su的返回值,但是相近,直接用get_su的返回值不影响
    另外这里用到了time模块,用了生成时间戳,1487602221124这个就是时间戳

    """

    #get_su()解释了那么多,就是为了获得su,虽然在这里su不那么重要(因为实际预登录url中su并不是完全正确的),但是最后的post表单中需要用到su
    pre_url = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su="\
    + su + "&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.18)&_=" + str(int(time.time() * 1000))    #为什么是这个url,详细请看3
    pre_data_res = session.get(pre_url, headers=headers)

    sever_data = eval(pre_data_res.content.decode("utf-8").replace("sinaSSOController.preloginCallBack", ''))   #这里用repalce替换
    # print(sever_data) 测试用
    return sever_data

# 这个是本次登录中最难的地方,需要用到上面的参数
def get_password(password,servertime,nonce,pubkey):
    """
    具体为什么需要这些参数,还是要仔细分析之前提到的js文件,里面有密码加密的过程
    request.servertime = me.servertime;
            request.nonce = me.nonce;
            request.pwencode = "rsa2";
            request.rsakv = me.rsakv;
            var RSAKey = new sinaSSOEncoder.RSAKey();
            RSAKey.setPublic(me.rsaPubkey, "10001");    #rsaPubkey就是pubkey,js的代码就不贴了
            password = RSAKey.encrypt([me.servertime, me.nonce].join("\t") + "\n" + password)
    """
    rsapublickey = int(pubkey,16)   #如果是16进制,则转化为10进制
    key = rsa.PublicKey(rsapublickey,65537) # '10001'转化为10进制就是65537
    message = str(servertime) + '\t' + str(nonce) + '\n' + str(password)  # 仔细对着js代码慢慢看
    message = message.encode("utf-8")
    #print(message) 测试用
    passwd = rsa.encrypt(message, key)  # 加密,为什么要用rsa,我也不知道,源代码就用的,我也不懂这个方法的具体的用途,反正看着和js的代码相似的,当成是python版本的翻译看
    #print(passwd) 测试用
    passwd = binascii.b2a_hex(passwd)  # 将加密信息转换为16进制,post需要16进制ps,猜测的,对编码不太了解。
    # print(passwd) 测试用
    return passwd

# 获得验证码,并下载后用PIL模块自动打开,没有安装的话手动去爬虫文件的目录中手动打开图片
def get_cha(pic):
    """

    我没有详细分析需要验证码的收获,因为我登录新浪微博基本没有碰到需要验证码的时候
    下面用到了随机数,我不是太理解,既然能用随机数,为什么不能用固定的数字,反正都是我们自己构造的一个数字
    """
    cha_url = "http://login.sina.com.cn/cgi/pin.php?r="
    cha_url = cha_url + str(int(random.random() * 100000000)) + "&s=0&p="
    cha_url = cha_url + pcid
    cha_page = session.get(cha_url, headers=headers)
    with open("cha.jpg", 'wb') as f:
        f.write(cha_page.content)
        f.close()
    try:
        im = Image.open("cha.jpg")
        im.show()
        im.close()
    except:
        print(u"请到当前目录下,找到验证码后输入")

def login(username,password):
    """
    激动人心的时候快要到了,上面作的一些准备工作就是为了获得post的属性
    """
    su = get_su(username)   #获得加密的su
    sever_data = server_data(su)    #获得server_data函数返回的字典
    servertime = sever_data['servertime']
    nonce = sever_data['nonce']
    rsakv = sever_data["rsakv"]
    pubkey = sever_data["pubkey"]
    showpin = sever_data["showpin"] #这个参数的值关系到是否需要输入验证码,0表示不需要,1表示需要
    password_secret = get_password(password,servertime,nonce,pubkey) #获得加密的sp
    # su,sp,servertime,nonce,rsakv,sp属性是变化的,其他的都可以写死
    postdata = {
        'entry':'weibo',
        'gateway':'1',
        'from':'',
        'savestate':'7',
        'useticket':'1',
        'pagerefer':"http://login.sina.com.cn/sso/logout.php?entry=miniblog&r=http%3A%2F%2Fweibo.com%2Flogout.php%3Fbackurl",
        'wsseretry':'servertime_error',
        'vsnf':'1',
        'su':su,
        'service':'miniblog',
        'servertime':servertime,
        'nonce':nonce,
        'pwencode':'rsa2',
        'rsakv':rsakv,
        'sp':password_secret,
        'sr':'1536*864',
        'encoding':'UTF-8',
        'prelt':'105',
        'url':'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
        'returntype':'META'
        }

    login_url = 'http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)'    #用于登录的url,psot表单提交的url
    if showpin == 0:
        login_page = session.post(login_url, data=postdata, headers=headers)
    else:
        pcid = sever_data["pcid"]
        get_cha(pcid)
        postdata['door'] = input(u"请输入验证码")
        login_page = session.post(login_url, data=postdata, headers=headers)
    login_loop = (login_page.content.decode("GBK")) #看网络抓包,知道是gbk编码
    #print(login_loop)
    pa = r'location\.replace\([\'"](.*?)[\'"]\)' #这里的正则查相关的教程
    loop_url = re.findall(pa, login_loop)[0]
    #print(loop_url)
    # 正常访问login_page就结束了,但是微博丧心病狂的还需要一部跳转,请继续往下看,我自己写的都累了,需要进一步访问login_loop这个url

    login_index = session.get(loop_url, headers=headers)
    uuid = login_index.text
    print(login_index.status_code)  #测试登录是否成功
    session.cookies.save() #保存cookies

    # ↑↑↑↑↑↑到上面其实已经完成了登录了

    response = session.get('http://weibo.com/',headers=headers)
    # print(response.text) #测试用,可以打印出来看看是否与正常登录看到的微博首页的源码一样了


    # 以下是原文作者用来登录微博个人首页获得使用者微博账号,并打印出来的代码,我没有详细解析
    uuid_pa = r'"uniqueid":"(.*?)"'
    uuid_res = re.findall(uuid_pa, uuid)[0]
    web_weibo_url = "http://weibo.com/%s/profile?topnav=1&wvr=6&is_all=1" % uuid_res
    weibo_page = session.get(web_weibo_url, headers=headers)
    weibo_pa = r'<title>(.*?)</title>'
    # print(weibo_page.content.decode("utf-8"))
    userID = re.findall(weibo_pa, weibo_page.content.decode("utf-8", 'ignore'), re.S)[0]    #不加re.S参数好像没什么不同,上文我没加
    print(u"欢迎你 %s, 你在正在使用 xcaojianhong 写的爬虫模拟登录微博" % userID)
    print(input(u'输入任何键继续'))
    print(u'好吧其实大部分代码都是参考xchaoinfo的文章')


if __name__ == "__main__":
    username = input(u'用户名:')
    password = input(u'密码:')
    login(username, password)


测试结果:

@P`MXHW5]5`%MP)~2LMWU50.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,474评论 25 707
  • 1.此文阅读较轻松,《三言两拍》以前就读过,个人感觉比罗贯中《三国演义》简单,据此制定的套餐是: 文言三成+旧小说...
    沛享人生阅读 208评论 2 1
  • 宋慧乔和宋仲基结婚了。从他们宣布婚讯到婚礼,三个月的等待,粉丝们终于等到。 半个月前,有媒体曝光宋慧乔宋仲基的婚礼...
    老金博客阅读 631评论 0 1
  • 若干年前的今天,焦急等在产房门口的年轻爸爸,直到听到了声声婴儿的啼哭声,才把悬了的心掉了下来,赶忙看看满头大汗筋疲...
    cc08阅读 351评论 0 0