藍奏雲批量下載工具的實現思路筆記

本文是針對個人工具藍奏雲批量下載工具的補充說明筆記,準備按照流程整理我實現軟件的思路與方法。php

涉及知識

  • Java的IO流
  • Java的下載文件
  • HtmlUnit的使用方法
  • okhttp的使用

分析與軟件思路

在某一天,我找到了一部電子書的資源,可是,該藍奏雲地址是一個文件夾,因爲藍奏雲不支持批量下載,因此我即是誕生了打造出一個批量下載的工具的念頭,大概搞了五天吧終因而成功了,折騰其中的重定向下載就搞了兩天,說多了都是淚啊...html

按照順序,一步步分析吧web

首先,我瀏覽器打開了藍奏雲地址,這裏有兩種狀況,一種是有提取碼,一種是沒有提取碼的。瀏覽器

這個時候,咱們須要能夠自動模擬用戶進行提交表單的操做(代碼詳情見關鍵代碼部分1)網絡

通過網上的查找,發現了HtmlUnit這個開源庫能夠實現咱們須要的操做。多線程

HtmlUnit,說白了就是一個瀏覽器,這個瀏覽器是用Java寫的無界面的瀏覽器,由於其沒有界面,所以執行的速度仍是妥妥的ide

以後咱們即是來到這樣的界面工具

咱們須要解析當前並得到每一個文件對應的藍奏雲地址,這裏因爲HTMLUnit內置了html元素選擇器,咱們可使用HtmlUnit的選擇器進行節點的過濾操做,獲得文件信息以及對應的藍奏雲地址(代碼詳情見關鍵代碼部分2)post

對了,這裏有可能文件過多,會出現顯示更多的按鈕,這個狀況咱們也得考慮,咱們可使用HTMLUnit實現自動點擊顯示更多的按鈕,我以前拿別人的連接來測試,那位大佬的連接裏文件過多,致使我程序跑了二十多分鐘,尚未跑完,而後,個人IP就被藍奏雲封了,出現了拒絕訪問的警告。。測試

以後我重啓了路由,因爲IP地址是自動分配的,改了IP地址就解決了

因此,我打算限定一個最大的次數,超過以後就不點擊了,即便列表尚未顯示徹底(代碼詳情請見關鍵代碼部分3)

因爲咱們打開某個文件的藍奏雲地址,能夠發現下載地址

右鍵,複製地址,咱們獲得下面這一串長長的連接,這個連接其實不是真實地址,因此,我姑且以僞直鏈來稱呼它,僞直鏈的是具備時效性的,就是說會過時,因此,得儘快經過僞直鏈來獲取真實地址。

https://vip.d0.baidupan.com/file/?AGYFO1tqDj9TWgE5VmNUOFFuVGxW7gKlAZhTvVCjVckJ7gLuANVV5AnvV4dQ4gCcAf5Ss1K1B7EE5AGdUopVsgCUBexb4w73U6MBslaSVNtR7VTZVpEC5AG8U9xQLFWyCZ4C8AC4VY8J2VfmUKsAhgF1UjJSfQdwBGEBIVJoVT0AbAU3W1kOM1NhAWpWNVRkUTJUZVY/AjUBMVNzUGpVJwk0AmcAbVUxCWlXMFA9ADcBfVInUn0HOAQxATdSP1VtAC8FYls0DnVTNwFhVi1UY1FoVGhWMAJiATVTM1A7VWQJbQJkAD9VNglrVzRQNgAxAT5SNFI6BzIEMgEwUjZVZAA4BWJbNQ4+UzcBZlZnVHtRblQhVnwCYgEgUyBQf1UxCXsCPAA5VTwJZ1c2UDAAMwFqUmFSKwdxBGoBalJrVTIAPQVjWzMObVM8AWNWMVRjUTlUZFYxAi4BIFMgUHxVaQk4AnsAe1VnCTNXdlA5ADABblJgUjQHNgQ3ATNSPlVmADQFdFtzDipTcgFqVjNUYFE+VGBWOAI4ATFTZFA0VWEJLwIgADRVcQliVzBQNQA2AXVSZlI1BzYELQE1Uj5VZgAuBWdbNg==

本來覺得使用HtmlUnit開源庫能夠很簡單地獲取僞直鏈,不過,出了點情況,經過瀏覽器的元素審查功能,發現下面的那三個地址實際上是一個iframe

因爲是iframe,至關於再次加載了另一個頁面,因此咱們不能直接得到僞直鏈,得先經過得到iframe的src屬性去訪問它本來的那個網頁。

咱們能夠經過瀏覽器,直接去訪問那個頁面(頁面地址爲https://www.lanzous.com+src屬性值),頁面打開以下:

頁面須要等待一會,以後出現了三個按鈕,以後,咱們即可以得到a標籤的href屬性,即得到了僞直鏈的地址(代碼詳情請見關鍵代碼4)

使用瀏覽器打開僞直鏈,瀏覽器會直接下載文件了,可是,在程序中使用Java的下載操做確實返回的html文件,內容較多,省略了一下樣式,內容以下:

...
<div id="pwdload">
<div class="title">下載文件</div>
<div class="txt">系統發現您網絡不正常,須要驗證<br>請輸入右邊圖形中的數字</div>
<div class="imcode"><img id="img" src="imagecode.php?" onclick="changeCode()"/></div>
<div class="cl"></div>
<div class="input_box"><input type="text" name="code" class="input" id="code" value="" /></div>
<div class="cl"></div>
<div id="pwderr"></div>
<div id="sub" onclick="down_r();" class="btnpwd">驗證並下載</div>
</div>
<div id="info">
<div class="info1"><div class="info2"></div></div>
<div class="info3">恭喜你,經過了</div>
<div class="load" id="go">
</div>
</div>
...
</html>

這裏研究了兩天,終因而找到了別人的博文中找到了答案,緣由是請求並無攜帶請求頭,因此致使藍奏雲返回一個驗證的頁面,有請求頭的話, 就會重定向到真實的地址。

這裏,我使用了okhttp這個開源庫,實現添加了請求頭,最後得到了真實的下載地址(代碼詳情請見關鍵代碼5),由此地址咱們再調用Java中的下載便可成功下載該文件

關鍵功能代碼及說明

一、二、3這三個部分的代碼都是在MainController類中的download方法中

四、5部分在MainController類中的getDownloadLink方法中

這裏我只抽取關鍵部分來進行講解

1.模擬用戶提交表單

注意,提交表單以後須要等待2s來等待js執行完畢以顯示出文件列表

//這個readyNodes包含全部id爲ready的div一個列表
val readyNodes = if (password.isNotBlank()) {
    //有密碼的狀況
    val pwdInput = page.getElementByName<HtmlTextInput>("pwd")
    val button = page.getElementsById("sub")[0] as HtmlSubmitInput
    pwdInput.valueAttribute = password//輸入提取碼
    val finishPage = button.click<HtmlPage>()//提交表單
    webClient.waitForBackgroundJavaScript(2000)//等待2s
    finishPage.getElementsById("ready")
} else {
    //無密碼的狀況
    webClient.waitForBackgroundJavaScript(2000)
    page.getElementsById("ready")
}

2.自動點擊加載更多按鈕

//文件可能不止一頁,爲了防止被封IP,限定最大翻頁數,由用戶輸入
        for (i in 0 until pageCount) {
            if (page.getElementById("filemore") != null) {
                page = page.getElementById("filemore").click()
            } else {
                break
            }
        }

3.解析列表得到各文件對應地址

爲了方便,我直接把文件名、日期等參數也一併獲取了,用了一個ItemData的bean類進行數據的存儲

//初始化列表(分享的藍奏雲地址中的全部文件及相關信息)
val itemDatas = arrayListOf<ItemData>()
//選擇器進行網頁的解析獲取數據
for (readyNode in readyNodes) {
    val childNodes = readyNode.getElementsByTagName("div")
    val nameNode = childNodes[0].lastElementChild
    val sizeNode = childNodes[1]
    val timeNode = childNodes[2]
    val name = nameNode.textContent
    val link = nameNode.getAttribute("href")//單個文件的藍奏雲地址
    val size = sizeNode.textContent
    val time = timeNode.textContent
    itemDatas.add(ItemData(name, link, "", size, time))
}

4.得到僞直鏈地址

//url是單個文件的藍奏雲地址
val page = webClient.getPage<HtmlPage>(url)
val srcText = page.getElementsByTagName("iframe")[0].getAttribute("src")
//拼接字符串,獲得另外頁面的url
val downloadHtmlUrl = "https://www.lanzous.com$srcText"
val downloadPage = webClient.getPage<HtmlPage>(downloadHtmlUrl)
//等待js加載完畢
webClient.waitForBackgroundJavaScript(1000)
//得到僞直鏈地址(a標籤的href屬性值)
val address = downloadPage.getElementById("go").firstElementChild.getAttribute("href")

5.使用okhttp得到藍奏雲真實地址

HttpUtil.sendOkHttpRequest(address, object : Callback {
    override fun onFailure(p0: Call?, p1: IOException?) {
        println("error")
    }

    override fun onResponse(p0: Call?, response: Response?) {
        itemData.downloadLink = response?.request()?.url().toString()
        response?.close()
    }
})

//補充的okhttp的工具類HttpUtilsendOkHttpRequest的方法
fun sendOkHttpRequest(address: String, callback: Callback) {
    val client = OkHttpClient()
    val control = CacheControl.Builder().build()
    //添加請求頭user-agent和accept-language
    val request = Request.Builder()
            .addHeader("user-agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36")
            .addHeader("accept-language","zh-CN,zh;q=0.9")
            .cacheControl(control)
            .url(address)
            .build()
    client.newCall(request).enqueue(callback)
}

6.下載功能

雖然和以前的工具同樣,可是我仍是把代碼貼出來吧

/**
 * 下載文件到本地
 * @param url 網址
 * @param file 文件
 */
private fun downloadFile(url: String, file: File) {
    if (!file.exists()) {
        val conn = URL(url).openConnection()
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)")
        val bytes = conn.getInputStream().readBytes()
        file.writeBytes(bytes)
    }
}

PS:我在解析過程和下載過程當中使用了多線程下載,提升了速度。具體實現思路請參考以前個人這一篇文章打造m3u8視頻(流視頻)下載解密合並器(kotlin)的第4部分

參考連接

Java實現網頁自動登陸和表單自動填寫提交研究

Python爬取藍奏雲直鏈(獲取真實文件地址)

相關文章
相關標籤/搜索