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

来源:https://www.cnblogs.com/stars-one/archive/2020/01/19/12215684.html
-Advertisement-
Play Games

本文是針對我的工具 "藍奏雲批量下載工具" 的補充說明筆記,準備按照流程整理我實現軟體的思路與方法。 涉及知識 Java的IO流 Java的下載文件 HtmlUnit的使用方法 okhttp的使用 分析與軟體思路 在某一天,我找到了一部電子書的資源,但是,該藍奏雲地址是一個文件夾,由於藍奏雲不支持批 ...


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

涉及知識

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

分析與軟體思路

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

按照順序,一步步分析吧

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

這個時候,我們需要可以自動模擬用戶進行提交表單的操作(代碼詳情見關鍵代碼部分1)

經過網上的查找,發現了HtmlUnit這個開源庫可以實現我們需要的操作。

HtmlUnit,說白了就是一個瀏覽器,這個瀏覽器是用Java寫的無界面的瀏覽器,因為其沒有界面,因此執行的速度還是妥妥的

之後我們便是來到這樣的界面

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

對了,這裡有可能文件過多,會出現顯示更多的按鈕,這個情況我們也得考慮,我們可以使用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中的下載即可成功下載該文件

關鍵功能代碼及說明

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

4、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爬取藍奏雲直鏈(獲取真實文件地址)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • dir同樣可以查找實例的屬性字典 print(dir(p1)) 下麵是增刪改查舉例: class Chinese: country='中國' def __init__(self,name): self.name=name def play_ball(self,ball): print('%s正在打% ...
  • 程式員在轉型架構師的過程中需要建立流程化、結構化、系統化的思維方式,而性能調優是非常難得的契機,它既給了我們壓力,也給了我們動力,跨越它就是突破自己的過程。Y 維度,就是從業務 HTTP 請求的橫向處理流程來看,HTTP 請求會穿越網路、電腦、應用容器(Tomcat)、Spring、ORM(Hib... ...
  • 一、java中八種基本數據類型對應的包裝類型 基本數據類型 包裝類型 byte java.lang.Byte short java.lang.Short int java.lang.Integer long java.lang.Long float java.lang.Float double ja ...
  • 開發環境: Windows操作系統 開發工具: Eclipse+Jdk+Tomcat+MYSQL資料庫 運行效果圖: 源碼及原文鏈接:http://javadao.xyz/forum.php?mod=viewthread&tid=28 ...
  • 慕課網-跳跳虎-圖解+仿寫 新手都能學懂的SpringBoot源碼課-366元 慕課網-跳跳虎-圖解+仿寫 新手都能學懂的SpringBoot源碼課-366元——全方位深入解析最新版SpringBoot源碼當下SpringBoot日漸取代SSM成為新項目首選框架,企業招聘對其要求也不斷提高。掌握Sp ...
  • 概述 ReentrantLock是一個可重入的互斥鎖,也被稱為獨占鎖。它支持公平鎖和非公平鎖兩種模式。 ReentrantLock的使用方法 下麵看一個最初級的例子: 在進入方法後,在需要加鎖的一些操作執行之前需要調用lock方法,在jdk文檔中對lock方法詳細解釋如下: 獲得鎖。 如果鎖沒有被另 ...
  • 相信有不少朋友日常工作會用到 Excel 處理各式表格文件,更有甚者可能要花大把時間來做繁瑣耗時的表格整理工作。最近有朋友問可否編程來減輕表格整理工作量,今兒我們就通過實例來實現 Python 對錶格的自動化整理。 首先我們有這麼一份數據表 source.csv: 我們要做的是從上表中提取數據,來生 ...
  • SpringMVC SpringMVC是一種輕量級的、基於MVC的Web層應用框架。 通過一套 MVC 註解,讓 POJO 成為處理請求的控制器,而無須實現任何介面。 採用了鬆散耦合可插拔組件結構,比其他 MVC 框架更具擴展性和靈活性。 優點: 1、天生與Spring框架集成,如:(IOC,AOP ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...