初衷
當(dāng)我們需要下載一個軟件,我們一般會怎么做呢?
1.打開搜索引擎
2.輸入軟件的名稱
3.查看搜索結(jié)果
4.找到官方網(wǎng)站
5.下載
但是
如果我們需要下載的軟件并不是像QQ/迅雷/暴風(fēng)影音那么知名,被搜索引擎收錄
如果它是由個人開發(fā)而且根本就沒有官方網(wǎng)站呢
我們是不是就會想到到一些大的軟件下載網(wǎng)站去查詢
比如說:
1. ZOL下載
2. 華軍軟件園
3. 綠色軟件聯(lián)盟
......
但是,不知道大家有沒有遇到過這樣的情況
當(dāng)我們興沖沖地進入一個軟件的下載頁面以后...
每當(dāng)遇到這些不知道是廣告還是病毒的垃圾鏈接,總是會點錯
而且這些鏈接的樣子都和我們軟件真正的下載鏈接超級類似
稍微不小心就會點錯
而且點錯的后果一般都很嚴(yán)重,你的電腦就會被莫名其妙安裝上各種各樣亂七八糟的的軟件,而且還超級難卸載
對于和我一樣的對電腦有超級潔癖的小伙伴兒們來說
這怎么能忍...
一旦卸載不了...我一般就只好采取最暴力的手段---重裝系統(tǒng)
然后又超級苦逼地重裝一遍軟件
再配置一遍開發(fā)環(huán)境...
所以如果能有一個小工具能幫我們迅速地定位軟件的下載地址就太好了
這也是這個小工具產(chǎn)生的原因
非常歡迎大家一起來完善這個小工具幫助它成長,讓它能夠幫助到更多的人,希望產(chǎn)品能夠更加注重用戶體驗
基本信息與下載地址
簡介 :
一款幫你避免在下載軟件的時候誤點擊了錯誤的下載地址而被動下載了一些亂七八糟的軟件的工具,可以幫你迅速地定位網(wǎng)頁中真正的軟件的下載地址.非常歡迎大家一起來完善這個小工具幫助它成長,讓它能夠幫助到更多的人,希望產(chǎn)品能夠更加注重用戶體驗
Jar下載地址:
FindDownloadLinks1.0(2016/07/23)(該版本Bug眾多,已被作者廢棄)
FindDownloadLinks1.1(2016/07/24)(該版本Bug眾多,已被作者廢棄)
FindDownloadLinks1.2(2016/07/24)
FindDownloadLinks1.3(2016/07/25)
FindDownloadLinks1.4(2016/07/25)
FindDownloadLinks1.5(2016/07/25)
FindDownloadLinks1.6(2016/07/25)
FindDownloadLinks1.7(2016/07/25)
FindDownloadLinks1.8(2016/07/27)
使用方法:
1.下載源碼編譯運行
2.下載jar包,在命令行中輸入:java -jar 包路徑/包名
如:"java -jar e:/"
3.運行軟件,輸入軟件站的下載詳情頁的URL
4.點擊"開始分析"按鈕
5.稍等一到兩秒鐘,可以看到正確的下載地址被軟件成功解析
6.復(fù)制解析出的下載地址,使用下載工具進行下載
目前支持網(wǎng)站 :
1. JZ5U綠色下載站
2. 未來軟件園
3. 非凡軟件站
4. 華軍軟件園
5. 下載吧
6. 綠色下載站
7. 綠軟家園
8. 太平洋軟件下載中心
9. 多特軟件站
10. 統(tǒng)一下載站
環(huán)境支持:
需要安裝JRE(即java運行環(huán)境)
軟件截圖:
更新日志 :
- 2016/07/23(1.0版)
- 完成軟件基本架構(gòu),具有可擴展性
- 添加對未來軟件園和JZ5U綠色下載站的支持
- 2016/07/24(1.1版)
- 修復(fù)日志信息過長不能顯示的BUG
- 添加對非凡軟件站的支持
- 解決不同站點編碼不同造成的亂碼問題
- 添加對華軍軟件園的支持
- 2016/07/24(1.2版)
- 修復(fù)前兩個版本打包失敗無法使用的問題
- 完全修復(fù)所有支持網(wǎng)站的編碼問題
- 精簡jar包體積,從3M多減少到300k左右
- 2016/07/25(1.3版)
- 添加對下載吧的支持
- 優(yōu)化程序結(jié)構(gòu)(switch語句)
- 使用BASE64方式對下載鏈接進行解密
- 2016/07/25(1.4版)
- 添加對綠色下載站的支持
- 2016/07/25(1.5版)
- 添加對綠軟家園的支持
- 2016/07/25(1.6版)
- 修復(fù)onlinedown模塊對URL的處理中的BUG
- 添加對太平洋軟件下載中心的支持
- 2016/07/25(1.7版)
- 修復(fù)由于獲取軟件名失敗而導(dǎo)致無法正常解析下載鏈接的BUG
- 添加對多特軟件站的支持
- 2016/07/27(1.8版)
- 添加對統(tǒng)一下載站的支持
- 修復(fù)URL格式不正確時沒有提示信息的BUG
貢獻者名單(特別感謝)
原理/工作流程與源碼:
利用同一個站點不同軟件下載頁的結(jié)構(gòu)類似
只需要根據(jù)一部分頁面的結(jié)構(gòu)提取出規(guī)律
理論上來說
就可以對該網(wǎng)站所有下載頁面進行解析
并提取相關(guān)的軟件信息
工作流程:
1.用戶輸入URL,點擊"開始分析"按鈕
2.軟件根據(jù)用戶輸入的URL分析這個URL來自哪個軟件站
3.如果軟件不具有解析這個軟件站的能力,則提示用戶"暫不支持該網(wǎng)站!"
4.如果軟件具有解析該網(wǎng)站的能力,則開始進入解析階段
5.在解析階段中,首先將頁面的內(nèi)容下載至本地
6.然后對HTML代碼進行分析(一般來說同一個站點的頁面的規(guī)格類似,可以使用相同的解析規(guī)則來提取真正的下載鏈接)
7.同時分析HTML代碼提取軟件名稱
8.全部信息提取完成后,進行信息的顯示
代碼:
Github地址
1.Main.java
import javax.swing.*;
/**
* 主入口
* Created by 王一航 on 2016/7/23.
*/
public class Main extends JFrame{
/**
* 主入口
* @param args
*/
public static void main(String[] args) {
new MyFrame();
}
}
2.MyFrame.java
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* 主界面
* Created by 王一航 on 2016/7/23.
*/
public class MyFrame extends JFrame{
//全局變量
static java.util.List<String> resultDownloadLionks;
static String softwareName;
//聲明控件
JTextField jTextField_url;
JButton jButton_start;
JPanel jPanel_title;
//需要在外部更新日志
//TODO 考慮這種形式的合理性
static JTextArea jTextArea_result;
JScrollPane jScrollPane_result;
JPanel jPanel_result;
/**
* 構(gòu)造方法
*/
public MyFrame(){
initView();
setView();
addView();
initEvent();
}
/**
* 實例化控件
*/
private void initView() {
jTextField_url = new JTextField("請輸入URL");
jButton_start = new JButton("開始分析");
jPanel_title = new JPanel();
jTextArea_result = new JTextArea();
jScrollPane_result = new JScrollPane(jTextArea_result);
jPanel_result = new JPanel();
}
/**
* 設(shè)置控件屬性
*/
private void setView() {
jTextArea_result.setText("1.在上方文本框中輸入下載詳情頁的URL\n" +
"(例如:http://www.orsoon.com/Soft/14553.html)\n" +
"2.點擊\"開始分析\"按鈕\n" +
"3.稍等1-2秒鐘,在下方會解析出正確的下載鏈接\n");
jPanel_title.setLayout(new BorderLayout());
jPanel_result.setLayout(new BorderLayout());
this.setTitle("直接找到下載地址 By:王一航");
this.setLayout(new BorderLayout());
this.setSize(400,400);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* 添加控件從屬關(guān)系
*/
private void addView() {
jPanel_title.add(jTextField_url,BorderLayout.CENTER);
jPanel_title.add(jButton_start,BorderLayout.EAST);
jPanel_result.add(jScrollPane_result);
this.add(jPanel_title,BorderLayout.NORTH);
this.add(jPanel_result,BorderLayout.CENTER);
}
/**
* 添加監(jiān)聽事件
* 調(diào)度程序(核心)
*/
private void initEvent() {
jButton_start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//打印分隔符
jTextArea_result.append("**********************************************\n");
//TODO 業(yè)務(wù)邏輯
String url = jTextField_url.getText();
String module = "";//解析規(guī)則模式
String content = "";//待解析的解析網(wǎng)頁內(nèi)容
module = Utils.URLParser(url);
url = Utils.URLHandler(module,url);
if (!(module.equals(""))){//存在解析模塊可以解析
//日志
jTextArea_result.append("存在解析模塊 : " + module + ", 可以解析\n");
content = Utils.getContentAsString(url, module);
Document document = Jsoup.parse(content);
softwareName = Utils.getSoftwareName(module, document);
resultDownloadLionks = Utils.getDownloadLinks(module,document);
//日志
jTextArea_result.append("頁面名稱為(軟件名稱) : \n" + softwareName + "\n");
for (String res: resultDownloadLionks
) {
//日志
jTextArea_result.append("下載地址 : \n" + res + "\n");
}
}else{
//TODO 給用戶提示暫不支持此網(wǎng)站
//日志
jTextArea_result.append("暫不支持該網(wǎng)站!\n");
}
}
});
}
}
3.Utils.java
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
/**
* 工具類:
* Created by 王一航 on 2016/7/23.
*/
public class Utils {
/**
* URL解析器(解析URL并分發(fā)給對應(yīng)的模塊進行處理)
* @param url
* @return
*/
public static String URLParser(String url){
String modules = "";
if (url.contains("www.jz5u.com")){//jz5u綠色下載
modules = "jz5u";
}else if (url.contains("www.orsoon.com")){//未來軟件園
modules = "orsoon";
}else if (url.contains("www.crsky.com")){//非凡軟件站
modules = "crsky";
}else if (url.contains("www.onlinedown.net")){//華軍軟件園
modules = "onlinedown";
}else if (url.contains("www.xiazaiba.com")){//下載吧
modules = "xiazaiba";
}else if (url.contains("www.greenxiazai.com")){//綠色下載站
modules = "greenxiazai";
}else if (url.contains("www.downg.com")){//綠軟家園
modules = "downg";
}else if (url.contains("dl.pconline.com.cn")){//太平洋電腦網(wǎng)
modules = "pconline";
}else if (url.contains("www.duote.com")){//多特軟件站
modules = "duote";
}else if(url.contains("www.3987.com")){//統(tǒng)一下載站
modules = "3987";
}else {
modules = "";
}
return modules;
}
/**
* 獲取給定URL網(wǎng)頁內(nèi)容
* @param url
* @return
*/
public static String getContentAsString(String url, String modules){
//保存結(jié)果
String temp = "";
String content = "";
try {
//判斷URL是否正確
URL myUrl = new URL(url);
URLConnection urlConnection = myUrl.openConnection();
InputStream inputStream = urlConnection.getInputStream();
InputStreamReader inputStreamReader = null;
//TODO 解決不同網(wǎng)站編碼不同造成的亂碼問題
switch (modules){
case "jz5u":
case "xiazaiba":
case "crsky":
case "greenxiazai":
case "downg":
case "pconline":
case "duote":
inputStreamReader = new InputStreamReader(inputStream,"GBK");
break;
case "orsoon":
case "onlinedown":
case "3987":
inputStreamReader = new InputStreamReader(inputStream,"UTF-8");
break;
default:
//TODO 因為之前已經(jīng)對modules進行了篩選,理論上來說,是不會進入Default的
break;
}
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
while((temp =bufferedReader.readLine()) != null){
content = content + temp;
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
} catch (MalformedURLException e) {
MyFrame.jTextArea_result.append("輸入URL非法!請檢查是否以\"http://\"開頭");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//返回
return content;
}
/**
* 獲得頁面中所有的下載鏈接
* @param document
* @param modules
* @return 下載地址集合
*/
public static List<String> getDownloadLinks(String modules, Document document){
List<String> downloadLinks = new ArrayList<>();
switch (modules){
case "jz5u"://jz5u綠色下載
//選出真正DIV
Elements element_div = document.getElementsByClass("co_content5");
if (element_div.isEmpty()){//沒有獲取到下載地址
//TODO 將來給用戶提示
System.out.println("輸入網(wǎng)址有誤,請您檢查是否輸入地址是否是軟件的詳情頁");
}else{//成功解析到下載地址
Element element = element_div.get(0);
Elements a = element.getElementsByTag("a");
for (Element e: a) {
if (!(e.text().contains("高速")) && (e.text().contains("本地"))){
downloadLinks.add(e.attr("href"));
}
}
}
break;
case "orsoon"://未來軟件園
Element element_pc = document.getElementById("x_downfile");
String content = element_pc.toString();
int start_orsoon = content.indexOf("push('");
int end = content.indexOf("');");
String result = content.substring(start_orsoon + 6, end);
//TODO 完成安卓客戶端/蘋果客戶端
downloadLinks.add(result);
break;
case "crsky"://非凡軟件園
Elements elements_crsky = document.getElementsByAttribute("itemprop");
for (Element e: elements_crsky
) {
if (e.attr("itemprop").equals("downloadUrl")){
downloadLinks.add(e.attr("href"));
}
}
break;
case "onlinedown"://華軍軟件園
//剛好這個script標(biāo)簽在下載鏈接之前
Elements element_js_before = document.getElementsByAttributeValue("src", "http://d.onlinedown.net/php/ajax_ip_1.2.php");
Element onlinedown_true = element_js_before.get(0).nextElementSibling();
String onlinedown_true_links = onlinedown_true.toString();
int json_onlinedown_start = onlinedown_true_links.indexOf("var durl = ");
int json_onlinedown_end = onlinedown_true_links.indexOf("]");
String json_onlinedown = onlinedown_true_links.substring(json_onlinedown_start + 11,json_onlinedown_end + 1);
//解析json對象
JSONArray jsonArray = new JSONArray(json_onlinedown);
for(int i = 0; i < jsonArray.length(); i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
//TODO 分開下載鏈接和服務(wù)器地址信息
//TODO 加入javabean
downloadLinks.add(jsonObject.getString("url") + " 服務(wù)器地址 : " + jsonObject.getString("name"));
}
break;
case "xiazaiba":
String content_xiazaiba = document.toString();
int start_xiazaiba = content_xiazaiba.indexOf("downlist(");
int end_xiazaiba = content_xiazaiba.indexOf("','");
String temp_xiazaiba = content_xiazaiba.substring(start_xiazaiba, end_xiazaiba);
int temp_start_xiazaiba = temp_xiazaiba.indexOf("\",TypeID:\"");
int temp_end_xiazaiba = temp_xiazaiba.length();
String half_xiazaiba = temp_xiazaiba.substring(temp_start_xiazaiba + 2, temp_end_xiazaiba);
String full_xiazaiba = "http://xiazai.xiazaiba.com" + half_xiazaiba;
downloadLinks.add(full_xiazaiba);
break;
case "greenxiazai":
Elements elements_greenxiazai = document.getElementsByAttributeValue("onclick", "SetHome();");
for (Element e: elements_greenxiazai
) {
downloadLinks.add(e.attr("href"));
}
break;
case "downg":
Elements elements_downg = document.getElementsByClass("download-list");
Elements elements_downg_a = elements_downg.get(0).getElementsByTag("a");
for (Element e: elements_downg_a
) {
downloadLinks.add(e.attr("href"));
}
break;
case "pconline":
Elements elements_pconline = document.getElementsByAttribute("tempUrl");
for (Element e:elements_pconline
) {
if (e.attr("class").equals("link-a")){//屏蔽高速下載,只留下本地下載
downloadLinks.add(e.attr("tempUrl"));
}
}
break;
case "duote":
//TODO 添加對該網(wǎng)站手機模塊的支持(暫時只支持PC軟件網(wǎng)頁處理)
String content_duote = document.toString();
int start_duote = content_duote.indexOf("var sPubdown = '");
int ent_duote = content_duote.indexOf("var serUrl = '';");
String half_duote = content_duote.substring(start_duote + 16, ent_duote - 2);
downloadLinks.add(half_duote);
break;
case "3987":
Elements elements_3987 = document.getElementsByClass("dl-ico");
for (Element e: elements_3987
) {
Element element_3987 = e.nextElementSibling();
downloadLinks.add(element_3987.attr("href"));
}
break;
default:
break;
}
return downloadLinks;
}
/**
* 獲取軟件名稱
* @param modules
* @param document
* @return
*/
public static String getSoftwareName(String modules,Document document) {
String softwareName = "";
Elements title = document.getElementsByTag("title");
Element tile_element = title.get(0);
String title_string = tile_element.text();;
switch (modules){
case "jz5u":
if (title_string.contains("-")){
softwareName = title_string.split("-")[0];
}
break;
case "orsoon":
if (title_string.contains(" - ")){
softwareName = title_string.split(" - ")[0];
}
break;
case "crsky":
if (title_string.contains("下載_")){
softwareName = title_string.split("下載_")[0];
}
break;
case "onlinedown":
if (title_string.contains(" - ")){
softwareName = title_string.split(" - ")[0];
}
break;
case "xiazaiba":
case "greenxiazai":
String temp1_greenxiazai = title_string;
String temp2_greenxiazai = title_string;
if (title_string.contains("-")){
temp1_greenxiazai = title_string.split("-")[0];
}
if (title_string.contains("\\|")){
temp2_greenxiazai = temp1_greenxiazai.split("\\|")[1];//注 : '|'的轉(zhuǎn)義字符是'\\|'
}
softwareName = temp2_greenxiazai;
break;
case "downg":
//TODO 抽取軟件名
softwareName = title_string;
break;
case "pconline":
String temp1_pconline = title_string;
String temp2_pconline = title_string;
if (title_string.contains("\\【")){
temp1_pconline = title_string.split("\\【")[0];
}
if (title_string.contains("_")){
temp2_pconline = temp1_pconline.split("_")[1];
}
softwareName = temp2_pconline;
break;
case "duote":
String temp1_duote = title_string;
String temp2_duote = title_string;
if (title_string.contains("\\】")){
temp1_duote = title_string.split("\\】")[1];
}
if (title_string.contains("_")){
temp2_duote = temp1_duote.split("_")[0];
}
softwareName = temp2_duote;
break;
case "3987":
String temp1_3987 = title_string;
String temp2_3987 = title_string;
if (title_string.contains("_")){
temp1_3987 = title_string.split("_")[0];
}
if (title_string.contains("\\|")){
temp2_3987 = temp1_3987.split("\\|")[1];//注 : '|'的轉(zhuǎn)義字符是'\\|'
}
softwareName = temp2_3987;
break;
default:
softwareName = title_string;
break;
}
return softwareName;
}
/**
* URL處理(有的時候用戶需要多次跳轉(zhuǎn)才能到達真正的下載頁面)
* 功能: 直接跳轉(zhuǎn)到真正頁面
* @return
*/
public static String URLHandler(String module, String url) {
switch (module){
case "jz5u":
if (url.contains("html")){//判斷是否是真正的下載頁面(如果包含了html,有可能需要再跳轉(zhuǎn)一下)
String fileName = url.split("/")[url.split("/").length - 1];
int indexOfPoint = fileName.indexOf(".");
String fileNumber = fileName.substring(0, indexOfPoint);
url = "http://www.jz5u.com/Soft/softdown.asp?softid=" + fileNumber;
}
break;
case "onlinedown":
if (url.contains("htm") && (!url.contains("_"))) {//判斷是否是真正的下載頁面(如果包含了htm,有可能需要再跳轉(zhuǎn)一下)
String fileName = url.split("/")[url.split("/").length - 1];
int indexOfPoint = fileName.indexOf(".");
String fileNumber = fileName.substring(0, indexOfPoint);
url = "http://www.onlinedown.net/softdown/" + fileNumber + "_2.htm";
}
break;
case "pconline":
if (url.contains("html") && (!url.contains("-"))) {
String filename = url.split("/")[url.split("/").length - 1];
String fileNumber = filename.split("\\.")[0];
url = "http://dl.pconline.com.cn/download/" + fileNumber + "-1.html";
}
break;
default:
break;
}
return url;
}
/**
* Unicode轉(zhuǎn)中文
*/
public void unicodeToChinese(){
//TODO 完成編碼轉(zhuǎn)換(華軍軟件園)
}
/**
* base64加密
* @param content 明文
* @return 密文
*/
public static String myBASE64Encoder(String content){
String result;
BASE64Encoder base64Encoder = new BASE64Encoder();
result = base64Encoder.encodeBuffer(content.getBytes());
return result;
}
/**
* base64解密
* @param content 明文
* @return 密文
*/
public static String myBASE64Decoder(String content){
String result = "";
BASE64Decoder base64Decoder = new BASE64Decoder();
try {
byte[] bytes = base64Decoder.decodeBuffer(content);
result = new String(bytes, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
作者的話 :
最近會逐步更新,擴大支持的網(wǎng)站范圍
希望可以在這里可以獲得大家的喜歡和支持
一直認(rèn)為用戶體驗是一個軟件產(chǎn)品吸引用戶的核心
(其實不僅僅是軟件,任何一個產(chǎn)品都離不開與用戶的交互)
但是許多的網(wǎng)站并不是特別地注重這些,可能不得已還會做一些降低用戶效率的行為
但是這并不是最好的解決沖突的方法
希望可以呼吁更多的產(chǎn)品不要太注重眼前的利益
更注重用戶體驗才會吸引更多的用戶
尤其是在一個行業(yè)中,許多產(chǎn)品的功能都類似的情況下
如何才能吸引用戶,我覺得讓用戶在使用產(chǎn)品的過程中能不自覺的對產(chǎn)品產(chǎn)生依賴和感情
這很重要
這種依賴并不一定體現(xiàn)在用戶的停留時間
比如說對于一個工具類的網(wǎng)站
用戶來到這些網(wǎng)站的目的當(dāng)然是最快地找到自己需要的信息然后離開
而真正關(guān)心用戶體驗的網(wǎng)站應(yīng)該做的就是最迅速地檢索到用戶需要的信息或者是最迅速地幫助用戶解決他的問題
然后讓用戶心滿意足的離開
這才是這些網(wǎng)站的初衷
而不是為了增加廣告的點擊量來用一些類似下載鏈接的標(biāo)簽來迷惑用戶
這是在欺騙上帝呀...
這只會讓用戶對產(chǎn)品的印象越來越差
黏著力會大大降低
剛才說的,如果這種類型的網(wǎng)站可以迅速地幫用戶解決問題
從表面上看來,可能用戶滯留的時間降低了
但是可能用戶訪問的頻率會大大增加
用戶得到了非常滿意的服務(wù),他就極有可能把產(chǎn)品介紹給身邊的人
這樣產(chǎn)品的用戶量又會進一步增加
說了這么多
是真心希望可以有更多的產(chǎn)品可以站在用戶的角度
考慮用戶真正需要的是什么
用戶來到軟件下載站
最需要的當(dāng)然是直接下載自己需要的軟件然后迅速離開
如果網(wǎng)站可以制作成一個清爽的頁面中只有一個下載的按鈕
點擊就可以直接下載
那么該有多美好
最后
希望大家可以一起完善這個小工具
幫助它慢慢成長
讓它能幫助到更多的人
也希望大家可以喜歡
謝謝