这个是我发现的源码解析,快手,
package blog.rs1314.cn.test;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.script.ScriptException;
import blog.rs1314.cn.kuaishou.*;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class KuaiShouTest {
public static void main(String[] args) throws IOException, ScriptException {
long time = new Date().getTime();
long nextPageTime = KuaiShouNextPage.getNextPageTime(time);
KuaishouUserVo inputClientUrl = inputClientUrl("http://www.gifshow.com/s/6vyyITXo",0,time,nextPageTime);
List userVideoList = inputClientUrl.getUserVideoList();
System.out.println(userVideoList.size());
ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), Executors.defaultThreadFactory());
for(int j=0;j getVideoList(KuaishouUserVo kuaishouUserVo) {
KuaiShou kuaiShou = null;
String readVideoPlayUrl = kuaishouUserVo.getReadVideoPlayUrl();
JSONObject jsonObject = new JSONObject(readVideoPlayUrl);
System.out.println(jsonObject);
JSONArray feeds = jsonObject.getJSONArray("feeds");
int length = feeds.length();
List kuaiShouList = new ArrayList(length);
for (int j = 0; j < length; j++) {
kuaiShou = new blog.rs1314.cn.kuaishou.KuaiShou();
try {
JSONObject jsonObject1 = feeds.getJSONObject(j);
//无水印频地址
JSONArray main_mv_urls = jsonObject1.getJSONArray("main_mv_urls");
JSONObject jsonObject2 = main_mv_urls.getJSONObject(0);
String videoUrl = jsonObject2.getString("url");
kuaiShou.setVideoUrl(videoUrl);
//share_info ("userId=3xwvjr74prbhz9s&photoId=3xfvvjb92hqpgdq",)
String share_info = jsonObject1.getString("share_info");
kuaiShou.setShare_info(share_info);
String photoId = String.valueOf(jsonObject1.get("photo_id"));
kuaiShou.setPhotoId(photoId);
//视频名称
String videoName = jsonObject1.getString("caption");
videoName = videoName.replaceAll("\n", "").replaceAll(" ", "");
kuaiShou.setVideoName(videoName);
}catch (Exception e){}
kuaiShouList.add(kuaiShou);
}
return kuaiShouList;
}
/**
* 获取真实无水印视频地址json
*
* @param kuaishouUserVo
* @return
*/
private static String getReadVideoPlayUrl(KuaishouUserVo kuaishouUserVo) {
Map sigUrlamap = kuaishouUserVo.getSigUrl();
String queryStringUrl = sigUrlamap.get(QUERYSTRING);
String bodyString = sigUrlamap.get(BODYSTRING);
OkHttpClient okHttpClient = new OkHttpClient();
FormBody.Builder requestBody = new FormBody.Builder();
Map params = getMapFromStr(bodyString);
Set keySet = params.keySet();
for (String key : keySet) {
String value = params.get(key);
requestBody.add(key, value);
}
FormBody formBody = requestBody.build();
Request request = new Request.Builder()
.url(READURL + queryStringUrl)
.post(formBody)
.addHeader("Cookie", "token=988045ae46624450873917df582dfd43-1355462031")
.addHeader("User-Agent", "kwai-android")
.addHeader("Connection", "keep-alive")
.addHeader("Accept-Language", "zh-cn")
.addHeader("X-REQUESTID", randomRequestId())
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Host", "api.ksapisrv.com")
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
return response.body().string();
} catch (IOException e) {
throw new RuntimeException("地址错误或者获取失败,联系Q群号414572608");
}
}
/**
* 第二步
* 1. 用户输入的分享地址 ,获取重定向后的地址
* 2. 获取用户加密id和加密后作品id
* 3. 获取真实的用户id
* 4. 得到sig后的请求连接,post请求
* 5.获取真实无水印视频地址json
* 6.获取List
*/
private static KuaishouUserVo inputClientUrl(String url,int temp,long time,long nexttime) {
KuaishouUserVo kuaishouUserVo = new KuaishouUserVo();
try {
//用户输入的分享地址 ,获取重定向后的地址
String redirectUrl = new OkHttpClient().newCall(new Request.Builder().url(url).build()).execute().request().url().toString();
redirectUrl = redirectUrl.substring(0, redirectUrl.indexOf("?"));
//获取用户加密id和加密后作品id
String regex = "https://live.kuaishou.com/u/";
redirectUrl = redirectUrl.substring(redirectUrl.indexOf(regex) + regex.length());
String[] split = redirectUrl.split("/");
kuaishouUserVo.setUserIdJiaMi(split[0]);
kuaishouUserVo.setPhotoId(split[1]);
//获取真实的用户id
kuaishouUserVo.setUserId(getUserId(split[0]));
if(temp ==0){
//得到sig后的请求连接,post请求
Map sigUrl = getSigUrl(kuaishouUserVo.getUserId());
kuaishouUserVo.setSigUrl(sigUrl);
}else{
Map sigUrl = getSigUrl(kuaishouUserVo.getUserId(),time,1,nexttime);
kuaishouUserVo.setSigUrl(sigUrl);
}
//获取真实无水印视频地址json
String readVideoPlayUrl = getReadVideoPlayUrl(kuaishouUserVo);
kuaishouUserVo.setReadVideoPlayUrl(readVideoPlayUrl);
//获取list
List videoList = getVideoList(kuaishouUserVo);
kuaishouUserVo.setUserVideoList(videoList);
return kuaishouUserVo;
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("地址错误或者获取失败,联系Q群号414572608");
}
}
/**
* 第一步:: 设置存活时间 token 建议60分钟请求一次
*
* @throws IOException
*/
private static void setttingLiveTime() {
String url = "http://api.ksapisrv.com/rest/n/hybrid/version?mod=HUAWEI%28COL-AL10%29&appver=6.4.1.9151&isp=CMCC&lon=0&language=zh-cn&sys=ANDROID_9&__NStokensig=30384a09fe4d364d48a9be9f182f80e76e964f870fedbd537a7a009ecd5dd60d&max_memory=384&ud=1355462031&sig=9c303bd81cc2c0575cecb7bc385c89c5&client_key=3c2cd3f3&oc=HUAWEI_KWAI&net=WIFI&lat=0&app=0&kpf=ANDROID_PHONE&ver=6.4&c=HUAWEI_KWAI&os=android&ftt=&kpn=KUAISHOU&token=988045ae46624450873917df582dfd43-1355462031&country_code=cn&hotfix_ver=&did_gt=1557994638922&iuid=&did=ANDROID_03c600e64ee0e3a7";
Request build = new Request.Builder().url(url).addHeader("Cookie", "token=988045ae46624450873917df582dfd43-1355462031")
.addHeader("User-Agent", "kwai-android")
.addHeader("Connection", "keep-alive")
.addHeader("Accept-Language", "zh-cn")
.addHeader("X-REQUESTID", randomRequestId())
.addHeader("Host", "api.ksapisrv.com")
.build();
String html = "";
try {
html = new OkHttpClient().newCall(build).execute().body().string();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(html);
}
/**
* 随机请求id //范围是 436650000 - 436669999
*
* @return
*/
private static String randomRequestId() {
int temp = 436669999 - 436650000;
int nextInt = new Random().nextInt(temp) + 436650000;
return String.valueOf(nextInt);
}
/**
* https://live.kuaishou.com/u/3xwvjr74prbhz9s
* 获取真实的用户id
*
* @param userIdjiaMi 3xwvjr74prbhz9s
* @return
*/
public static String getUserId(String userIdjiaMi) {
String url = "https://live.kuaishou.com/u/" + userIdjiaMi;
String temp = "";
try {
String html = new OkHttpClient().newCall(new Request.Builder().url(url).build()).execute().body().string();
Document parse = Jsoup.parse(html);
Elements eles = parse.getElementsByTag("script");
for (Element ele : eles) { //configModel
String script = ele.toString();
if (script.indexOf("configModel") > -1) {
script = script.substring(script.indexOf("liveDetailModel") + 18, script.lastIndexOf("webSocketInfo") + 18);
JSONObject jsonObject = new JSONObject(script);
jsonObject = jsonObject.getJSONObject("user");
Object object = jsonObject.get("userId");
temp = String.valueOf(object);
}
}
return temp;
} catch (IOException e) {
throw new RuntimeException("地址错误或者获取失败,联系Q群号414572608");
}
}
/**
* 获取签名后的请求连接
*
* @param userid 真实的用户id post请求
* @return
*/
public static Map getSigUrl(String userid) {
long time = new Date().getTime();
return getSigUrl(userid,time,0,0);
}
public static Map getSigUrl(String userid,long time,int temp,long nexttime) {
if(temp == 0){
Map sig = getSig(userid, time, 30);
String genSignature = genSignature(getMapFromStr(sig.get(SIGSTRING)), FANS_SALT);
sig = getSigUrlT(userid, time, 30, genSignature);
return sig;
}else{
Map sig = getSignextPage(userid, time, 30,nexttime);
String genSignature = genSignature(getMapFromStr(sig.get(SIGSTRING)), FANS_SALT);
sig = getSigUrlT(userid, time, 30, genSignature);
return sig;
}
}
/**
* Post请求 异步
* 使用 Callback 回调可返回子线程中获得的网络数据
*
* @param url
* @param params 参数
*/
public static void httpPost(final String url, final Map params, final Callback callback) {
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient okHttpClient = new OkHttpClient();
FormBody.Builder formBodyBuilder = new FormBody.Builder();
Set keySet = params.keySet();
for (String key : keySet) {
String value = params.get(key);
formBodyBuilder.add(key, value);
}
FormBody formBody = formBodyBuilder.build();
Request request = new Request
.Builder()
.post(formBody)
.url(url)
.build();
//Response response = null;
okHttpClient.newCall(request).enqueue(callback);
}
}).start();
}
public static String genSignature(Map params, String salt) {
if (params == null) {
return null;
}
String sign = "";
StringBuffer sb = new StringBuffer();
try {
// 1. 字典升序排序
SortedMap sortedMap = new TreeMap<>(params);
// 2. 拼按URL键值对
Set keySet = sortedMap.keySet();
for (String key : keySet) {
//sign不参与算法
if (key.equals("sig") || key.equals("__NStokensig")) {
continue;
}
String value = sortedMap.get(key);
sb.append(key + "=" + URLDecoder.decode(value, "UTF-8"));
}
String uriString = sb.toString();
uriString = uriString + salt;
//System.out.println("My String: \n" + uriString);
// 3. MD5运算得到请求签名
sign = MD5.md5(uriString);
//System.out.println("My Sign:\n" +sign);
} catch (Exception e) {
e.printStackTrace();
}
return sign;
}
public static Map getMapFromStr(String str) {
if (str == null || "".equalsIgnoreCase(str)) {
return null;
}
String[] arr = str.split("\\&");
Map map = new HashMap<>();
for (String item : arr) {
String[] itemArr = item.split("=", 2);
map.put(itemArr[0], itemArr[1]);
}
return map;
}
private static Map getSig(String userid, long time, int size) {
return getSigUrlT(userid, time, size, "001a0805a029a8a466f8492a37d077ae");
}
private static Map getSignextPage(String userid, long time, int size,long neexrtime) {
return getSigUrlTnextPage(userid, time, size, "001a0805a029a8a466f8492a37d077ae",neexrtime);
}
private static Map getSigUrlTnextPage(String userid, long time, int size, String sig,long neexrtime) {
String queryString = "app=0&kpf=ANDROID_PHONE&ver=6.4&c=HUAWEI_KWAI&mod=HUAWEI%28COL-AL10%29&appver=6.4.1.9151&ftt=&isp=CMCC&kpn=KUAISHOU&lon=0&language=zh-cn&sys=ANDROID_9&max_memory=384&ud=1355462031&country_code=cn&oc=HUAWEI_KWAI&hotfix_ver=&did_gt=" + time + "&iuid=&net=WIFI&did=ANDROID_03c600e64ee0e3a7&lat=0";
String bodyString = "token=988045ae46624450873917df582dfd43-1355462031&user_id=" + userid + "&lang=zh&count=" + size + "&privacy=public&pcursor="+neexrtime+"&referer=1&browseType=1&sig=" + sig + "&client_key=3c2cd3f3&os=android&__NStokensig=8581c63e468fa7829def9cf79fdebae7fc8f15dd021aa68724928c86872dc554";
String sigString = new StringBuilder().append(queryString).append("&").append(bodyString).toString();
Map map = new HashMap();
map.put(QUERYSTRING, queryString);
map.put(BODYSTRING, bodyString);
map.put(SIGSTRING, sigString);
return map;
}
private static Map getSigUrlT(String userid, long time, int size, String sig) {
String queryString = "app=0&kpf=ANDROID_PHONE&ver=6.4&c=HUAWEI_KWAI&mod=HUAWEI%28COL-AL10%29&appver=6.4.1.9151&ftt=&isp=CMCC&kpn=KUAISHOU&lon=0&language=zh-cn&sys=ANDROID_9&max_memory=384&ud=1355462031&country_code=cn&oc=HUAWEI_KWAI&hotfix_ver=&did_gt=" + time + "&iuid=&net=WIFI&did=ANDROID_03c600e64ee0e3a7&lat=0";
String bodyString = "token=988045ae46624450873917df582dfd43-1355462031&user_id=" + userid + "&lang=zh&count=" + size + "&privacy=public&referer=1&browseType=1&sig=" + sig + "&client_key=3c2cd3f3&os=android&__NStokensig=8581c63e468fa7829def9cf79fdebae7fc8f15dd021aa68724928c86872dc554";
String sigString = new StringBuilder().append(queryString).append("&").append(bodyString).toString();
Map map = new HashMap();
map.put(QUERYSTRING, queryString);
map.put(BODYSTRING, bodyString);
map.put(SIGSTRING, sigString);
return map;
}
private static final String QUERYSTRING = "queryString";
private static final String BODYSTRING = "bodyString";
private static final String SIGSTRING = "sigString";
private static final String FANS_SALT = "382700b563f4";
private static final String READURL = "http://api.ksapisrv.com/rest/n/feed/profile2?";
}
这个原文链接 http://blog.rs1314.cn/article/detail/36