2019独角兽企业重金招聘Python工程师标准>>>
朋友推荐了一个比较隐蔽的盗版电影观看网站,网速特别慢观看不爽,就想是不是可以下载下来看,于是就写了这个小工具
首先,你要有能力在网页里面找到这个M3U8的索引文件,相信对于一个开发人员这个应该很容易,通过浏览器F12找到了这个索引文件,如下,我只截取了一部分,这个文件简单讲一下就是把一个视频切分成了好多小片段,而这个文件就是他们的目录文件,找到这个就容易了,接下来,把里面的每个视频片段下载下来合成就可以了。
第一步,下载索引文件
public static String getIndexFile(String urlpath){
try{
URL url = new URL(urlpath);
//下在资源
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(),"UTF-8"));
String content = "" ;
String line;
while ((line = in.readLine()) != null) {
content += line + "\n";
}
in.close();
System.out.println(content);
return content;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:4.971633,
ba1620338f71656.ts
#EXTINF:3.336667,
ba1620338f71657.ts
#EXTINF:3.336667,
ba1620338f71658.ts
#EXTINF:3.336667,
ba1620338f71659.ts
#EXTINF:3.336667,
ba1620338f71660.ts
#EXTINF:0.266933,
ba1620338f71661.ts
#EXT-X-ENDLIST
第二步,解析索引文件
public static List analysisIndex(String content){
Pattern pattern = Pattern.compile(".*ts");
Matcher ma = pattern.matcher(content);
List list = new ArrayList();
while(ma.find()){
String s = ma.group();
list.add(s);
System.out.println(s);
}
return list;
}
解析的数据结果,把索引中的ts部分解析出来,方法很多
ba1620338f7035.ts
ba1620338f7036.ts
ba1620338f7037.ts
ba1620338f7038.ts
ba1620338f7039.ts
ba1620338f7040.ts
ba1620338f7041.ts
ba1620338f7042.ts
ba1620338f7043.ts
ba1620338f7044.ts
ba1620338f7045.ts
ba1620338f7046.ts
ba1620338f7047.ts
第三步,根据第二步的解析结果下载视频片段
public static List downLoadIndexFile(String preUrlPath,List urlList){
try{
List filePathList = new ArrayList();
String uuid = UUID.randomUUID().toString().replaceAll("-","");
for(String urlpath:urlList){
URL url = new URL(preUrlPath+urlpath);
//下在资源
DataInputStream dataInputStream = new DataInputStream(url.openStream());
String fileOutPath = rootPath+File.separator+uuid+File.separator+urlpath;
File file = new File(rootPath+File.separator+uuid);
if(!file.exists()){
file.mkdirs();
}
FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath));
byte[] bytes = new byte[1024];
int length = 0;
while ((length = dataInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, length);
}
System.out.println("下载完成..."+fileOutPath);
dataInputStream.close();
filePathList.add(fileOutPath);
}
return filePathList;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
到这里基本大功告成了,写一个 main方法执行一下就ok了
private static String rootPath = "F:\\m3u8dir";
public static void main(String[] args) {
String indexPath = "https://youku.cdn2-youku.com/20180710/12991_efbabf56/1000k/hls/index.m3u8";
String prePath = indexPath.substring(0,indexPath.lastIndexOf("/")+1);
System.out.println(prePath);
//下载索引文件
String indexStr = getIndexFile(indexPath);
//解析索引文件
List videoUrlList = analysisIndex(indexStr);
//下载视频片段
List fileList = downLoadIndexFile(prePath,videoUrlList);
}
其实还可以补充一步代码合成,额不过着急看电影,就直接用格式工厂合成了,后面会补充
--------------------------------------------------------------------------------------------------------------------
补充代码,多线程的写法,上面的单线程太慢了,同时补充了一个文件合成的方法,不需要格式工厂了
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DownFileUtil {
private static String rootPath = "F:\\m3u8dir";
public static void main(String[] args) {
String indexPath = "https://youku.cdn2-youku.com/20180710/12991_efbabf56/1000k/hls/index.m3u8";
String prePath = indexPath.substring(0,indexPath.lastIndexOf("/")+1);
System.out.println(prePath);
//下载索引文件
String indexStr = getIndexFile(indexPath);
//解析索引文件
List videoUrlList = analysisIndex(indexStr);
//生成文件下载目录
String uuid = UUID.randomUUID().toString().replaceAll("-","");
String fileRootPath = rootPath+File.separator+uuid;
File fileDir = new File(fileRootPath);
if(!fileDir.exists()){
fileDir.mkdirs();
}
//下载视频片段,分成50个线程切片下载
HashMap keyFileMap = new HashMap();
int downForThreadCount = videoUrlList.size()/50;
for(int i=0;ivideoUrlList.size()){
end = videoUrlList.size()-1;
}
new DownFileUtil().new downLoadNode(videoUrlList,i,end,keyFileMap,prePath,fileRootPath).start();
}
//等待下载
while (keyFileMap.size() keyFileMap){
try {
FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath));
byte[] bytes = new byte[1024];
int length = 0;
for(int i=0;i list = new ArrayList();
while(ma.find()){
String s = ma.group();
list.add(s);
System.out.println(s);
}
return list;
}
class downLoadNode extends Thread{
private List list ;
private int start;
private int end;
public HashMap keyFileMap ;
private String preUrlPath ;
private String fileRootPath ;
public downLoadNode(List list,int start,int end,HashMap keyFileMap,String preUrlPath,String fileRootPath){
this.list = list;
this.end = end;
this.start = start;
this.keyFileMap = keyFileMap;
this.preUrlPath = preUrlPath;
this.fileRootPath = fileRootPath;
}
@Override
public void run(){
try{
String uuid = UUID.randomUUID().toString().replaceAll("-","");
for( int i = start;i<=end;i++){
String urlpath = list.get(i);
URL url = new URL(preUrlPath+urlpath);
//下在资源
DataInputStream dataInputStream = new DataInputStream(url.openStream());
String fileOutPath = fileRootPath+File.separator+urlpath;
FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath));
byte[] bytes = new byte[1024];
int length = 0;
while ((length = dataInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, length);
}
dataInputStream.close();
keyFileMap.put(i,fileOutPath);
}
System.out.println("第"+start/(end-start)+"组完成,"+"开始位置"+start+",结束位置"+end);
}catch (Exception e){
e.printStackTrace();
}
}
}
public static String getIndexFile(String urlpath){
try{
URL url = new URL(urlpath);
//下在资源
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(),"UTF-8"));
String content = "" ;
String line;
while ((line = in.readLine()) != null) {
content += line + "\n";
}
in.close();
System.out.println(content);
return content;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
补充:部分ts文件被加密的问题
第一步:找到解密的key,一般会在某个请求中返回(额找不到没法解密)
#EXT-X-KEY:METHOD=AES-128,URI="/20180125/NfJJpxIH/1482kb/hls/key.key"
第二步:根据 AES 对ts进行解密,java可以实现可以自行百度一下
技术交流qq群:208779755