python爬虫:登录百度账户,并上传文件到百度云盘

login.js文件:

/**
 * Created by resolvewang on 2017/4/15.
 */
function getGid() {
    return "xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (e) {
        var t = 16 * Math.random() | 0, n = "x" == e ? t : 3 & t | 8;
        return n.toString(16)
    }).toUpperCase()
}

function  getCallback() {
    return "bd__cbs__" + Math.floor(2147483648 * Math.random()).toString(36)
}

Pyhton实现代码:

#-*- coding:utf-8 -*-
__author__ = ‘Administrator‘

import time
import json
import re
import requests
import execjs
import base64
from urllib.parse import urlencode
from requests_toolbelt import MultipartEncoder
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
from hashlib import md5
from zlib import crc32

try:
    requests.packages.urllib3.disable_warnings()
except:
    pass

headers = {‘User-Agent‘: ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 ‘
                         ‘(KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36‘,
           }

# 全局的session
session = requests.session()
session.get(‘https://pan.baidu.com‘, headers=headers)

class BufferReader(MultipartEncoder):
    """将multipart-formdata转化为stream形式的Proxy类
    """

    def __init__(self, fields, boundary=None, callback=None, cb_args=(), cb_kwargs=None):
        self._callback = callback
        self._progress = 0
        self._cb_args = cb_args
        self._cb_kwargs = cb_kwargs or {}
        super(BufferReader, self).__init__(fields, boundary)

    def read(self, size=None):
        chunk = super(BufferReader, self).read(size)
        self._progress += int(len(chunk))
        self._cb_kwargs.update({
            ‘size‘: self._len,
            ‘progress‘: self._progress
        })
        if self._callback:
            try:
                self._callback(*self._cb_args, **self._cb_kwargs)
            except:  # catches exception from the callback
                # raise CancelledError(‘The upload was cancelled.‘)
                pass
        return chunk

def _get_runntime():
    """
    :param path: 加密js的路径,注意js中不要使用中文!估计是pyexecjs处理中文还有一些问题
    :return: 编译后的js环境,不清楚pyexecjs这个库的用法的请在github上查看相关文档
    """
    phantom = execjs.get()  # 这里必须为phantomjs设置环境变量,否则可以写phantomjs的具体路径
    with open(‘login.js‘, ‘r‘) as f:
        source = f.read()
    return phantom.compile(source)

def get_gid():
    return _get_runntime().call(‘getGid‘)

def get_callback():
    return _get_runntime().call(‘getCallback‘)

def _get_curtime():
    return int(time.time()*1000)

# 抓包也不是百分百可靠啊,这里?getapi一定要挨着https://passport.baidu.com/v2/api/写,才会到正确的路由
def get_token(gid, callback):
    cur_time = _get_curtime()
    get_data = {
        ‘tpl‘: ‘netdisk‘,
        ‘subpro‘: ‘netdisk_web‘,
        ‘apiver‘: ‘v3‘,
        ‘tt‘: cur_time,
        ‘class‘: ‘login‘,
        ‘gid‘: gid,
        ‘logintype‘: ‘basicLogin‘,
        ‘callback‘: callback
    }
    headers.update(dict(Referer=‘http://pan.baidu.com/‘, Accept=‘*/*‘, Connection=‘keep-alive‘, Host=‘passport.baidu.com‘))
    resp = session.get(url=‘https://passport.baidu.com/v2/api/?getapi‘, params=get_data, headers=headers)
    if resp.status_code == 200 and callback in resp.text:
        # 如果json字符串中带有单引号,会解析出错,只有统一成双引号才可以正确的解析
        #data = eval(re.search(r‘.*?\((.*)\)‘, resp.text).group(1))
        data = json.loads(re.search(r‘.*?\((.*)\)‘, resp.text).group(1).replace("‘", ‘"‘))
        return data.get(‘data‘).get(‘token‘)
    else:
        print(‘获取token失败‘)
        return None

def get_rsa_key(token, gid, callback):
    cur_time = _get_curtime()
    get_data = {
        ‘token‘: token,
        ‘tpl‘: ‘netdisk‘,
        ‘subpro‘: ‘netdisk_web‘,
        ‘apiver‘: ‘v3‘,
        ‘tt‘: cur_time,
        ‘gid‘: gid,
        ‘callback‘: callback,
    }
    resp = session.get(url=‘https://passport.baidu.com/v2/getpublickey‘, headers=headers, params=get_data)
    if resp.status_code == 200 and callback in resp.text:
        data = json.loads(re.search(r‘.*?\((.*)\)‘, resp.text).group(1).replace("‘", ‘"‘))
        return data.get(‘pubkey‘), data.get(‘key‘)
    else:
        print(‘获取rsa key失败‘)
        return None

def encript_password(password, pubkey):
    """
    import rsa
    使用rsa库加密(法一)
    pub = rsa.PublicKey.load_pkcs1_openssl_pem(pubkey.encode(‘utf-8‘))
    encript_passwd = rsa.encrypt(password.encode(‘utf-8‘), pub)
    return base64.b64encode(encript_passwd).decode(‘utf-8‘)

    """
    # pubkey必须为bytes类型
    pub=RSA.importKey(pubkey.encode(‘utf-8‘))
    #构造“加密器”
    encryptor=PKCS1_v1_5.new(pub)
    #加密的内容必须为bytes类型
    encript_passwd =encryptor.encrypt(password.encode(‘utf-8‘))
    return base64.b64encode(encript_passwd).decode(‘utf-8‘)

def login(token, gid, callback, rsakey, username, password):
    post_data = {
        ‘staticpage‘: ‘http://pan.baidu.com/res/static/thirdparty/pass_v3_jump.html‘,
        ‘charset‘: ‘utf-8‘,
        ‘token‘: token,
        ‘tpl‘: ‘netdisk‘,
        ‘subpro‘: ‘netdisk_web‘,
        ‘apiver‘: ‘v3‘,
        ‘tt‘: _get_curtime(),
        ‘codestring‘: ‘‘,
        ‘safeflg‘: 0,
        ‘u‘: ‘http://pan.baidu.com/disk/home‘,
        ‘isPhone‘: ‘‘,
        ‘detect‘: 1,
        ‘gid‘: gid,
        ‘quick_user‘: 0,
        ‘logintype‘: ‘basicLogin‘,
        ‘logLoginType‘: ‘pc_loginBasic‘,
        ‘idc‘: ‘‘,
        ‘loginmerge‘: ‘true‘,
        ‘foreignusername‘: ‘‘,
        ‘username‘: username,
        ‘password‘: password,
        ‘mem_pass‘: ‘on‘,
        # 返回的key
        ‘rsakey‘: rsakey,
        ‘crypttype‘: 12,
        ‘ppui_logintime‘: 33554,
        ‘countrycode‘: ‘‘,
        ‘callback‘: ‘parent.‘+callback
    }
    resp = session.post(url=‘https://passport.baidu.com/v2/api/?login‘, data=post_data, headers=headers)
    if ‘err_no=0‘ in resp.text:
        print(‘登录成功‘)
    else:
        print(‘登录失败‘)

def upload(dest_path,file_handle,token):
     params = {
            ‘method‘: ‘upload‘,
            ‘app_id‘: "250528",
            ‘BDUSS‘: session.cookies[‘BDUSS‘],
            ‘t‘: str(int(time.time())),
            ‘bdstoken‘: token,
            ‘path‘: dest_path,
            ‘ondup‘: "newcopy"
        }
     # print(params)
     files = {‘file‘: (str(int(time.time())), file_handle)}
     url = ‘https://{0}/rest/2.0/pcs/file‘.format(‘pcs.baidu.com‘)
     api = ‘%s?%s‘ % (url, urlencode(params))
     # print(api)
     body = BufferReader(files)
     # print(body)
     baibupan_header = {"Referer": "http://pan.baidu.com/disk/home",
                    "User-Agent": "netdisk;4.6.2.0;PC;PC-Windows;10.0.10240;WindowsBaiduYunGuanJia"}
     header = dict(baibupan_header.items())
     # print(headers)
     header.update({"Content-Type": body.content_type})
     response = session.post(api, data=body, verify=False, headers=header)
     return response

def rapidupload(dest_path,file_handler,token):
    """秒传一个文件
    :param file_handler: 文件handler, e.g. open(‘file‘,‘rb‘)
    :type file_handler: file

    :param dest_path: 上传到服务器的路径,包含文件名
    :type dest_path: str

    :return: requests.Response
        .. note::
            * 文件已在服务器上存在,不上传,返回示例
            {
                "path" : "/apps/album/1.jpg",
                "size" : 372121,
                "ctime" : 1234567890,
                "mtime" : 1234567890,
                "md5" : "cb123afcc12453543ef",
                "fs_id" : 12345,
                "isdir" : 0,
                "request_id" : 12314124
            }
            * 文件不存在,需要上传
            {"errno":404,"info":[],"request_id":XXX}
            * 文件大小不足 256kb (slice-md5 == content-md5) 时
            {"errno":2,"info":[],"request_id":XXX}
            * 远程文件已存在
            {"errno":-8,"info":[],"request_id":XXX}
    """

    file_handler.seek(0, 2)
    _BLOCK_SIZE = 2 ** 20
    content_length = file_handler.tell()
    file_handler.seek(0)

    # 校验段为前 256KB
    first_256bytes = file_handler.read(256 * 1024)
    slice_md5 = md5(first_256bytes).hexdigest()

    content_crc32 = crc32(first_256bytes).conjugate()
    content_md5 = md5(first_256bytes)

    while True:
        block = file_handler.read(_BLOCK_SIZE)
        if not block:
            break
        # 更新crc32和md5校验值
        content_crc32 = crc32(block, content_crc32).conjugate()
        content_md5.update(block)

    params = {
            ‘method‘: ‘rapidupload‘,
            ‘app_id‘: "250528",
            ‘BDUSS‘: session.cookies[‘BDUSS‘],
            ‘t‘: str(int(time.time())),
            ‘bdstoken‘: token,
            ‘path‘: dest_path,
            ‘ondup‘: "newcopy"
            }

    data = {
            ‘content-length‘: content_length,
            ‘content-md5‘: content_md5.hexdigest(),
            ‘slice-md5‘: slice_md5,
            ‘content-crc32‘: ‘%d‘ % (content_crc32.conjugate() & 0xFFFFFFFF)
            }
    baibupan_header = {"Referer": "http://pan.baidu.com/disk/home",
                    "User-Agent": "netdisk;4.6.2.0;PC;PC-Windows;10.0.10240;WindowsBaiduYunGuanJia"}
    header = dict(baibupan_header.items())
    url = ‘https://{0}/rest/2.0/pcs/file‘.format(‘pcs.baidu.com‘)
    api = ‘%s?%s‘ % (url, urlencode(params))
    # print(api)
    response= session.post(api, data=data, verify=False,headers=header)
    return response

if __name__ == ‘__main__‘:
    user=‘xxx‘  #用户名
    password=‘xxx‘  #密码

    cur_gid = get_gid()
    cur_callback = get_callback()
    cur_token = get_token(cur_gid, cur_callback)
    # print("token:%s" %(cur_token))
    cur_pubkey, cur_key = get_rsa_key(cur_token, cur_gid, cur_callback)
    encript_password = encript_password(password, cur_pubkey)
    login(cur_token, cur_gid, cur_callback, cur_key, user, encript_password)
    # print("cookies:%s" %(session.cookies[‘BDUSS‘]))

    # res=upload("/hello/temp.txt",open("temp.txt",‘rb‘),cur_token)
    # print(res.content.decode(‘utf-8‘))
    res=rapidupload("/hello/words.txt",open("words.txt",‘rb‘),cur_token)
    print(res.content.decode(‘utf-8‘))
时间: 2024-08-03 07:24:23

python爬虫:登录百度账户,并上传文件到百度云盘的相关文章

Python脚本远程Linux创建目录、上传文件

最近这段时间,经常通过xftp在服务器上创建目录并上传文件,繁琐的事一直循环的做,因此一直在想通过Python脚本能自动创建目录,上传文件,询问公司大佬和百度终于找到了方法,接下来看看. 一. 说明 主要安装两个模块paramiko与scp,功能即可实现 paramiko是一个基于SSH用于连接远程服务器并执行相关操作(SSHClient和SFTPClinet,即一个是远程连接,一个是上传下载服务),使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远

Jmeter_针对一个账户批量上传文件

之前分享了上传一个文件,批量上传多个文件,把文件名字,大小,路径参数化,实现即可 操作如下: 举例上传2个文件 1.创建文件 2.线程组,因为是2个文件上传,要运行2次 3. HTTP请求值 4.因为登录只需要运行一次就够了,添加一个 仅一次控制器 5.登录按照需求文档添加信息头 6.使用正则表达式获取token 7.上传文件-Http请求,fileName,fileSize参数化 8.HTTP请求头,需求文档要求上传文件添加信息头 9.上传文件 10,查看结果树 原文地址:https://ww

Python+Selenium学习笔记10 - send_keys上传文件

在火狐浏览器上传文件 上传前,同一个HTML文件在火狐和Edge浏览器显示有些不同 这是Firefox浏览器的显示 这是Edge浏览器 上传后 1 # coding = utf-8 2 3 from selenium import webdriver 4 import os 5 import time 6 7 dr = webdriver.Firefox() 8 file_path = "file:///" + os.path.abspath('upfile.html') 9 dr.g

利用百度云盘API上传文件至百度云盘

一.获取Access Token示例 1. 请您将以下HTTP请求直接粘贴到浏览器地址栏内,并按下回车键. https://openapi.baidu.com/oauth/2.0/authorize?response_type=token&client_id=L6g70tBRRIXLsY0Z3HwKqlRE&redirect_uri=oob&scope=netdisk 2.执行后,弹出百度登录页面,登录后弹出以下授权页面: 3.授权后,将跳转到以下百度OAuth2.0页面: 4.请

百度 UEditor--自定义上传文件路径及读取文件

jsp中替换掉上传和预览图片的URL 注意第一句判断,注意要用项目的相对URL return '/sirdifoa/kentra/file/uploadImage.do'; if(UE.Editor.prototype._bkGetActionUrl == undefined)UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;     UE.Editor.prototype.getActionUrl = 

用shell和python实现FTP自动登陆然后上传和下载

1.ftp自动登陆下载文件 -n 不受.netrc文件的影响.(ftp默认为读取.netrc文件中的设定) !是即时文件的标志它必须成对出现,以标识即时文件的开始和结尾 binary -   设置文件传输类型为binary(二进制传输)  prompt -  开关交互提示(默认为ON) close -   结束FTP会话并返回命令行 quit -  结束FTP会话并退出FTP(功能通bye) mget -  复制一个或多个远程文件至本地 get -   复制单个远程文件到本地 put -  复制

利用paramiko模块批量登录(执行命令/上传文件)

工作中由于服务器主机很多,如果手动的一台一台去添加ssh认证,效率太低了,而此脚本正是为了解决此问题 此脚本的实现的功能: 1.实现了(密码.ssh认证)单一主机登录和批量主机登录 2.实现了(密码.ssh认证)单一主机上传文件和批量主机上传文件(下载文件的原理和此一样) 3.主机批量添加ssh认证(这才是我的主要目的) 脚本的不足: 1.只能循环主机名 2.所有的主机的账号和密码都是一样的,不够灵活 有需求的朋友可以修改下代码,可以把主机.账号密码存放在一个文件中,循环读取文件 下面贴上代码吧

python实例编写(3)--对话框,多窗口,下拉框,上传文件

一.对话框: 例:点击百度的登录,弹出的小窗口 #coding=utf-8 from selenium import webdriver from time import sleep dr=webdriver.Chrome() dr.get("http://www.baidu.com") #一定要记得设置等待时间,要不然定位不到!!! dr.find_element_by_link_text("登录").click() sleep(3) #思路:二次定位,点击登录后

selenium+python自动化78-autoit参数化与批量上传【转载】

转至博客:上海-悠悠 前言前一篇autoit实现文件上传打包成.exe可执行文件后,每次只能传固定的那个图片,我们实际测试时候希望传不同的图片.这样每次调用的时候,在命令行里面加一个文件路径的参数就行. 一.命令行参数 1.参数化传入的参数,可以通过autoit的命令行参数: ```    myProg.exe param1 "This is a string parameter" 99``` 在脚本中,可用以下变量获取命令行参数: ```$CmdLine[0] ; = 3$CmdLi