本篇文章是 Robert 發表分享在JavaWorld 的文章
由於嚮往 xlinx 大的 [網路]自製 抓DCVIEW攝影 照片 程式 簡單好用 [一按鈕搞定]
剛下載來時,那時程式還是可以正常使用的,但是我的程度太差,完全看不懂,
最近想說再來研究一番,但程式卻已無法正常執行了,
研究了半天,
也不是搞得很清楚,於是自己寫寫看,
順便了解一下基本的原理,
當然無法像 xlinx 大的那樣可以自動登入與下載與識別圖片。
只有簡單的所見即所得的,看的到就抓得到。
由於寫程式的時候遇到很多問題,都是參考網站上的相關經驗。
且受益良多,於是野人獻曝地
把自己完成的東西也放上來分享與記錄自己。
使用&功能說明:
1.貼上目標網址,再按下[執行]即可下載。
2.預
設會在程式的所在資料夾下再建立一個 pic 的資料夾放置圖片。
3.預設下載 20 KB 以上的圖片,重複的檔案將被複寫。
4.點選
Table中每一行的fileName部分,可預覽下載完成的圖片。
PS:
1.本程式僅供 java
技術測試與分享,其餘目的皆與本人無關。
2.本程式僅在DCView上測試過,且這不是相簿下載器。
3.本人作業環境是 Eclipse
+ JRE System Library [ jdk1.6.0_05 ]
後記:
Duncan
大大到底是何許人也,怎麼什麼問題他都可以回答啊??
真神人也,要怎樣才能像他那樣強呢...
程式畫面.
以下為原始碼 , 或按這裡下載
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.DefaultTableModel;
//
public class picBox extends JFrame {
JTable table = null ;
JTextField txtURL = null;
Container cp = null;
JLabel lbPicPreview = null;
final int atLeastSizeKB = 20 ;
final String defaultFolder = "pic/" ;
final double defaultW = 300.0 ;//自訂SizeW:
final double defaultH = 300.0 ;//自訂SizeH:
public static void main(String args[]) {
new picBox();
}
picBox() {
super("DCView WebPage Image Downloader");
String testURL1="http://gallery.dcview.com/showGallery.php?id=8831";//For Test 風景
String testURL2="http://gallery.dcview.com/showGallery.php?id=9309";//For Test 正妹
//JTextField
txtURL = new JTextField("");
txtURL.setText(testURL2);
//JButton: btnExe
JButton btnExe = new JButton("執行") ;
btnExe.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
try {
ActionExe(evt);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//JButton: Exit
JButton btnExit = new JButton("離開") ;
btnExit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
System.exit(0);
}
});
//Preview Window
lbPicPreview = new JLabel(changeImage("00.jpg"));
try{
//Table//以Model物件宣告建立表格的JTable元件
table = new JTable(){
public void valueChanged(ListSelectionEvent e){
super.valueChanged(e); //呼叫基礎類別的valueChanged()方法, 否則選取動作無法正常執行
if( table.getSelectedRow() == -1) return;//取得表格目前的選取列,若沒有選取列則終止執行方法
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setSelectionBackground(Color.ORANGE);//設定選取背景顏色
table.setCellSelectionEnabled(true); //設定允許儲存格選取
//取得處理表格資料的Model物件,建立關聯
DefaultTableModel dtm = (DefaultTableModel)table.getModel(); //宣告處理表格資料的TableModel物件
//Set ColumnHeader Name
dtm.addColumn( "Item" );
dtm.addColumn( "FileName" );
dtm.addColumn( "Size(KB)" );
//欄寬設定
table.getColumnModel().getColumn(0).setPreferredWidth(40); //設定欄位的喜好寬度為40
table.getColumnModel().getColumn(1).setPreferredWidth(270); //設定欄位的喜好寬度為270
table.getColumnModel().getColumn(2).setPreferredWidth(70); //設定欄位的喜好寬度為70
//註冊回應JTable元件的MouseEvent事件的監聽器物件
table.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
int selRow = table.rowAtPoint(e.getPoint());//取得滑鼠點選位置所在之資料的列索引
String Size = (String) table.getValueAt(selRow, 2); //取得被點選資料列的第3欄的值
if (Integer.parseInt(Size)> 0 ){
String imgPath = defaultFolder + (String) table.getValueAt(selRow, 1); //取得被點選資料列的第2欄的值
lbPicPreview.setIcon((changeImage(imgPath)));
}
}
});
}catch ( Exception e){
e.printStackTrace();
}
//setup main window
Box bxRow1= new Box(BoxLayout.X_AXIS);
bxRow1.add(Box.createHorizontalStrut(10));//Strut:固定長度的透明支架
bxRow1.add(new JLabel("Target URL :"));
bxRow1.add(Box.createHorizontalStrut(10));//Strut:固定長度的透明支架
bxRow1.add(txtURL);
bxRow1.add(Box.createHorizontalStrut(10));//Strut:固定長度的透明支架
bxRow1.add(btnExe);
bxRow1.add(Box.createHorizontalStrut(10));//Strut:固定長度的透明支架
bxRow1.add(btnExit);
bxRow1.add(Box.createHorizontalStrut(10));//Strut:固定長度的透明支架
Box bxMix = new Box(BoxLayout.X_AXIS);
bxMix.add(Box.createHorizontalStrut(10));//Strut:固定長度的透明支架
bxMix.add(new JScrollPane(table));//放在 JScrollPane 內才有, Scrollbar
bxMix.add(Box.createHorizontalStrut(10));//Strut:固定長度的透明支架
bxMix.add(lbPicPreview);
bxMix.add(Box.createVerticalStrut(10));//Strut:固定長度的透明支架
//內容面板
cp = getContentPane(); //取得內容面版
cp.setLayout(new BorderLayout(10, 10)); //建立各區域水平、垂直間距為10的BorderLayout物件
//將各按鈕控制項,加入版面的指定位置
cp.add(bxRow1, BorderLayout.NORTH);
cp.add(bxMix);
///設定根面版四周將使用寬度為5的空白框線
getRootPane().setBorder(new EmptyBorder(5, 5, 5, 5));
//設定視窗預設的關閉動作、視窗大小, 並顯示視窗
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(750, 500);//pack();強迫視窗會變成最佳尺寸, 使 setSize 無效
setVisible(true);
}
private void ActionExe(java.awt.event.ActionEvent evt) throws InterruptedException{
this.setTitle("Analyzing and Downloading...");
//reset Table
DefaultTableModel dtm = (DefaultTableModel)table.getModel();
for (int kk = dtm.getRowCount() - 1 ; kk >= 0 ; kk -- ){
dtm.removeRow(kk);
}
String URL = txtURL.getText().trim();
//讀入網頁原始碼
if (readPage(URL) == -1){
addMatch("ReadPage Error !!", 0 );
return;
};
//分析網頁資料
if (analyPage()== -1){
addMatch("AnalyPage Error !!", 0 );
return;
};
//這個 ActionExe 的 thread 比 analyPage 的 thead 早結束
}
//換照片時,自動縮小
private ImageIcon changeImage(String imgPath){
ImageIcon img = new ImageIcon(imgPath) ;
double imgW = img.getIconWidth();
double imgH = img.getIconHeight();
double scale = 1.0;
if (imgW >= imgH){
scale = defaultW / imgW ;
img.setImage(img.getImage().getScaledInstance( (int) defaultW, (int) (imgH * scale) ,Image.SCALE_DEFAULT));
}else{
scale = defaultH / imgH ;
img.setImage(img.getImage().getScaledInstance((int)(imgW * scale) , (int)defaultH,Image.SCALE_DEFAULT));
}
return img;
}
// Add data to table.
private void addMatch(String path, long size ) throws InterruptedException {
DefaultTableModel dtm = (DefaultTableModel)table.getModel();
dtm.addRow(new String[] {String.valueOf(dtm.getRowCount()+1), path, (size>0 ? setComma(size):"")});
if (path.indexOf("OK") > -1){this.setTitle("DCView WebPage Image Downloader");}
}
private String setComma( long size ) {
int idx = 0;
String s = String.valueOf(size);
StringBuffer sb = new StringBuffer("") ;
for(int k=s.length() ; k>0 ; k-- ){
idx++;
sb.append((idx != s.length()&& idx%3==0)? s.substring(k-1, k) + "," : s.substring(k-1, k));
}
return sb.reverse().toString();
}
//分析網頁
public int analyPage() {
int c;
final StringBuffer sb = new StringBuffer("");
try{
InputStreamReader isr = new InputStreamReader(new FileInputStream("WebPage.txt"),"Big5");
while((c = isr.read()) != -1){ //Null, the end of file
sb.append((char) c);
}
//參考:http://www.javaworld.com.tw/jute/post/view?bid=29&id=42796&tpg=1&ppg=1&sty=0&age=0#42796
//因為用 while 會佔住 cpu , 所以加一個 thead 來執行, 以讓畫面可在每加一筆後,立即更新
//也就是 把 time-consuming 工作以獨立的 thread 來執行
new Thread(){
public void run() {
String[] target = {".jpg",".bmp",".png"};//pass gif
for ( int k=0 ; k < target.length ; k++){
int idx=0, start = 0 , tgtPos = 0 , httpPos = 0 ;
StringBuffer sbPage = new StringBuffer(sb.toString().toLowerCase());
while (true){
tgtPos = sbPage.indexOf(target[k], start);
if (tgtPos == -1 ){ break; }
// if ( (idx++) >= 5 ){ break; }//for test
//get target path
httpPos = sbPage.lastIndexOf("http", tgtPos);
String tgtURL = sbPage.substring(httpPos, tgtPos + 4).toString() ;
String fileName = tgtURL.substring(tgtURL.lastIndexOf("/")+1) ;
//檢查一些規則
if ( checkRule(tgtURL , fileName) ){
long fileSize = downloadPic(tgtURL);
try {
if(fileSize > 0){
addMatch(fileName , fileSize );
Thread.sleep(10);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
//reset
start = tgtPos + 4 ;
}
}
//Log for done
try {
addMatch("OKOK, Download Done !!", 0 );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}catch (IOException e) {
e.printStackTrace();
return -1;
}
return 1;
}
//避掉分析錯誤或無法存檔的情況
public boolean checkRule( String URL , String fileName ) {
if ( !URL.substring(0, 4).equals("http") ){
return false; //避掉一些相對路徑的圖片,這通常都很小
}else if ( URL.indexOf('>') > 0 || URL.indexOf('<') > 0 ){
//一些分析錯誤的情況
//http://www.facebook.com/pages/DCView/402684696689?v=wall&ref=ts"><img title="facebook" alt="facebook" src="/i/facebook_20.png
return false;
}else if (fileName.length() > 170 ){
//Windows檔名長度限制260字元,但再加上本身資料夾路徑,D:\eclipse\WorkSpace\picBox\pic 所以就更少了
return false;
}
//check double-file
for (int k=0; k< table.getRowCount() ; k++){
String downloadedFile = (String) table.getValueAt(k, 1);
if ( downloadedFile.equals(fileName) ){//已下載, <img> 內 src= 和 alt= 裡面的圖片是一樣的
return false;
}
}
return true;
}
//讀入網頁原始碼
public static int readPage( String strURL ) {
int chunksize = 4096;
byte[] chunk = new byte[chunksize];
int count;
try {
URL pageUrl = new URL(strURL );
// 讀入網頁(位元串流)
BufferedInputStream bis = new BufferedInputStream(pageUrl.openStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("WebPage.txt", false));
while ((count = bis.read(chunk, 0, chunksize)) != -1) {
bos.write(chunk, 0, count); // 寫入檔案
}
bos.flush();
bos.close();
bis.close();
}catch (IOException e) {
e.printStackTrace();
return -1;
}
return 1;
}
//下載圖片
public long downloadPic(String strURL){
long fileSize = 0;
FileOutputStream fos = null ;
InputStream is = null ;
try {
System.out.println("Checking -> " + strURL);
//為了避免 403 的錯誤,http://www.javaworld.com.tw/jute/post/view?bid=38&id=108431&tpg=1&ppg=1&sty=0&age=0#108431
URL url = new URL(strURL);
URLConnection URLConn = (HttpURLConnection) url.openConnection();
URLConn.setRequestProperty("User-agent","IE/6.0");
fileSize = ( URLConn.getContentLength() / 1024) + 1 ; //Unit:KB , 自動進位^^
if ( URLConn.getContentLength() > 0 && URLConn.getContentType().indexOf("text/html") >= 0) {
//未被授存取的圖片, 無權進入的網頁, 會回應出此類訊息 URLConn.getContentType()=> text/html; charset=iso-8859-1
//例如 http://upload.dcview.com/u/gallery/201007/8191a51eea9df2e7defa401a36ded0b2.jpg
return -1;
}else if ( fileSize <= atLeastSizeKB ){
//小於 atLeastSizeKB 不下載
return -1;
}
//check Folder for picture
File f = new File(defaultFolder) ;
if (!f.exists()){f.mkdirs();}
f = null;
//
String filePath = defaultFolder + strURL.substring(strURL.lastIndexOf("/")+1) ;
fos = new FileOutputStream(filePath, false);
is = URLConn.getInputStream(); // OldScript:url.openStream();
//==讀到 buffer[] 因為不能保證連線的品質,或是檔案較大的時候,也許會有lose
int chunkSize = 1024 * 8;
byte[] buf = new byte[chunkSize];
int readLen;
System.out.println("Downloading -> " + strURL);
while ((readLen = is.read( buf, 0, buf.length)) != -1) {
fos.write(buf, 0, readLen);
}
is.close(); fos.close();
//顯示已下載的圖片
lbPicPreview.setIcon((changeImage(filePath)));
lbPicPreview.repaint();
} catch (MalformedURLException e) {
fileSize = -1;
e.printStackTrace();
} catch (FileNotFoundException e) {
fileSize = -1;
e.printStackTrace();
} catch (IOException e) {
fileSize = -1;
e.printStackTrace();
} catch (Throwable e) {
fileSize = -1;
e.getMessage();
e.printStackTrace();
}finally{
try {
if (is !=null ){is.close();}
if (fos !=null ){fos.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
return fileSize ;
}
}
全站熱搜
留言列表