天空宫阙 发表于 2020-2-13 22:02

新浪微博模拟登录 支持手动处理验证码

本帖最后由 天空宫阙 于 2020-2-13 22:05 编辑

介绍对于爬取少量的微博信息自己手动登录再copy一下cookie是最简单的方式而对于大规模的爬取,需要大量账号的登录,手动登录费时费力,模拟登录就有它的重要意义一般的做法是大量账号的模拟登录并保存cookie形成cookie池,提供爬虫使用

代码参考https://github.com/CharlesPikachu/DecryptLogin/blob/master/DecryptLogin/platforms/weibo.py通过新浪通行证的登录来登录微博https://login.sina.com.cn/signup/signin.php
登录过程1.预登录,向prelogin_url(https://login.sina.com.cn/sso/prelogin.php)发起get请求得到rsa加密的参数    该请求的核心参数    su为用户名的base64加密    _   时间戳 python模拟 str(int(time.time()*1000))    其他entry,rsakt,client为不变参数
2.登录,向ssologin_url(https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19))发起post请求登录    改请求核心参数    su 为用户名的base64加密    servertime 预登录返回    nonce 预登录返回    rsakv 预登录返回    sp servertime + '\t' +nonce +'\n'+ password 这一串字符(如图)的rsa加密      rsa加密的modules是与请求返回的pubkey,exponent是"10001"(二进制),用PKCS1_v1_5方式填充      rsa的加密可以用 python的RSA库模拟 也可用pycryptodome库模拟,选择PKCS1_v1_5即可

3.请求login_url(https://passport.weibo.com/wbsso/login)    需要携带的核心参数ticket, ssosavestate,均为post请求的返回值
完整代码"""
参考https://github.com/CharlesPikachu/DecryptLogin/blob/master/DecryptLogin/platforms/weibo.py
"""
import requests
import base64
import time
import random
# rsa用的是PKCS1_v1_5填充
import rsa
import re
import json
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Cipher import PKCS1_v1_5
from binascii import b2a_hex
from PIL import Image
import warnings
# 过滤警告信息
warnings.filterwarnings('ignore')

class weibo:
    def __init__(self):
      self.session = requests.Session()
      self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
      }
      self.prelogin_url = 'https://login.sina.com.cn/sso/prelogin.php'
      self.ssologin_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)'
      self.pin_url = 'https://login.sina.com.cn/cgi/pin.php'
      self.login_url = 'https://passport.weibo.com/wbsso/login?'
      self.home_url = 'https://weibo.com/u/%s/home'

    def get_prelogin_info(self,username,password):
      """ 请求prelogin_url得到RSA加密的参数 """
      su = base64.b64encode(username.encode())
      su = str(su,'utf-8')
      params = {
            'entry': 'account',
            # 'callback': 'sinaSSOController.preloginCallBack',
            'su': su,
            'rsakt': 'mod',
            'client': 'ssologin.js(v1.4.15)',
            '_': str(int(time.time()*1000))
      }
      # verify=False 不加也可以返回数据
      res = self.session.get(self.prelogin_url, params=params, verify=False)
      return res.json()

    def get_pin(self):
      """ 保存验证码图片 """
      r = int(random.random()*100000000)
      params = {
                        'r': str(r),
                        's': '0',
                }
      response = self.session.get(self.pin_url,params=params)
      if response.status_code ==200:
            with open('pin_img.png','wb') as f:
                f.write(response.content)
                f.close()
                print('had saved Captcha.')
            # Image好像会调用默认的图片查看器打开图片
            I = Image.open('pin_img.png')
            I.show()
            Captcha_value = input('enter the Captcha value:')
            return Captcha_value

    def post_login_data(self,username,password,Captcha_value=None):
      """ post请求登录 """
      p = self.get_prelogin_info(username,password)
      
      # 用不同的库实现RSA加密 都可行
      """ RSA库实现 """
      # publickey = rsa.PublicKey(int(p['pubkey'], 16), int('10001', 16))
      # sp = rsa.encrypt((str(p['servertime'])+'\t'+p['nonce']+'\n'+password).encode(), publickey)
      
      """ 用pycryptodome库实现 """
      rsa_public_key = RSA.construct((int(p['pubkey'],16),int('10001',16)))
      cipher_rsa = PKCS1_v1_5.new(rsa_public_key)
      sp2 = cipher_rsa.encrypt((str(p['servertime'])+'\t'+p['nonce']+'\n'+password).encode())
      # 返回的二进制数据的十六进制表示
      sp = b2a_hex(sp2)
      data_post = {
            'entry': 'account',
            'gateway': '1',
            'from': '',
            'savestate': '30',
            'useticket': '0',
            'pagerefer': '',
            'vsnf': '1',
            'su': base64.b64encode(username.encode()),
            'service': 'account',
            'servertime': str(int(p['servertime'])+random.randint(1, 20)),
            'nonce':p['nonce'],
            'pwencode': 'rsa2',
            'rsakv': p['rsakv'],
            'sp': sp,
            'sr': '1366*768',
            'encoding': 'UTF-8',
            'cdult': '3',
            'domain': 'sina.com.cn',
            'prelt': '95',
            'returntype': 'TEXT',
      }
      if Captcha_value:
            data_post['door'] = Captcha_value
      res = self.session.post(self.ssologin_url, data=data_post,allow_redirects=False, verify=False)
      if res.status_code==200:
            return res.json()
   
    def check_at_login_url(self,res,username):
      ticket, ssosavestate = re.findall(r'ticket=(.*?)&ssosavestate=(.*?)"', res)
      # 请求login_url
      params = {
                  'ticket': ticket,
                  'ssosavestate': str(ssosavestate),
                  'callback': 'sinaSSOController.doCrossDomainCallBack',
                  'scriptId': 'ssoscript0',
                  'client': 'ssologin.js(v1.4.19)',
                  '_': str(int(time.time() * 1000))
                }
      params = '&'.join(['%s=%s' % (key, value) for key, value in params.items()])
      res = self.session.get(self.login_url+params, verify=False)
      uid = re.findall(r'"uniqueid":"(.*?)"', res.text)
      res = self.session.get(self.home_url % uid, verify=False)
      if '我的首页' in res.text:
            print(': Account -> %s, login successfully...' % username)
            infos_return = {'username': username}
            return infos_return, self.session

   
    def login(self,username,password):
      res = self.post_login_data(username,password)
      while True:
            if res['retcode']=='0':
                infos_return,login_session = self.check_at_login_url(json.dumps(res),username)
                if login_session:
                  return login_session
                break
            elif res['retcode']=='101':
                # 用户名或密码不正确
                print(res['reason'])
                break
            elif res['retcode']=='4049':
                # 需要验证码
                print(res['reason'])
                res = self.post_login_data(username,password,self.get_pin())
            elif res['retcode']=='2070':
                # 验证码错误
                print(res['reason'])
                res = self.post_login_data(username,password,self.get_pin())
            else:
                print(res)
                break
      


if __name__ == "__main__":
    t = weibo()
    # t.login('用户名','密码')
    login_session = t.login('','')
    # print(login_session.cookies)
   
py文件下载

https://www.lanzouj.com/i9bq9yj
效果示例



有验证码的情况这个例子中是手动输入的其他方法是接入打码平台,或者cnn(卷积神经网络)训练模型识别(这是人工智能中计算机视觉的内容,还不会)
如果觉得还可以免费评分鼓励一下!

Zeaf 发表于 2020-2-13 23:30

学习了,感谢!

天空宫阙 发表于 2020-2-14 13:18

最近几篇忘记转播了

新征程 发表于 2020-4-27 11:26

感谢楼主分享,先收藏,具体情况使用再评价

fuxian 发表于 2020-5-22 15:23

你好,请问现在怎么得出微博等级信息{:1_919:}

清晨呀 发表于 2020-7-31 17:20

本帖最后由 清晨呀 于 2020-8-6 17:18 编辑

感谢大佬分享,代码很实用

doanthan 发表于 2020-12-31 16:18

楼主有心了,可惜的是通过新浪通行证跳转的方法基本都被河蟹了,都需要扫码或者私信短信验证,今年被封了大批接口。我艰难找到一个能跳验证的,不知道能用多久。

MOEYU_VANILLA 发表于 2020-12-31 21:14

感谢分享

a3851458 发表于 2021-4-18 18:16

大佬现在有可以直接登入APP的吗微博 不要手机验证码的 有吗

zhaochon 发表于 2021-5-23 17:04

页: [1]
查看完整版本: 新浪微博模拟登录 支持手动处理验证码