天天看點

python之新浪微網誌模拟登入 一

import requests
import time
import json
import rsa
import binascii
import base64
import random
import re
from dll_call import DLLCALL
class WeiBoLogin:
    def __init__(self,username,password):
        self.username = username
        self.password = password
        self.session = requests.session()
        self.showpin = 0
        self.cookie_file = "Cookie.json"
        self.cookie=""
        self.nonce,self.pubkey,self.rsakv,self.pcid= "","","","",
        self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
        self.OCRDLL = DLLCALL("F:\hqm\wb1\login\dll_lib\OCR.dll")
        self.ip_list=[]
        self.proxy_ip= get_chroce_ip()
        self.set_cookie=''
        self.myuid=''

    def save_cookie(self):
        lens = len(self.cookie)
        if lens==0:
            self.login(self)
        with open(self.cookie_file, 'w') as f:
            json.dump(self.cookie, f)
    def load_cookie(self):
        '''
        導出cookie
        :return: Cookie
        '''
        with open(self.cookie_file,'r') as f:
            cookie = requests.utils.cookiejar_from_dict(json.load(f))
        return cookie

    def pre_login(self,usr):
        '''
        預登陸
        :return:
        '''
        su = base64.b64encode(usr.encode('utf-8')).decode()

        url = 'https://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su={}&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.19)&_={}'.format(su,int(time.time() * 1000))
        res= requests.get(url,headers = self.headers)
       # print(res.text)
        p = re.compile('preloginCallBack\((.+)\)')
        pp=p.search(res.text).group(1)
        js = json.loads(pp)
        self.nonce,self.pubkey,self.rsakv,self.pcid= js["nonce"],js["pubkey"],js["rsakv"],js["pcid"]
        self.showpin=js["showpin"]

    def sso_login(self,sp,su):
        '''
        發送加密後的使用者名和密碼
        :param sp: 加密後的密碼
        :param su: 加密後的使用者名
        :return:
        '''
        proxy = self.proxy_ip
        showpin = self.showpin
        def get_cha(pcid):
            cha_url = "http://login.sina.com.cn/cgi/pin.php?r=" + str(
                int(random.random() * 100000000)) + "&s=0&p=" + pcid
            cha_page = requests.get(cha_url,headers=self.headers)

            with open("cha.jpg", 'wb') as f:
                f.write(cha_page.content)
                f.close()
            if showpin == 1:
                img = cha_page.content
                retCode = self.OCRDLL.OCR_E(img, len(img))
                retCode = self.OCRDLL.getMsg()
                #code = input('請輸入驗證碼')
                return retCode
            return

        data ={
            'encoding':'utf-8',
            'entry': 'weibo',
            'from': '',
            'gateway': '1',
            'nonce': self.nonce,
            'pagerefer': 'https://login.sina.com.cn/crossdomain2.php?action=logout&r=https%3A%2F%2Fweibo.com%2Flogout.php%3Fbackurl%3D%252F',
            'prelt': '22',
            'pwencode': 'rsa2',
            'qrcode_flag': 'false',
            'returntype': 'META',
            'rsakv': self.rsakv,
            'savestate': '7',
            'servertime': int(time.time()),
            'service': 'miniblog',
            'sp': sp,
            'sr': '1920*1080',
            'su': su,
            'url': 'https://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
            'useticket': '1',
            'vsnf': '1'}
        url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)&_={}'.format(int(time.time() * 1000))
        if self.showpin == 0:
            resp=self.session.post(url, headers=self.headers,data=data)

        code = get_cha(self.pcid)
        data['pcid'] =self.pcid
        data['door'] = code
        resp=self.session.post(url, headers=self.headers,data=data)



    def login(self):
        '''
        模拟登陸
        :return:
        '''
        #使用者名使用base64加密
        def encode_username(usr):
            return base64.b64encode(usr.encode('utf-8'))[:-1]

        #密碼使用rsa加密
        def encode_password(code_str):
            pub_key = rsa.PublicKey(int(self.pubkey,16),65537)
            crypto = rsa.encrypt(code_str.encode('utf-8'),pub_key)
            return binascii.b2a_hex(crypto)#轉成16進制
        #擷取nonce,pubkey,rsakv
        self.pre_login(self.username)
        #加密使用者名
        su = encode_username(self.username)
        #加密密碼
        text = str(int(time.time())) + "\t" +str(self.nonce) + "\n" + str(self.password)
        sp = encode_password(text)
        #發送參數,儲存cookie
        self.sso_login(sp,su)
        cookie_dt = requests.utils.dict_from_cookiejar(self.session.cookies)
        self.cookie=cookie_dt
        self.save_cookie()
        self.session.close()
def run(username,password):
    wb = WeiBoLogin(username,password)
    wb.login()
           

1, 在送出POST請求之前, 需要GET 擷取兩個參數。

位址是:http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)

得到的資料中有 “servertime” 和 “nonce” 的值, 是随機的,其他值貌似沒什麼用。

2, 通過httpfox 觀察POST 的資料, 參數較複雜,其中 “su" 是加密後的username, “sp"是加密後的password。“servertime” 和 ”nonce” 是上一步得到的。其他參數是不變的。

username 經過了BASE64 計算: username = base64.encodestring( urllib.quote(username) )[:-1];

password 經過了三次SHA1 加密, 且其中加入了 servertime 和 nonce 的值來幹擾。

即: 兩次SHA1加密後, 将結果加上 servertime 和 nonce 的值, 再SHA1 算一次。

3. showpin是判斷是否需要驗證碼,showpin=0則不需要驗證碼,showpin=1則需要驗證碼。dll_lib是我自己的一個驗證碼識别庫。