├── .gitignore ├── .idea └── .gitignore ├── README.md ├── pom.xml ├── src └── main │ └── java │ └── com │ └── hoyoung │ └── CrawHelper │ ├── Helper │ ├── LanzouHelper.java │ └── XiaoHongShuHelper.java │ └── common │ ├── constant │ └── ContentTypeConstant.java │ ├── entity │ ├── CommonCrawEntity.java │ ├── LanzouCrawEntity.java │ └── XHSCrawEntity.java │ ├── enums │ └── EntityTypeEnum.java │ └── utils │ ├── HeaderUtil.java │ └── UAGenerator.java └── target └── CrawHelper-1.0-SNAPSHOT.jar /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 蓝奏云直链获取工具 2 | 3 | ##### lanzou direct link Helper 4 | 5 | ~~一开始是想找个解析工具放在Android app里用来更新的,但发现Java版本的最短的都一年没有更新了,还是自己摸个简单的能用就好。单Java类,拷走就能用~~ 6 | 7 | 该项目正无人期待的火热重写中~ 8 | 之前单Java类是方便了,但实在是十分耦合,结构不堪入目,刚开始工作,边学习边重写一下项目结构ing 9 | 改成jar包的形式发布,可直接下载target下的jar包食用,也可以自己folk打包 10 | - 依赖 okhttp3,jsoup 11 | - 支持新旧两种蓝奏云页面,文件名、大小和直链 12 | 13 | 如果这有帮助到你,请你点个 **Star** 让我知道吧 :) 14 | 15 | **Example:** 16 | 17 | ```java 18 | class Test { 19 | 20 | public static void main(String[] args) { 21 | ArrayList urls = new ArrayList<>(); 22 | //企业链接 23 | urls.add("https://macwk.lanzouo.com/iRH0wwq0m8d"); 24 | //个人链接 25 | urls.add("https://vincentapps.lanzouo.com/i4uS3lmp56j"); 26 | 27 | //输出 28 | urls.stream().map(LanzouHelper::getLink).forEach(System.out::println); 29 | 30 | /** 31 | * LanzouEntity{name='Karabiner-Elements_14.3.0_(最低11.0)__macwk.com.dmg', size='9.8 M'} , {dlLinks=[https://develope.lanzoug.com/file/?AWdSbFprVGVUXQA4V2JUOFZpBj4FEQdkAXRbPFFvWjIHaVtpDSIBeAUWBD4ENV0xUG9TOAUuBndVDVBnAWlbdAEyUitaN1RfVCoAsFefVNVW6Aa+BdQHNAE3W3NRPVpyB1hbUw09ATQFMAQlBDtdclBpUzkFNwYqVTZQOwE6W3wBZ1JsWmtUZVRdAD9XZ1RoVjkGNQVsBz0BP1tsUTpaaAchW2oNIwFoBWEEYgRnXWpQMlNgBWIGMlV0UCYBLVtnATNSNVo1VDFULQBnVzJUelY+BjIFdQc3ATZbZFFuWj0HY1s6DTIBbQVjBGoEYl1rUDhTZgVuBmBVN1BlAWpbaQFgUjFaYlRhVDoAZVdnVGVWaAYzBTwHKwFiWzBRalp9B3Jbfw01AScFOgQ2BG1dZFAzU2AFagY3VWZQcAEpWzMBbFJgWmFUPVQzAGBXNVRlVjwGOgVvBzABN1trUSNadQchW2oNPAEiBW4EYwRmXWlQM1NvBW4GPVVgUG8BZFt8AXRSdVpwVD1UMwBgVzBUYlY4BjYFaQcwATdbZFErWi4Hblt8DW0BZAVnBHwEYl1qUCRTZwVsBipVa1Bi]} 32 | * LanzouEntity{name='JDCookie.apk', size='2.6 M'} , {dlLinks=[https://develope.lanzoug.com/file/?UDZSbF5vAjMGD1FpBzJdMVNsV29RRFQSC09QOVRnVz0BaFFjAXICNwQiUG0HdVYxAzBUPV5kBVhWOFU3AWAHNVBoUjVeNgJuBmVRMgdqXXpTb1chUTNUZAs7UGNUP1duATNRNgF6AiYEIlA7B2FWZwNrVGBeLgU3VmNVfAFsBzVQf1IyXjICNQYxUWQHMV09UzlXYVE2VGYLO1BhVGpXZwE3UTEBbAJkBGpQZAdlVjIDblRiXmcFMlZnVTABOQdjUDFSK15iAiYGO1EhByZdL1NsVyBRZ1QyCzFQYFQ8V2UBNVEzAWsCcAQmUG8HPlYyAz9UbF4wBTFWZ1VjAW0HP1BlUjBeMgJhBn5RKQd1XTpTZVclUTNUZws6UGBUOFdmATBRMgFoAmEEZVAgByZWJwMuVGxeMAUxVmBVYAFvBzZQYlIwXjoCZAZ2UXIHOl0sUzRXY1E6VHgLPlBgVCZXZwE3USgBZQJi]} 33 | */ 34 | } 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | groupId 8 | CrawHelper 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 8 13 | 8 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.jsoup 21 | jsoup 22 | 1.14.3 23 | 24 | 25 | com.squareup.okhttp3 26 | okhttp 27 | 4.9.2 28 | 29 | 30 | 31 | 32 | com.alibaba 33 | fastjson 34 | 1.2.83 35 | 36 | 37 | cn.hutool 38 | hutool-all 39 | 5.7.7 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/Helper/LanzouHelper.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.Helper; 2 | 3 | import com.hoyoung.CrawHelper.common.entity.LanzouCrawEntity; 4 | import com.hoyoung.CrawHelper.common.utils.HeaderUtil; 5 | import okhttp3.*; 6 | import org.jsoup.Jsoup; 7 | import org.jsoup.nodes.Document; 8 | import org.jsoup.select.Elements; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.regex.Matcher; 13 | import java.util.regex.Pattern; 14 | 15 | /** 16 | * 蓝奏下载直接链接获取工具 17 | * 调用 getResource() 即可 18 | * 19 | * @author Hoyoung 20 | */ 21 | public class LanzouHelper { 22 | static final Pattern mainHostRegex = Pattern.compile("(?<=http://|\\.)[^.]*?\\.(?:com\\.cn|net\\.cn|org\\.cn|com|net|org|cn|biz|info|cc|tv)", Pattern.CASE_INSENSITIVE); 23 | static final Pattern fullHostRegex = Pattern.compile("[^//]*?\\.(com|cn|net|org|biz|info|cc|tv)", Pattern.CASE_INSENSITIVE); 24 | 25 | private LanzouHelper() { 26 | } 27 | 28 | public static LanzouCrawEntity getResource(String url) { 29 | 30 | String fullHost = getFullHost(url); 31 | 32 | // 添加蓝奏云特有的header 33 | Headers headers = new HeaderUtil.Generator().set("Upgrade-Insecure-Requests", "1").setReferer(url).generate().build(); 34 | 35 | String name = null, size = null; 36 | try { 37 | // 加载页面 38 | Document doc = Jsoup.connect(url).get(); 39 | 40 | // 获取文件名和大小 41 | Elements title1 = doc.select("div[style=font-size: 30px;text-align: center;padding: 56px 0px 20px 0px;]"); 42 | if (title1.size() != 0) { 43 | name = title1.get(0).html(); 44 | } else { 45 | name = doc.select("#filenajax").html(); 46 | } 47 | 48 | Elements size1 = doc.select("meta[name=description]"); 49 | if (size1.size() != 0) { 50 | size = regex(size1.attr("content"), "\\d.\\d(?: )*[A-Za-z]+"); 51 | } 52 | 53 | // 获取与拼接下载页(iframe)地址 54 | Elements realPage = doc.select("iframe"); 55 | String realUrl = "https://" + fullHost + realPage.attr("src"); 56 | doc = Jsoup.connect(realUrl).get(); 57 | 58 | // 正则分析动态参数 59 | String js = doc.select("script[type=text/javascript]").get(1).html(); 60 | String sign = getValue("sign", js); 61 | String action = getValue("action", js); 62 | String signs = getValue("ajaxdata", js); 63 | String webSignKey = getValue("cwebsignkeyc", js); 64 | String webSign = ""; 65 | String apiUrl = "https://" + fullHost + getValue("url", js); 66 | 67 | // OkHttp 获取直链 68 | OkHttpClient client = new OkHttpClient(); 69 | FormBody.Builder builder = new FormBody.Builder(); 70 | builder.add("sign", sign) 71 | .add("action", action) 72 | .add("signs", signs) 73 | .add("websign", webSign) 74 | .add("websignkey", webSignKey) 75 | .add("ves", "1"); 76 | RequestBody formBody = builder.build(); 77 | Request request = new Request.Builder() 78 | .url(apiUrl) 79 | .post(formBody) 80 | .headers(headers) 81 | .build(); 82 | String dl; 83 | try (Response response = client.newCall(request).execute()) { 84 | if (!response.isSuccessful()) { 85 | throw new IOException("Unexpected code " + response); 86 | } 87 | String body = response.body().string(); 88 | dl = getValue("dom", body).replace("\\/", "/") + "/file/" + getValue("url", body).replace("\\/", "/"); 89 | } 90 | 91 | // 返回蓝奏云对象 92 | LanzouCrawEntity lanzouCrawEntity = new LanzouCrawEntity(name, size, dl); 93 | return lanzouCrawEntity; 94 | } catch (IOException e) { 95 | e.printStackTrace(); 96 | } 97 | 98 | return null; 99 | } 100 | 101 | /** 102 | * 正则匹配js中设定值,或者匹配json 103 | * eg: var key = value; 104 | * 105 | * @param key 106 | * @param json 107 | * @return 108 | */ 109 | private static String getValue(String key, String json) { 110 | return regex(json, "(?<=" + key + "['\"]?( )?[:=]( )?['\"]).+?(?=['\"])"); 111 | } 112 | 113 | private static String getMainHost(String url) { 114 | Matcher matcher = mainHostRegex.matcher(url); 115 | if (matcher.find()) { 116 | return (matcher.group()); 117 | } 118 | return null; 119 | } 120 | 121 | private static String regex(String words, String regex) { 122 | Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); 123 | Matcher matcher = p.matcher(words); 124 | if (matcher.find()) { 125 | return (matcher.group()); 126 | } 127 | return null; 128 | } 129 | 130 | private static String getFullHost(String url) { 131 | Matcher matcher = fullHostRegex.matcher(url); 132 | if (matcher.find()) { 133 | return (matcher.group()); 134 | } 135 | return null; 136 | } 137 | 138 | public static void main(String[] args) { 139 | ArrayList urls = new ArrayList<>(); 140 | //企业链接 141 | urls.add("https://macwk.lanzouo.com/iRH0wwq0m8d"); 142 | //个人链接 143 | urls.add("https://vincentapps.lanzouo.com/i4uS3lmp56j"); 144 | 145 | //输出 146 | urls.stream().map(LanzouHelper::getResource).forEach(System.out::println); 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/Helper/XiaoHongShuHelper.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.Helper; 2 | 3 | import com.hoyoung.CrawHelper.common.entity.XHSCrawEntity; 4 | 5 | /** 6 | * 小红书下载工具 7 | * @author Hoyoung 8 | */ 9 | public class XiaoHongShuHelper { 10 | private XiaoHongShuHelper() { 11 | } 12 | 13 | public static XHSCrawEntity getResource(String url){ 14 | 15 | return null; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/common/constant/ContentTypeConstant.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.common.constant; 2 | 3 | /** 4 | * ContentType请求头常量 5 | * 6 | * @author Hoyoung 7 | */ 8 | public class ContentTypeConstant { 9 | public final static String JSON = "application/json"; 10 | public final static String RAW = "text/plain"; 11 | public final static String JS = "application/javascript"; 12 | public final static String XML = "application/xml"; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/common/entity/CommonCrawEntity.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.common.entity; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 通用实体对象 7 | * dlLink 8 | * @author Hoyoung 9 | */ 10 | public class CommonCrawEntity { 11 | public CommonCrawEntity() { 12 | } 13 | 14 | public CommonCrawEntity(List dlLinks) { 15 | this.dlLinks = dlLinks; 16 | } 17 | 18 | private List dlLinks; 19 | 20 | /** 21 | * 如果明确下载的文件格式,建议指定,以防下载服务器未指定文件后缀名 22 | */ 23 | private String suffix; 24 | 25 | public String getSuffix() { 26 | return suffix; 27 | } 28 | 29 | public void setSuffix(String suffix) { 30 | this.suffix = suffix; 31 | } 32 | 33 | public List getDlLinks() { 34 | return dlLinks; 35 | } 36 | 37 | public void setDlLinks(List dlLinks) { 38 | this.dlLinks = dlLinks; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return ", {" + 44 | "dlLinks=" + dlLinks + 45 | ", suffix='" + suffix + '\'' + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/common/entity/LanzouCrawEntity.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.common.entity; 2 | 3 | 4 | import com.hoyoung.CrawHelper.common.enums.EntityTypeEnum; 5 | 6 | import java.util.Collections; 7 | 8 | /** 9 | * 蓝奏云实体对象 10 | * @author Hoyoung 11 | */ 12 | public class LanzouCrawEntity extends CommonCrawEntity { 13 | public LanzouCrawEntity() { 14 | } 15 | 16 | public LanzouCrawEntity(String name, String size, String dl) { 17 | this.name = name; 18 | this.size = size; 19 | // 默认不设置后缀 20 | this.setSuffix(EntityTypeEnum.UNKNOWN.getSuffix()); 21 | this.setDlLinks(Collections.singletonList(dl)); 22 | } 23 | 24 | private String name; 25 | private String size; 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public String getSize() { 36 | return size; 37 | } 38 | 39 | public void setSize(String size) { 40 | this.size = size; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "LanzouEntity{" + 46 | "name='" + name + '\'' + 47 | ", size='" + size + '\'' + 48 | "} " + super.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/common/entity/XHSCrawEntity.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.common.entity; 2 | 3 | /** 4 | * 小红书实体对象 5 | * 6 | * @author Hoyoung 7 | */ 8 | public class XHSCrawEntity extends CommonCrawEntity { 9 | private String username; 10 | private String signature; 11 | private String avatar; 12 | 13 | public XHSCrawEntity(String username, String signature, String avatar) { 14 | this.username = username; 15 | this.signature = signature; 16 | this.avatar = avatar; 17 | } 18 | 19 | public String getUsername() { 20 | return username; 21 | } 22 | 23 | public void setUsername(String username) { 24 | this.username = username; 25 | } 26 | 27 | public String getSignature() { 28 | return signature; 29 | } 30 | 31 | public void setSignature(String signature) { 32 | this.signature = signature; 33 | } 34 | 35 | public String getAvatar() { 36 | return avatar; 37 | } 38 | 39 | public void setAvatar(String avatar) { 40 | this.avatar = avatar; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/common/enums/EntityTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.common.enums; 2 | 3 | /** 4 | * 下载格式枚举 5 | * @author Hoyoung 6 | */ 7 | 8 | public enum EntityTypeEnum { 9 | // 不知道写什么 10 | IMG("jpg","图片"), 11 | VIDEO("mp4","视频"), 12 | APK(".apk","安卓安装包文件"), 13 | IPA(".ipa","苹果安装包文件"), 14 | EXE(".exe","Windows安装包文件"), 15 | DMG(".dmg","Mac安装包文件"), 16 | MUSIC(".mp3","音乐"), 17 | UNKNOWN("","由服务器决定"); 18 | 19 | private String suffix; 20 | private String desc; 21 | 22 | EntityTypeEnum(String suffix, String desc) { 23 | this.suffix = suffix; 24 | this.desc = desc; 25 | } 26 | 27 | public String getSuffix() { 28 | return suffix; 29 | } 30 | 31 | public void setSuffix(String suffix) { 32 | this.suffix = suffix; 33 | } 34 | 35 | public String getDesc() { 36 | return desc; 37 | } 38 | 39 | public void setDesc(String desc) { 40 | this.desc = desc; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/common/utils/HeaderUtil.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.common.utils; 2 | 3 | import okhttp3.Headers; 4 | 5 | /** 6 | * OkHttp3通用 随机UA 请求头生成 7 | * 8 | * @author Hoyoung 9 | */ 10 | public class HeaderUtil { 11 | private Headers.Builder builder; 12 | 13 | /** 14 | * 默认Header 15 | */ 16 | private HeaderUtil() { 17 | builder = new Headers.Builder(); 18 | builder.set("Accept", "*/*"); 19 | builder.set("Accept-Encoding", "gzip, deflate, br"); 20 | builder.set("accept-language", "zh-CN,zh;q=0.9,zh-TW;q=0.8,en-US;q=0.7,en;q=0.6,ja;q=0.5"); 21 | } 22 | 23 | public static class Generator { 24 | Headers.Builder builder = new HeaderUtil().builder; 25 | 26 | public Generator() { 27 | builder.set("User-Agent", UAGenerator.randomOneUA()); 28 | } 29 | 30 | public Generator setUA(String ua) { 31 | builder.set("User-Agent", ua); 32 | return this; 33 | } 34 | 35 | public Generator setReferer(String refer) { 36 | builder.set("referer", refer); 37 | return this; 38 | } 39 | 40 | public Generator setContentType(String ct) { 41 | builder.set("Content-Type", ct); 42 | return this; 43 | } 44 | 45 | public Generator set(String key, String value) { 46 | builder.set(key, value); 47 | return this; 48 | } 49 | 50 | 51 | public Headers.Builder generate() { 52 | return builder; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/hoyoung/CrawHelper/common/utils/UAGenerator.java: -------------------------------------------------------------------------------- 1 | package com.hoyoung.CrawHelper.common.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | 7 | /** 8 | * 随机UA生成 9 | * @author Hoyoung 10 | */ 11 | public class UAGenerator { 12 | static private List uaList = new ArrayList<>(); 13 | 14 | static { 15 | uaList.add("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"); 16 | uaList.add("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"); 17 | uaList.add("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36 Edg/104.0.1293.47"); 18 | } 19 | 20 | static List uaList(){ 21 | return uaList; 22 | } 23 | 24 | static String randomOneUA(){ 25 | return uaList.get(new Random().nextInt(uaList.size())); 26 | } 27 | 28 | private UAGenerator() { 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /target/CrawHelper-1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qwe1187292926/LanzouHelper/ed5db3d1c3d2a271fbf54ba4008316adca9d4227/target/CrawHelper-1.0-SNAPSHOT.jar --------------------------------------------------------------------------------