蓝奏云批量下载工具的实现思路笔记

本文是针对个人工具蓝奏云批量下载工具的补充说明笔记,准备按照流程整理我实现软件的思路与方法。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爬取蓝奏云直链(获取真实文件地址)

相关文章
相关标签/搜索