×
文章路径: Java

java解析华为网盘真实下载地址

发表于3年前(Jun 3, 2015 4:22:35 PM)  阅读 491  评论 0

分类: Java 类库工具

标签: 华为网盘 外链 解析下载地址

1、背景:

这几年涌现出一大批网盘运营商,对于很多服务器磁盘有限的站长也经常将要提供下载的文件上传到网盘,以节省自己的空间。一般来说,都是链接到网盘页面,然后用户点击下载开始下载文件,其中不乏有些网盘需要登录,需要提取码等等,这些操作能不能简化,一次性过呢?是可以的,笔者写的这个java类是针对华为网盘,通过网盘的链接地址,获取到该页面下载列表里面的所有文件的真实下载地址。获得真实下载地址后,其实直接可以使用该地址作为图片、音乐等等的外链了。不过最后测试的时候,笔者发现,华为网盘的下载地址是有时效性的,过一段时间后必须重新加密计算,做外链的话多了一次解析加密的过程。

2、原理:

华为网盘的真实下载地址主要由两个字段计算出来,一个是encryKey,一个是downloadurl,downloadurl是一大长串字符,每个文件唯一对应,而encryKey不是固定的,每个下载页面对应一个encryKey(时效性就跟这个值有关),同一个下载页面的所有文件encryKey相同。

加密所需要的两个字段都在下载页面的js代码里面包含了,以http://dl.vmall.com/c09o4rem5w 这个页面为例,我们可以在整个网页源文件中找到如下代码:

<script type="text/javascript">
    var globallinkdata = {"retcode":"0000","data":{"profile.productid":"0","profile.lastvipname":null,"profile.link_access_switch":"close","profile.dbank_avatar":null,"product.productname":"\u6807\u51c6\u7528\u6237","outlink_text":["APE","\u8f6f\u4ef6","\u624b\u673a\u5e94\u7528","\u58c1\u7eb8","\u5b89\u5353\u6e38\u620f","\u82f1\u8bed","\u52a8\u6f2b","ppt"],"encryKey":"ed23697139","download_num":0,"resource_ad":{"ad_A":true,"ad_B":true,"ad_C":true,"ad_D":true,"ad_E":true,"ad_F":true,"ad_G":true,"ad_H":false,"ad_I":true,"ad_J":true},"captcha_switch":{"hao123_old":100,"hao123_new":100,"captcha":-1,"doHao123":"false","captcha_rate":[{"adShow":"true","tips":"100","install":"0"},{"adShow":"false","tips":"100","install":"0"}]},"is_captcha":"true","captcha":{"high_speed_download":"open"},"showOverSizeTip":"false","downLoadWhite":"false","pluginForceSetup":0,"buttonshow":{"download":"open","high_speed_download":"open","thunder_download":"open","resource_store":"open","rule":"lt"},"hongMediaRatio":"0","ruletype":3,"resource":{"id":"c09o4rem5w","uid":"40103792","title":"\u4e14\u541f\u6625\u8bed.mp3","summary":"","tags":"","username":"yang139wei","status":"0","create_time":"2013-08-30 22:28:04","modify_time":"2013-08-31 09:54:54","update_time":"2015-06-01 07:11:10","form":"dbank_advance_link","content":"<p><\/p>","attribute":{"cnt":106,"encry_tpl":"default","store_switch":"open","appid":"10007"},"files":[{"name":"\u4e14\u541f\u6625\u8bed.mp3","type":"File","nspurl":"MDAwMDAwMDGBIQ-W-87qIt27Nqcmtwuq3M9QM86_C1INQVpXMSlyGg..\/c1c475a732fd57a7bf277bfabf954380f2aa73","status":0,"id":1,"size":15903347,"downloadurl":"XEwQRVtKHFcKH0FVAwhVSgBbWUpUDBILXAsFAUoQfVERelwQWFEWdlMUDghHXX9BJgIRXAhGJFAVIVxAJHMdJHAWCUVSWlUOBQEOV1YWXAlWQxIMDVJDDQ1VUFZWBglSBw5WExdYVwpXBA8NWgAfEV4EBVRWWlJdVEINFVgDCUsFDFYbU1EFHVcBEUhfVB8IE11QWBYXBlgBQgUQDFEFQ1hLWQ==","xunleiurl":"QFARWwUAQQlJHmZtJAtdLDFDewwIFT8iRxEACFRdWiJDTT0HWBF\/ATRHUwpXF1tWJV94HGYlKyZmJysmMAB2JmJ+KmY0UH5wMwRlUTQidw02AXsmZiErNmYiKyYzd2oMYno2dlQRUHcrHm1SUw50IA9Cei16DwcxZlcuCA4MdTZuVzRhJFV+SStLemwBHncOKllQDwEIKjF1VSshMAFiJm4JNGEgHX5kPwR5QgoPcwkPQ2QxaRspD3VUKQxRTHYhbU0pYSAIUHdWRn1VGhNYMzINfgtiCTUxdQk9PTNFYiEEVQZ9LFxkXwkM"}],"seo_title":"\u4e14\u541f\u6625\u8bed.mp3-[\u97f3\u4e50]"}}};
</script>
可以看到,globallinkdata变量包含了我们需要的所有信息,该变量是一个json对象,retcode是状态码,data是我们所需要的数据,data里的encryKey是加密需要的一个字段,data里的resource属性里面有一个files数组,每一个元素就代表了一个下载文件,其中downloadurl就是我们所需要的,剩下的就是加密算法了。

3、实现:

以下是java代码实现,其中获取globallinkdata变量值时使用了htmlparser工具解析html,需要引入该jar包:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.RegexFilter;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.util.NodeList;

import sun.misc.BASE64Decoder;


public class DBankUtil {

	public static void main(String[] args) {
		String url = "http://dl.vmall.com/c09o4rem5w";
		String[] downURLs = getDownloadURL(url);
		for(String str:downURLs) {
			System.out.println(str);
		}		
	}
	
	public static String[] getDownloadURL(String url) {
		String linkData = "";
		linkData = getLinkData(url);
		Map map = getLinkDataMap(linkData);
		return calcDownURL(map);
	}
	
	
	public static String[] calcDownURL(Map linkDataMap) {
		if(linkDataMap==null) {
			return new String[]{};
		}
		String key = (String) linkDataMap.get("encryKey");
		List<String> downList = new ArrayList<String>();
		
		LinkedHashMap rlist = (LinkedHashMap) linkDataMap.get("resource");
		List fileList = (List) rlist.get("files");
		for(int i=0;i<fileList.size();i++) {
			LinkedHashMap fileMap = (LinkedHashMap) fileList.get(i);
			String downloadurl = (String) fileMap.get("downloadurl");
			downList.add(downloadurl);
		}
		
		List<String> downloadurlList = new ArrayList<String>();
		for(int i=0;i<downList.size();i++) {
			String downloadurl = decry(downList.get(i), key);
			downloadurlList.add(downloadurl);
		}

		return downloadurlList.toArray(new String[]{});
	}
	
	public static Map getLinkDataMap(String linkData) {
		if(linkData!=null&&!"".equals(linkData)) {
			return (Map) JsonUtil.toObject(linkData, HashMap.class).get("data");
		}
		return null;
	}
	
	public static String getLinkData(String url) {
		try {
			URLConnection conn = new URL(url).openConnection();
			Parser parser = new Parser(conn);
			parser.setEncoding("UTF-8");
//			String regex = "globallinkdata\\s=\\s(.*?);";
			String regex = "globallinkdata\\s=\\s(.*?}+);";
			NodeFilter filter = new RegexFilter(regex);
			NodeList list = parser.parse(filter);
			
			if(list!=null&&list.size()>0) {
				TextNode node = (TextNode) list.elementAt(0);
				String linkData = node.getText().trim();
				
				Pattern pattern = Pattern.compile(regex);
				Matcher matcher = pattern.matcher(linkData);
				if(matcher.find()) {
					linkData = matcher.group(1);
				} else {
					linkData = "";
				}
				return linkData;
			} else {
				return "";
			}
			
		} catch (Exception e) {
			
		}
		return "";
	}
	
	public static String decry(String url, String key) {
		String g = base64_decode(url);
		String f = key.substring(0, 2);
		String d = "";
		if("ea".equals(f)) {
			d = g;
		} else if("eb".equals(f)) {
			d = a(g, b(key, key));
		} else if("ed".equals(f)) {
			d = a(g, MD5Util.encodeMD5(key));
		} else {
			d = g;
		}
		return d;
	}
	
	
	public static String base64_decode(String str) {
		BASE64Decoder decoder = new BASE64Decoder();
		byte[] b = null;
		try {
			b = decoder.decodeBuffer(str);
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
		String dec = "";
		try {
			dec = new String(b, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return dec;
	}
	
	public static String a(String d, String e) {
		String g = "";
		int l = e.length();
		int f = d.length();
		for(int h=0;h<f;h++) {
			int k = d(d, h)^d(e, h%l);
			g += c(k+"");
		}
		return g;
	}
	
	public static String b(String h, String l) {
		int[] k = new int[256];
		int e = 0;
		for(int f=0;f<256;f++) {
			k[f] = f;
		}
		for(int f=0;f<256;f++) {
			e = (e+k[f]+d(h, f%h.length()))%256;
			int d = k[f];
			k[f] = k[e];
			k[e] = d;
		}
		int f = 0;
		e = 0;
		String g = "";
		for(int m=0;m<l.length();m++) {
			f = (f+1)%256;
			e = (e+k[f])%256;
			int d = k[f];
			k[f] = k[e];
			k[e] = d;
			g += c(Integer.toBinaryString(d(l, m)^k[(k[f]+k[e])%256]));
		}
		return g;
	}
	
	public static String c(String str) {
		String re = "";
		char a = (char) Integer.parseInt(str);
		re = a+"";
		return re;
	}
	
	public static int d(String str, int i) {
		int n = 0;
		n = str.codePointAt(i);
		return n;
	}

}

发表评论