Python3實現百度雲盤資源自動轉存

Python3百度雲盤資源自動轉存

Python3實現百度雲盤資源自動轉存,解決帶有密碼的分享鏈接自動轉存,不含密碼的資源自動轉存,同時實現post請求轉存以及selenium轉存

前言

最近看上了一個免費的動漫網站,資源一出更得巨快,而且有很多的網盤資源,於是想…

於是寫了一段代碼,爬取了網站的全部資源

然後就該一個個的保存到我的雲盤中了,問題是手動的話1900多個得累死人,所以就打算通過Python來做

一開始的想法是拿selenium來操作,但是又好奇有沒有通過普通的爬蟲思路來做這件事,於是下面把摸索的過程也加上了

分析&代碼

分析目標,通過從數據庫取出的資源鏈接以及密碼,構造併發送請求,然後可以進入資源的保存頁面,再通過selenium來點擊操作

首先網盤帶密碼的提取鏈接是這樣的
https://pan.baidu.com/share/init?surl=xxx

而不需要密碼可以直接提取資源的鏈接是這樣的
https://pan.baidu.com/s/1xxx

跟輸入密碼後跳轉的提取頁面差不多,注意,以上兩個xxx的內容一致,有個1是從web端訪問的固有參數,後面會提到

我們在輸入密碼後就可以進去,那麼關鍵就是提交密碼的過程是怎樣的,按照常理按f12打開開發者工具,在輸入密碼的頁面輸入密碼後,點擊提取文件

這裏有一定可能你會出現404找不到資源的頁面,當然你可以用fiddler抓包就肯定可以抓到

我們找到關鍵的請求

這個post請求在發送時帶上了一系列的參數,以及密碼

下面的就是跳轉的資源頁面,而這個是一個get請求,沒有帶上其他的參數,但是你單拿出來直接去訪問的話(從沒有輸過密碼的時候),會直接被跳轉到輸入密碼的頁面,那麼問題來了,爲什麼會這樣

有經驗的能比較準的猜測可能是這兩個請求的cookie中有差異,因爲邏輯上我輸入密碼後的post請求會返回一個參數,而這個參數既沒有體現在第二個請求的url上,也沒有可以攜帶的formdata,所以可能是在cookie中存在差異

事實證明兩個請求的cookie確實有不同,關鍵在於 https://pan.baidu.com/s/1xxx
的cookie中的BDCLND正好是 https://pan.baidu.com/share/verify?surl=5RdjtVK55eEuayvz82cDmg&t=1579432835477&channel=chunlei&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d&logid=MTU3OTQzMjgzNTQ3OTAuNjM2MDg4OTgzOTY3MzU0OQ==&clienttype=0 返回的參數中的一個值,如圖:

https://pan.baidu.com/s/1xxx

post請求的返回參數,f12工具可能看不到,fiddler抓包可以

也就是說我們要取得這個參數後再訪問 https://pan.baidu.com/s/1xxx 時帶上這個cookie纔可以不被返回到輸入密碼的頁面

那接下來就是如何獲取這個參數的問題,我長話短說

對比分析多個post鏈接可以知道,鏈接中
https://pan.baidu.com/share/verify?surl=5RdjtVK55eEuayvz82cDmg&t=1579432835477&channel=chunlei&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d&logid=MTU3OTQzMjgzNTQ3OTAuNjM2MDg4OTgzOTY3MzU0OQ==&clienttype=0

參數 狀態
surl 5RdjtVK55eEuayvz82cDmg 相當於資源的ID,已知
t 1579432835477 13位時間戳
channel chunlei 反正是固定的(春雷?)
web 1 固定,也就是前面提到過的
app_id 250528 固定
bdstoken 08a7da93cf25d7935788a123e3e10c3d 固定
logid MTU3OTQzMjgzNTQ3OTAuNjM2MDg4OTgzOTY3MzU0OQ== 變化
clienttype 0 固定

就只有logid是改變的,然後我找了找,應該是在js中產生的,最後在這裏
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-s0RP42Yw-1579682702660)(http://image.joelyings.com/2020-01-20_10.png)]

找到了這段js生成代碼具體如下:

    var u = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/~!@#¥%……&"
      , l = String.fromCharCode
      , d = function(e) {
        if (e.length < 2) {
            var n = e.charCodeAt(0);
            return 128 > n ? e : 2048 > n ? l(192 | n >>> 6) + l(128 | 63 & n) : l(224 | n >>> 12 & 15) + l(128 | n >>> 6 & 63) + l(128 | 63 & n)
        }
        var n = 65536 + 1024 * (e.charCodeAt(0) - 55296) + (e.charCodeAt(1) - 56320);
        return l(240 | n >>> 18 & 7) + l(128 | n >>> 12 & 63) + l(128 | n >>> 6 & 63) + l(128 | 63 & n)
    }
      , f = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g
      , g = function(e) {
        return (e + "" + Math.random()).replace(f, d)
    }
      , h = function(e) {
        var n = [0, 2, 1][e.length % 3]
          , t = e.charCodeAt(0) << 16 | (e.length > 1 ? e.charCodeAt(1) : 0) << 8 | (e.length > 2 ? e.charCodeAt(2) : 0)
          , o = [u.charAt(t >>> 18), u.charAt(t >>> 12 & 63), n >= 2 ? "=" : u.charAt(t >>> 6 & 63), n >= 1 ? "=" : u.charAt(63 & t)];
        return o.join("")
    }
      , m = function(e) {
        return e.replace(/[\s\S]{1,3}/g, h)
    }
      , p = function() {
        return m(g((new Date).getTime()))
    }
      , w = function(e, n) {
        return n ? p(String(e)).replace(/[+\/]/g, function(e) {
            return "+" == e ? "-" : "_"
        }).replace(/=/g, "") : p(String(e))
    };
    !function() {
        r(document).ajaxSend(function(e, n, t) {
            var i = w(s.getCookie("BAIDUID"));
           ...
        })
    }(),

主要是這段內容,通過一系列的方法來生成logid,由於比較複雜,所以決定通過第三方庫execjs來調用,把這一段js稍加調整

var u = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/~!@#¥%……&",
l = String.fromCharCode,
d = function(e) {
    if (e.length < 2) {
        var n = e.charCodeAt(0);
        return 128 > n ? e : 2048 > n ? l(192 | n >>> 6) + l(128 | 63 & n) : l(224 | n >>> 12 & 15) + l(128 | n >>> 6 & 63) + l(128 | 63 & n)
    }
    var n = 65536 + 1024 * (e.charCodeAt(0) - 55296) + (e.charCodeAt(1) - 56320);
    return l(240 | n >>> 18 & 7) + l(128 | n >>> 12 & 63) + l(128 | n >>> 6 & 63) + l(128 | 63 & n)
},
f = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,
g = function(e) {
    return (e + "" + Math.random()).replace(f, d)
},
h = function(e) {
    var n = [0, 2, 1][e.length % 3],
        t = e.charCodeAt(0) << 16 | (e.length > 1 ? e.charCodeAt(1) : 0) << 8 | (e.length > 2 ? e.charCodeAt(2) : 0),
        o = [u.charAt(t >>> 18), u.charAt(t >>> 12 & 63), n >= 2 ? "=" : u.charAt(t >>> 6 & 63), n >= 1 ? "=" : u.charAt(63 & t)];
    return o.join("")
},
m = function(e) {
    return e.replace(/[\s\S]{1,3}/g, h)
},
p = function() {
    return m(g((new Date).getTime()))
},
w = function(e, n) {
        return n ? p(String(e)).replace(/[+\/]/g, function(e) {
            return "+" == e ? "-" : "_"
        }).replace(/=/g, "") : p(String(e))
    };

function getLogId(data){
        var logid = w(data);
        return logid;
}

然後我們調用的時候,輸入BAIDUID即可,這個可以在最早的輸入密碼頁面的cookie中取得

安裝execjs 注意,你沒看錯,命令就是輸的pyexecjs

pip install pyexecjs

因爲Node.js 是Javascript語言服務器端運行環境,所以你還需要安裝nodejs

安裝好的情況下在Python3環境下你可以看到

Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import execjs
>>> execjs.get().name
'Node.js (V8)'

然後來調用

    # 讀入修改好的js代碼文件
    def get_logid(self, baidu_id):
        with open('boot.js', encoding='utf-8') as f:
            bootjs = f.read()
        # 編譯js代碼
        js_obj = execjs.compile(bootjs)
        # 調用getLogId方法,給參數baidu_id,也就是BAIDUID,然後得到輸出
        res = js_obj.call('getLogId', baidu_id)
        return res

這是測試發送請求的代碼

    def __init__(self):
        # 從數據庫中取資源鏈接及密碼後存放的列表
        self.row_lists = []
        # 帶上密碼請求的需要format的鏈接
        self.pan_post = 'https://pan.baidu.com/share/verify?surl={}&t={}&channel=chunlei' \
                        '&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d' \
                        '&logid={}&clienttype=0'
        # 13位的時間戳
        self.t = int(round(time.time() * 1000))
        # 自己弄得隨機ua
        self.user_agent = FaUa.get_ua()

    def get_logid(self, baidu_id):
        with open('boot.js', encoding='utf-8') as f:
            bootjs = f.read()
        js_obj = execjs.compile(bootjs)
        res = js_obj.call('getLogId', baidu_id)
        return res

    def test(self):
        # 保持會話
        session = requests.session()
        # 需要提取的資源鏈接
        s_url = 'https://pan.baidu.com/share/init?surl=5RdjtVK55eEuayvz82cDmg'
        # verify=False 可以一定程度上避免多次訪問導致對方服務器封你,但是會出現警告,這是還需在前面加上加一條requests.packages.urllib3.disable_warnings(),即禁用安全請求警告
        r_bid = session.get(s_url, headers={'user-agent': self.user_agent}, verify=False)
        # 拿到cookie中的BAIDUID
        baiduid = r_bid.cookies['BAIDUID']
        # 根據BAIDUID得到返回的logid
        logid = self.get_logid(baiduid)
        # 獲取資源的鏈接後一部分ID
        surl = s_url.split('surl=')[1]
        # post請求的參數,帶上密碼,後兩個爲空
        data = {
            'pwd': 'xxx',
            'vcode': '',
            'vcode_str': '',
        }
        # 請求頭
        headers = {
            'user-agent':self.user_agent,
            'Referer': 'https://pan.baidu.com/share/init?surl=5RdjtVK55eEuayvz82cDmg',
            'Accept':'*/*',
            'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With':'XMLHttpRequest',
            'Accept-Language':'zh-CN',
            'Accept-Encoding':'gzip, deflate',
            'Host':'pan.baidu.com',
            'DNT':'1',
            'Connection': 'Keep-Alive',
            'Cache-Control': 'no-cache',
        }
        # 發送post請求
        r = session.post(self.pan_post.format(surl, self.t, logid), data=data, headers=headers, verify=False)
        print(r.url, r.text)
        # 得到返回的BDCLND ,在下一個請求的cookie中帶上
        BDCLND = r.json()['randsk']
        headers['Cookie'] = 'BDCLND=' + BDCLND
        print(headers)
        r2 = session.get('https://pan.baidu.com/s/15RdjtVK55eEuayvz82cDmg', headers=headers, verify=False)
        r2.encoding = 'utf-8'
        print(r2.text)

這是返回的頁面結果

<!DOCTYPE html>
<html>
<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=7,9,10,11" />
<meta name="renderer" content="webkit">
<script src="/sns/box-static/disk-share/js/share.dp.js?t=1578364180271"></script>
<link rel="shortcut icon" href="/res/static/images/favicon.ico"/>
<script src="/sns/box-static/disk-share/js/mod.js?t=1578364180271"></script>
<link rel="stylesheet" type="text/css" href="/box-static/consult/base.css"/>
<link rel="stylesheet" type="text/css" href="/box-static/consult/system-core.css"/>
<script src="/box-static/consult/base.js"></script>
<script src="/box-static/consult/system-core.js"></script>

<link rel="stylesheet" type="text/css" href="/box-static/consult/function.css"/>
...
<div class="slide-show-left">
<h2 class="file-name" title="文件名">
<em class="global-icon-16"></em>文件名</h2>
</div>
<div class="slide-show-right">
<span class="slide-header-funcs">
</span>
<div class="module-share-top-bar g-clearfix">
<div class="bar"></div>
</div>
</div>
<div class="cb"></div>
<div class="slide-show-other-infos">
<div class="share-file-info">
<span>2020-01-15 19:22</span>
</div>
<div class="share-valid-check">
失效時間:永久有效
</div>
<div class="slide-show-other-cns clearfix">
<span class="title-funcs">
<span class="funcs-share-area">
</span>
</span>
</div>
<div class="cb"></div>
</div>
</div>
</div>
<div class="share-list" id="shareqr">
<div class="module-toolbar g-clearfix">
<div class="default-dom">
<div class="list-grid-switch list-switched-on">
<a class="list-switch" href="javascript:void(0)" node-type="kyzmAM0B" style="display:none"></a>
<a class="grid-switch" href="javascript:void(0)" node-type="xgcvwQNp"></a>
</div>
</div>
<div class="after-dom"></div>
<div class="user-dom">
</div>
</div>
<!--[if IE]><iframe id="historyIFrameEmulator" style="display: none"></iframe><![endif]-->
<div node-type="KPDwCE" class="KPDwCE">
</div>
</div>
<div class="ad-platform-tips ad-multi-tips" node-type="share-mutil-bottom" id="web-multi-bottom" node-id="web-sharemultibanner">
<div style="margin: 0 auto; width: 960px;" id="cpro_u2164871"></div>
</div>

</div>
</div>
<div class="bd-aside">

<div node-type="module" class="module-share-person-info">
<div class="share-person-inner global-clearfix haha">
<div class="share-person-avatar">
<a href="//yun.baidu.com/buy/center?tag=1&from=sicon" class="vip-icon sicon" target="_blank"><em></em></a>
<a href="javascript:void(0)" title="去Ta的分享主頁" class="person-icon"><img alt="fci****re2" src="https://ss0.bdstatic.com/7Ls0a8Sm1A5BphGlnYG/sys/portrait/item/netdisk.1.46160ad.44gPu69hQcgfXwSxAB1nrQ.jpg"></a>
</div>
<div class="share-person-data self">
<div class="share-person-data-top">
<a href="/share/home?uk=3821724077&suk=euEHLsAO_SkKFFGZ7JnePA" target="_blank" title="去Ta的分享主頁" class="share-person-username global-ellipsis">fci****re2</a>
<a href="//yun.baidu.com/buy/center?tag=8&from=sicon" class="svip-icon sicon">
<em></em>
...

ok,以上就是摸索的內容,主要摸清楚了輸入密碼後跳轉的logid如何取得,這樣一來我們在拿到 https://pan.baidu.com/share/init?surl=xxx 這樣的鏈接和密碼時,就可以通過代碼實現批量輸入密碼後獲得訪問資源文件頁面的權限

那麼如何通過請求做到創建新文件夾以及轉存呢
我們對把一個資源轉存自己盤中的操作進行抓包(第一步是創建一個文件夾,然後第二步再把資源存到這個文件夾中)

這樣一來我們就可以看到有兩個明顯的請求

# 創建文件夾的請求
https://pan.baidu.com/api/create?a=commit&channel=chunlei&app_id=250528&bdstoken=undefined&channel=chunlei&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d&logid=MTU3OTYwNDg1NTE3ODAuNTkxMDExODM4OTIwNDg1Mw==&clienttype=0 
# 轉存資源的請求
https://pan.baidu.com/share/transfer?shareid=3153250388&from=3821724077&ondup=newcopy&async=1&channel=chunlei&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d&logid=MTU3OTYwNDg1NTE3ODAuNTkxMDExODM4OTIwNDg1Mw==&clienttype=0 

先來看創建文件夾部分的這個post請求:
https://pan.baidu.com/api/create?a=commit&channel=chunlei&app_id=250528&bdstoken=undefined&channel=chunlei&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d&logid=MTU3OTYwNDg1NTE3ODAuNTkxMDExODM4OTIwNDg1Mw==&clienttype=0

querystring跟上面差不多,就只有logid需要改動,主要的是攜帶的data

參數 狀態
isdir 1 固定
size 固定
method post 固定
dataType json 固定
path /動漫/斗羅大陸-20180062 01-最新話 自定義

可以看出其他的都不用動,在我們發送post請求時只要再帶上自定義的path就可以了

self.create_dir_post = 'https://pan.baidu.com/api/create?a=commit&channel=chunlei' \
                       '&app_id=250528&bdstoken=undefined&channel=chunlei&web=1' \
                       '&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d' \
                       '&logid={}&clienttype=0'

self.headers = {
            'User-Agent': self.user_agent,
            'Host': 'pan.baidu.com',
            'Connection': 'keep-alive',
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Origin': 'https://pan.baidu.com',
            'X-Requested-With': 'XMLHttpRequest',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Sec-Fetch-Site': 'same-origin',
            'Sec-Fetch-Mode': 'cors',
            'Accept-Encoding': 'gzip, deflate, br',
            'Accept-Language': 'zh-CN,zh;q=0.9',
        }

logid = self.get_logid(baiduid)
create_path = '/動漫/' + source_filename
 # 新建文件夾請求所需的data參數
self.create_dir_data['path'] = create_path
self.headers['Referer'] = s_url
self.headers['Cookie'] = bdclnd + ';' + self._stoken_bduss
r_create_dir = requests.post(self.create_dir_post.format(logid), data=self.create_dir_data, headers=self.headers, verify=False)
print(r_create_dir.json())

請求成功後你就可以看到在你的網盤中創建了一個自己命名的文件夾

而下一個post就是實現轉存內容的

https://pan.baidu.com/share/transfer?shareid=3153250388&from=3821724077&ondup=newcopy&async=1&channel=chunlei&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d&logid=MTU3OTYwNDg1NTE3ODAuNTkxMDExODM4OTIwNDg1Mw==&clienttype=0

參數 狀態
shareid 3153250388 變化
from 3821724077 變化
logid MTU3OTYwNDg1NTE3ODAuNTkxMDExODM4OTIwNDg1Mw== 變化

除了這三個其他querystring中的參數都是固定的,再來看post攜帶的data

參數 狀態
fsidlist [597498773956140] 變化
path /動漫/斗羅大陸-20180062 01-最新話 變化

path是需要你自己構造的,而logid,我們之前已經講到過生成方法,最關鍵的就是剩下的三個參數:shareidfromfsidlist

這參數要在哪裏找得到呢

實際上仔細想想,這三個參數肯定在之前的頁面源代碼或者Js代碼中有,之前我們已經可以成功訪問 https://pan.baidu.com/s/1xxx 這樣的頁面了,但是沒有注意這個頁面的頁面源代碼有哪些內容,再一想這三個參數是在轉存的時候用的,而轉存的頁面正好是在這個 https://pan.baidu.com/s/1xxx 頁面

那麼我們觀察一下這個頁面的源代碼就不難發現,有這麼些內容

        yunData.SHAREPAGETYPE = "multi_file";

        yunData.MYUK = "4503602932392500";
        yunData.SHARE_USER_NAME = "fci****re2";
        // 這個就是share_id -----------------------------------
        yunData.SHARE_ID = "3151703641";
        yunData.SIGN = "8e9fc93e128935d2b43ed0cb267c8bca964e33af";
        yunData.sign = "8e9fc93e128935d2b43ed0cb267c8bca964e33af";
        yunData.TIMESTAMP = "1579608010";
        // 這個就是from -----------------------------------
        yunData.SHARE_UK = "3821724077";
        yunData.SHARE_PUBLIC = 0;
        yunData.SHARE_TIME = "1579087633";
        yunData.SHARE_DESCRIPTION = "";
        yunData.MYSELF = +false;
        yunData.MYAVATAR = "https:\/\/ss0.bdstatic.com\/7Ls0a8Sm1A5BphGlnYG\/sys\/portrait\/item\/netdisk.1.c8d8ac7b.54y40Nw_2ayb-Pg7hPetiA.jpg";

                    yunData.NOVELID = "";
                // 這個就是fsidlist -----------------------------------
                yunData.FS_ID = "540067849856680";
        yunData.FILENAME = "20190069 科學的超電磁炮T";
        yunData.PATH = "\/sharelink3821724077-540067849856680\/20190069 科學的超電磁炮T";
        yunData.PATH_MD5 = "10451130099679229426";
        yunData.CTIME = "1579087633";
        yunData.CATEGORY = "6";

那麼只要能夠訪問這個頁面,然後用正則提取出來這三個參數,再構造url發送請求不就解決了嘛

這就是最後的代碼:

        self._stoken_bduss = '這一部分自己在瀏覽器的cookie中複製粘貼'
        self.pan_post = 'https://pan.baidu.com/share/verify?surl={}&t={}&channel=chunlei' \
                        '&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d' \
                        '&logid={}&clienttype=0'
        self.create_dir_post = 'https://pan.baidu.com/api/create?a=commit&channel=chunlei' \
                               '&app_id=250528&bdstoken=undefined&channel=chunlei&web=1' \
                               '&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d' \
                               '&logid={}&clienttype=0'
        self.transfer_post = 'https://pan.baidu.com/share/transfer?shareid={}' \
                             '&from={}&ondup=newcopy&async=1&channel=chunlei' \
                             '&web=1&app_id=250528&bdstoken=08a7da93cf25d7935788a123e3e10c3d' \
                             '&logid={}&clienttype=0'
        self.pan_s_url = 'https://pan.baidu.com/s/1{}'
        self.create_dir_data = {
            'isdir': '1',
            'size':	'',
            'block_list': [],
            'method': 'post',
            'dataType':	'json'
        }
        self.pwd_data = {
            'vcode': '',
            'vcode_str': '',
        }
        self.headers = {
            'User-Agent': self.user_agent,
            'Host': 'pan.baidu.com',
            'Connection': 'keep-alive',
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Origin': 'https://pan.baidu.com',
            'X-Requested-With': 'XMLHttpRequest',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Sec-Fetch-Site': 'same-origin',
            'Sec-Fetch-Mode': 'cors',
            'Accept-Encoding': 'gzip, deflate, br',
            'Accept-Language': 'zh-CN,zh;q=0.9',
        }
        self.t = int(round(time.time() * 1000))

    def get_logid(self, baidu_id):
        with open('boot.js', encoding='utf-8') as f:
            bootjs = f.read()
        js_obj = execjs.compile(bootjs)
        res = js_obj.call('getLogId', baidu_id)
        # print(res)
        return res

    def enter_pwd(self, source_filename, pan_url, pan_pwd):
        """
        通過execjs運行生成logid的代碼,獲取後跟密碼等參數一起發送post請求,將返回的BDCLND參數作爲cookie加入到get
        'https://pan.baidu.com/s/1xxx' 的請求頭中,可以正常訪問資源文件頁面
        """
        session = requests.session()
        # 請求需要密碼的網盤資源的url;verify=False 避免頻繁嘗試被封,斷開SSL,但是這個請求是不安全的
        r_baiduid = session.get(pan_url, headers={'user-agent': self.user_agent}, verify=False)
        # 獲得當前的BAIDUID用於生成logid
        baiduid = r_baiduid.cookies['BAIDUID']
        logid = self.get_logid(baiduid)
        surl = pan_url.split('surl=')[1]
        self.pwd_data['pwd'] = pan_pwd
        self.headers['Referer'] = pan_url
        # 帶密碼的post請求,成功可以訪問'https://pan.baidu.com/s/1xxx'頁面
        r = session.post(self.pan_post.format(surl, self.t, logid), data=self.pwd_data, headers=self.headers, verify=False)
        # 返回帶有randsk的json數據,取得bdclnd
        bdclnd = 'BDCLND=' + r.json()['randsk']
        # 訪問'https://pan.baidu.com/s/1xxx'的請求頭
        self.headers['Cookie'] = bdclnd
        # 'https://pan.baidu.com/s/1xxx'
        s_url = self.pan_s_url.format(surl)
        r_s_url = session.get(s_url, headers=self.headers, verify=False)
        r_s_url.encoding = 'utf-8'
        # 利用正則 獲取 轉存資源的post請求 所需的三個參數
        params = re.findall(r'yunData\.SHARE_ID = "(.*?)";.*?yunData\.SHARE_UK = "(.*?)";.*?yunData\.FS_ID = "(.*?)";', r_s_url.text, re.S)[0]
        # 調用新建文件夾以及轉存的請求
        self.create_dir(baiduid, s_url, source_filename, params, bdclnd)

    def create_dir(self, baiduid, s_url, source_filename, params, bdclnd):
        logid = self.get_logid(baiduid)
        shareid, from_id, fsidlist = params[0], params[1], params[2]
        transfer_url = self.transfer_post.format(shareid, from_id, logid)
        create_path = '/動漫/' + source_filename
        # 新建文件夾請求所需的data參數
        self.create_dir_data['path'] = create_path
        self.headers['Referer'] = s_url
        self.headers['Cookie'] = bdclnd + ';' + self._stoken_bduss
        # 需要兩個參數BDUSS,STOKEN
        r_create_dir = requests.post(self.create_dir_post.format(logid), data=self.create_dir_data, headers=self.headers, verify=False)
        print(r_create_dir.json())
        # 需要三個參數BDUSS,BDCLND,STOKEN
        r_transfer = requests.post(transfer_url, data={'fsidlist': '[' + str(fsidlist) + ']', 'path': create_path}, headers=self.headers, verify=False)
        print(r_transfer.text)

解釋一下 source_filename, pan_url, pan_pwd這三個參數分別是path的一部分,資源的鏈接,資源的密碼

另外還有selenium的操作版本,我就直接放代碼了

Selenium操作

    def s_enter_pwd(self, source_filename, pan_url, pan_pwd):
        """
        selenium操作的輸入密碼
        """
        browser = webdriver.Chrome()
        browser.get(pan_url)
        time.sleep(3)
        if '404' in browser.current_url:
            print('404,找不到頁面')
            self.update_status(pan_url)
            time.sleep(10)
            browser.close()
        # print(browser.page_source)
        # 自動輸入密碼
        browser.find_element_by_id("wkwj9A").send_keys(pan_pwd)
        time.sleep(2)
        # 自動回車
        browser.find_element_by_id("wkwj9A").send_keys(Keys.ENTER)
        time.sleep(5)
        print(browser.current_url)
        # 點擊保存到網盤,跳出登錄框
        browser.find_element_by_css_selector('.g-button.g-button-blue').click()
        time.sleep(5)
        # 輸入賬號密碼
        browser.find_element_by_id("TANGRAM__PSP_10__footerULoginBtn").click()
        time.sleep(3)
        browser.find_element_by_id("TANGRAM__PSP_10__userName").send_keys(self.username)
        browser.find_element_by_id("TANGRAM__PSP_10__password").send_keys(self.password)
        browser.find_element_by_id("TANGRAM__PSP_10__submit").click()
        # 若出現旋轉驗證碼
        try:
            slid_ing = browser.find_element_by_class_name('vcode-spin-button')
            if slid_ing:
                while True:
                    ActionChains(browser).click_and_hold(on_element=slid_ing).perform()
                    time.sleep(0.2)
                    for track in [0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4]:
                        ActionChains(browser).move_by_offset(xoffset=track, yoffset=0).perform()
                    try:
                        ActionChains(browser).release(on_element=slid_ing).perform()
                    except:
                        break
        except NoSuchElementException as e:
            print(e)
        time.sleep(10)
        browser.find_element_by_css_selector('.Qxyfvg.fydGNC').click()
        time.sleep(2)
        # 再次點擊保存到網盤
        browser.find_element_by_css_selector('.g-button.g-button-blue').click()
        time.sleep(2)
        browser.find_element_by_xpath('//*[@id="fileTreeDialog"]/div[2]/div/ul/li/ul/li[4]/div/span').click()
        time.sleep(2)
        browser.find_element_by_css_selector('.icon.icon-newfolder').click()
        time.sleep(3)
        browser.find_element_by_css_selector('.input.shareFolderInput').clear()
        browser.find_element_by_css_selector('.input.shareFolderInput').send_keys(source_filename)
        browser.find_element_by_css_selector('.input.shareFolderInput').send_keys(Keys.ENTER)
        time.sleep(2)
        browser.find_element_by_css_selector('.treeview-node.treenode-empty.treeview-node-on').click()
        browser.find_element_by_xpath('//*[@id="fileTreeDialog"]/div[3]/a[2]').click()
        time.sleep(30)
        browser.close()

備忘

import time
import datetime

t = time.time()

print (t)                       #原始時間數據  1552267863.7501628
print (int(t))                  #秒級時間戳     1552267863
print (int(round(t * 1000)))    #毫秒級時間戳    1552267863750

nowTime = lambda:int(round(t * 1000))
print (nowTime());              #毫秒級時間戳,基於lambda    1552267863750

print (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))   #日期格式化
2019-03-11 09:31:03

參考

python3爬蟲(5)百度雲盤暴力破解嘗試
OpenSSL.SSL.Error: [(‘SSL routines’, ‘tls_process_server_certificate’, ‘certificate verify failed’)](ssl證書問題)
python3+selenium常用語法彙總
https://www.52pojie.cn/thread-1059883-1-1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章