[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends] UrlRetriever.java



サイトマップ作成ツールですが、試したものにはソースが付いていませんでした。
いろいろカスタマイズしたいと思ったので、勉強がてら自分で書いてみました。
まだ途中ですが、いちおう動いているので投稿します。

UrlRetriever.java
================================================================
import java.net.*;
import java.io.*;
import java.util.*;
import javax.swing.tree.*;

public class UrlRetriever {
  private String base = null; // 他のサイトを再帰探査の対象にしないためのもの
  private TreeSet treeset = new TreeSet(); //一度探索したnodeを再帰探索しないため
  private MutableTreeNode top = null; //いちばん上のノード
  public MutableTreeNode getTop() { return top; }

  public void retrieve(String urlspec, DefaultMutableTreeNode parent) {
    int BUFFER_LENGTH = 1024;
    byte[] buffer = new byte[BUFFER_LENGTH + 1];
    int pos = 0;
    boolean is_append = false;
    String protocol = "";
    String host = "";
    String file = "";
    String path = "";
    String exform = "";
    DefaultMutableTreeNode node = null;
    try {
      URL url = new URL(urlspec);
      URLConnection conn = url.openConnection();
      URL u = conn.getURL(); // url とまったく同じ?
      protocol = u.getProtocol();
      host = u.getHost();
      file = u.getFile();
      path = this.getPath(file);
      //exform = u.toExternalForm();
      if (protocol.equals("mailto")) {
        exform = protocol + ":" + host + file;
      } else {
        exform = protocol + "://" + host + file;
      }
        System.out.println(exform); // DEBUG
      node = new DefaultMutableTreeNode(exform);
      if (parent == null) {
        //parent=null のとき base をセット
        top = node;
        base = url.getHost();
      } else {
        //parent=null でなければ url.toExternalForm() を 親ノードに add
        parent.add(node);
      }
      //ヘッダーを解析して、text でなければ return
      String type = conn.getContentType();
        //System.out.println("CONTENT_TYPE=" + type); // DEBUG
      if (type.indexOf("text") == -1) return;

      //Base URL が異なるものは再帰探索しない
      if (!host.equals(base)) { return; }

      if (!treeset.contains(exform)) {
        //今まで探索していないものだけ
        treeset.add(exform);       //TreeSetに登録
      } else {
        return;                    //すでに探索した
      }
      InputStreamReader is = new InputStreamReader(conn.getInputStream());
      int c;
      while ((c = is.read()) != -1) {
        // タグ開始?////////////////////
        if ((char)c == '<') {
          is_append = true;
          pos = 0;
          Arrays.fill(buffer, (byte)'\0');// JDK 1.2 Only
        }
        //タグの中?/////////////////////
        if (is_append) {
          // バッファーに追加/////////////////////////
          pos++;
          if (pos < BUFFER_LENGTH) {
            buffer[pos] = (byte)c;
          }
        }
        // タグ終了?/////////////////////
        if ((char)c == '>') {
          is_append = false;
          String s = new String(buffer, 0, pos + 1);
          String link = null;
          if ((link = this.getLink(s)) != null) {
            link = this.getUrlspeck(link, protocol, host, path);
            //再帰探索///////////////////////////////////////////////////
            this.retrieve(link, node);
          }
        }
      }
    }
    catch (IOException e) {
    }
    catch (Exception e) {
    }
  }

  // URL#getFile() のうちのパス名を解析
  public String getPath(String file) {
    int slash = file.lastIndexOf('/');
    if (slash > -1) {
      // '/' 記号がある
      if (slash == file.length() - 1) {
        // '/' 記号で終わっている
        return new String(file);
      } else {
        // '/' 記号で終わっていない
        int dot = file.lastIndexOf('.');
        if ( dot > slash + 1 && dot < file.length() - 1) {
          // '/' 記号の後ろに '.' 記号がある
          return file.substring(0, slash + 1);
        } else {
          // '/' 記号の後ろに '.' 記号は無い
          return new String(file + "/"); // 危険かなあ...
        }
      }
    } else {
      // '/' 記号が無い (たぶんありえない)
      return "/"; // これでいいのか?
    }
  }

  //プロトコル名、相対リンクなどの補完
  public String getUrlspeck( String link,
                             String protocol, String host, String path)
  {
    // プロトコル名がある?( "://" を含む?)
    int collon = -1;
    boolean b = false;
    if ((collon = link.indexOf(':')) > 0) {
      // プロトコル名なのか?( : の手前が [a-z] ?)
      b = true;
      for (int i = 0; i < collon; i++) {
        char ci = link.charAt(i);
        if (ci < 'a' || ci > 'z') {
          b = false;
          break;
        }
      }
    }
    if (!b) {
      //プロトコル名を含まない
      if (link.startsWith("/")) {
        // Document Root からのリンク
        // protocol, host, path を補完
        link = protocol + "://" + host + link;
      } else {
        // このページからの相対リンク
        // protocol, host, path を補完
        link = protocol + "://" + host + path + link;
      }
    }
    return new String(link);
  }

  // tag 中の HREF=, SRC= を取得
  public String getLink(String tag) {
    if (tag.startsWith("</")) { return null; }
    String utag = (tag.toUpperCase()).trim(); // 検査対象を大文字化
    String link = "";                         // リンクの先頭部分
    if (utag.startsWith("<A "))          { link = "HREF"; } // <A HREF
    else if (utag.startsWith("<FRAME ")) { link = "SRC";  } // <FRAME SRC
    else                                 { return null;   } // 上記以外調べない
    int pos = -1;
    if ((pos = utag.indexOf(link)) != -1) {        // HREF または SRC の探索
      int start = pos + link.length() + 1;         // HREF または SRC の次の文字位置
      String stag = tag.substring( start,          // HREF または SRC を除去
                                   tag.length());
      stag = stag.replace('"', ' ');               // " 記号を空白にしてしまう
      stag = stag.replace('>', ' ');               // > 記号を空白にしてしまう
      stag = stag.trim();                          // 前後の空白を除去
      if (!stag.startsWith("=")) { return null; }  // 先頭に = 記号が無い
      stag = stag.substring(1, stag.length());     // = 記号の除去
      StringTokenizer tk =                         //トークン取り出し開始
        new StringTokenizer(stag);
      if (!tk.hasMoreTokens()) { return null; }    //リンクが空
      return tk.nextToken();                       //最初のトークンだけ返す
    } else {
      return null;                                 //リンクではない
    }
  }

  public static void main(String[] args) {
    UrlRetriever me = new UrlRetriever();
    me.retrieve(args[0], null);
  }
}
------------------------------------------------------------------
遠藤靖之 (えんどう やすゆき) <yasuyuki@xxxxxxxxxx>
http://www.freepage.total.co.jp/jfriends/ (Java互助会ホームページ)
株式会社タイムインターメディア 情報通信サービス部 TEL 03-5362-9009
〒162-0065 新宿区住吉町3-11 新宿スパイアビル8F    FAX 03-5362-9008