逆向腾讯视频获取 m3u8 源地址 (Java)

本贴最后更新于 1276 天前,其中的信息可能已经天翻地覆

以下内容仅供学习使用,请勿用于非法用途

代码是在今年三月份写的,当时候捣鼓了一天,现在也有点忘了,就直接把代码贴出来吧,今天测试了一下还是可以用的

代码中有一些包还有方法是自己的,就不都粘贴出来了,如果直接复制代码的话,会有报错,需要再手动改改

<!--相关依赖-->
	<dependency>
    		<groupId>org.jsoup</groupId>
    		<artifactId>jsoup</artifactId>
    		<version>1.11.3</version>
	</dependency>
	<dependency>
		<groupId>cn.hutool</groupId>
		<artifactId>hutool-all</artifactId>
		<version>5.1.0</version>
	</dependency>
package com.Yang.watermark;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TencentVideo{

	String url  = "";
	String appVersion = "1.0.143";
	String platform = "10201";
	String v = "3.5.57";
	String encryptVer = "9.1";

	public TencentVideo(String url) {
		this.url = url;
	}

	@Override
	public String execute() {
		String start = "<link rel=\"canonical\" href=";
		HttpResponse response = requestNoHeader(url);
		String body = response.body();
		int indexOf = body.indexOf(start);
		body = body.substring(indexOf + start.length() + 1);
		int index = body.indexOf("\" />");
		body = body.substring(0,index);
		String[] split = body.split("/");
		String vid = split[split.length - 1].replaceAll(".html","");
		String[] split2 = url.split("/");
		String coverid = split2[split2.length - 1].replaceAll(".html","");
	
		//这儿替换成自己的生产随机数的方法就可以
		String flowid = RandomCharUtil.getRandomNumberLowerLetterChar(32) + "_" + platform;
		String tm = String.valueOf(System.currentTimeMillis()).substring(0,10);
		String rfid = RandomCharUtil.getRandomNumberLowerLetterChar(32) + "_" + tm;
		//这儿是cKet加密字符串的获取方式,调用自己的node服务,下文中有说明
		String cKey = HttpUtil.get("http://Ip:port/?vid="+ vid +"&tm=" + tm);
	
		log.info("vid:{}",vid);
		log.info("coverid:{}",coverid);
		log.info("flowid:{}",flowid);
		log.info("tm:{}",tm);
		log.info("rfid:{}",rfid);
		log.info("url:{}",url);
		log.info("cKey:{}",cKey);
	
		//登录了腾讯视频之后可以拿到cookie,直接粘贴在这儿就行
		String cookieStr = "";
		String[] split3 = cookieStr.split("; ");
		Map<String, String> cookieMap = new HashMap<String, String>();
		if(cookieStr != "" && cookieStr != null) {
			for(String str : split3) {
				cookieMap.put(str.split("=")[0], str.split("=")[1]);
			}
		}
	
	
		HttpRequest post = HttpUtil.createPost("https://vd.l.qq.com/proxyhttp");
		post.header("Referer" , url);
		String buildParam = buildParam(coverid, flowid, url, rfid, vid, cKey, tm , cookieMap);
		post.body(buildParam);
		//执行
		String res = post.execute().body();
		log.info(res);
		JSONArray ul = JSONObject.parseObject(res).getJSONObject("vinfo").getJSONObject("vl").getJSONArray("vi").getJSONObject(0).getJSONObject("ul").getJSONArray("ui");
		//这里拿数组最后一个,清晰度最高的
		JSONObject ui = ul.getJSONObject(ul.size()-1);
		if(cookieStr == "") {
			//没有登录使用这种方式获取,但是如果是vip电影获取出来的只有5分钟
			return ui.getString("url") + ui.getJSONObject("hls").getString("pt");
		}
		//如果登录了可以使用这种方式获取
		return ui.getString("url");
	}

	public static String get(String address) {
		return new TencentVideo(address).execute();
	}

	public static void main(String[] args) {
		log.info(TencentVideo.get("https://v.qq.com/x/cover/050w2y6nen7rud1.html"));
//		TencentVideo.get("https://v.qq.com/x/cover/bqejbbv8mgtusrs/u00242ise58.html");
	
	}


	public String buildParam(String coverid,String flowid,String url,String rfid , String vid , String cKey , String tm , Map<String, String> cookieMap) {
	
		boolean haveCookie = false;
		if(!cookieMap.isEmpty()) {
			haveCookie = true;
		}
	
	
		StringBuffer adparam = new StringBuffer();
		adparam.append("ad_type=LD|KB|PVL").append("&");
		adparam.append("adaptor=2").append("&");
		adparam.append("appversion="+ appVersion).append("&");
		adparam.append("chid=0").append("&");
		adparam.append("coverid=" + coverid).append("&");
		adparam.append("dtype=1").append("&");
		adparam.append("flowid=" + flowid).append("&");
		adparam.append("from=0").append("&");
		adparam.append("guid=" + "d1384f3028935f6465a473a5a07113b5").append("&");
		adparam.append("live=0").append("&");
		adparam.append("pf=in").append("&");
		adparam.append("platform=" + platform).append("&");
		adparam.append("pf_ex=pc").append("&");
		adparam.append("plugin=1.0.0").append("&");
		adparam.append("pt=").append("&");
		adparam.append("pu=0").append("&");
		adparam.append("refer=" + url).append("&");
		adparam.append("req_type=1").append("&");
		adparam.append("resp_type=json").append("&");
		adparam.append("rfid=" + rfid).append("&");
		adparam.append("tpid=1").append("&");
		adparam.append("ty=web").append("&");
		adparam.append("url=" + url).append("&");
		adparam.append("v=" + v).append("&");
		adparam.append("vid=" + vid).append("&");
		adparam.append("vptag=www_baidu_com");
		if(haveCookie) {
			String uid = cookieMap.get("vqq_vuserid");
			String tkn = cookieMap.get("vqq_vusession");
			String opid = cookieMap.get("vqq_openid");
			String lt = cookieMap.get("main_login");
			String atkn = cookieMap.get("vqq_access_token");
			String appid = cookieMap.get("vqq_appid");
		
			adparam.append("&");
			adparam.append("uid=" + uid).append("&");
			adparam.append("tkn=" + tkn).append("&");
			adparam.append("lt=" + lt).append("&");
			adparam.append("opid=" + opid).append("&");
			adparam.append("atkn=" + atkn).append("&");
			adparam.append("appid=" + appid);
		}
		
	
	
	
		StringBuffer vinfoparam = new StringBuffer();
		vinfoparam.append("appVer=" + v).append("&");
		vinfoparam.append("cKey=" + cKey).append("&");
		vinfoparam.append("charge=0").append("&");
		vinfoparam.append("defaultfmt=auto").append("&");
		vinfoparam.append("defn=fhd").append("&");//取值:fhd(蓝光) shd(超清)   hd(高清)  sd(标清)
		vinfoparam.append("defnpayver=1").append("&");
		vinfoparam.append("defsrc=1").append("&");
		vinfoparam.append("dlver=2").append("&");
		vinfoparam.append("drm=32").append("&");
		vinfoparam.append("dtype=3").append("&");
		vinfoparam.append("ehost=" + url).append("&");
		vinfoparam.append("encryptVer=" + encryptVer).append("&");
		vinfoparam.append("fhdswitch=0").append("&");
		vinfoparam.append("flowid=" + flowid).append("&");
		vinfoparam.append("fp2p=1").append("&");
		vinfoparam.append("guid=" + "d1384f3028935f6465a473a5a07113b5").append("&");
		vinfoparam.append("hdcp=0").append("&");
		vinfoparam.append("host=v.qq.com").append("&");
		vinfoparam.append("isHLS=1").append("&");
	
		if(haveCookie) {
			String uid = cookieMap.get("vqq_vuserid");
			String tkn = cookieMap.get("vqq_vusession");
			String opid = cookieMap.get("vqq_openid");
			String lt = cookieMap.get("main_login");
			String atkn = cookieMap.get("vqq_access_token");
			String appid = cookieMap.get("vqq_appid");
		
			String logintoken = "{\"main_login\":\""+ lt +"\",\"openid\":\""+ opid +"\",\"appid\":\""+ appid +"\",\"access_token\":\""+atkn+"\",\"vuserid\":\""+uid+"\",\"vusession\":\""+tkn+"\"}";
			vinfoparam.append("logintoken=" + URLEncoder.encode(logintoken)).append("&");
		}
	
	
		vinfoparam.append("otype=ojson").append("&");
		vinfoparam.append("platform=" + platform).append("&");
		vinfoparam.append("refer=v.qq.com").append("&");
		vinfoparam.append("sdtfrom=v1010").append("&");
		vinfoparam.append("show1080p=1").append("&");
		vinfoparam.append("spadseg=1").append("&");
		vinfoparam.append("spau=1").append("&");
		vinfoparam.append("spaudio=15").append("&");
		vinfoparam.append("spgzip=1").append("&");
		vinfoparam.append("sphls=2").append("&");
		vinfoparam.append("sphttps=1").append("&");
		vinfoparam.append("spwm=4").append("&");
		vinfoparam.append("tm=" + tm).append("&");
		vinfoparam.append("unid=cdbb5f0a6aad11ea981ca042d48ad00a").append("&");
		vinfoparam.append("vid=" + vid);
	
	
		//构造参数时buid可取值
		//1.vinfoad(包含视频信息和广告)
		//2.onlyvinfo(只包含视频信息)
		return "{\"buid\":\"vinfoad\",\"adparam\":\"" + adparam.toString() + "\",\"vinfoparam\":\"" + vinfoparam.toString() + "\"}";
	}

	HttpResponse requestNoHeader(String url) {
		return HttpUtil.createGet(url).execute();
	}
}

上边的代码中预留了一个调用 node 服务的地方,这个是一堆加密的玩意儿,需要一个 node 服务,还有一个 wasm 文件

点击此处下载 node 服务的 js 代码以及 wasm 文件

下载好之后直接按照 node 命令启动服务即可

启动之后把 node 服务的 ip 和端口填写在 Java 代码中(49 行左右)

接下来就可以运行 Java 脚本执行获取结果了,最后获取到的是 m3u8 的地址

里边有一些参数是固定的值(unid)(guid)之类的,不要去修改它,代码呢,可能写的比较low,哈哈哈

  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖
  • m3u8
    1 引用
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3168 引用 • 8207 回帖
1 操作
724555508 在 2020-10-25 12:08:45 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...