2012年10月17日水曜日

JAVAでスクレイピングを実現するための覚書 2

第2回の投稿は前回に引き続きスクレイピングについてです。
前回は接続、取得まで行いました。
今回は解析についてです。
HTML解析はカスタマイズが容易なHTMLEditorKit.Parserクラスを利用して自作します。

HTMLEditorKit.Parserクラス

このクラスはタグなどのデータを検知し、指定した処理を行えるものです。
使い方は、HTMLファイルを読み込みながら解析を行うのでコールバッククラスを定義して指定した処理を行います。

主なメッソッド
handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
開始タグ検知時の処理をします。
例:<title> ⇒titleタグを検知⇒処理

handleEndTag(HTML.Tag t, int pos)
終了タグ検知時処理をします。
例:</titele>titleタグを検知⇒処理

handleText(char[] data, int pos)
通常文字列検知時の処理をします。
例:<title>タイトル</title>あいうえお⇒「タイトル」及び「あいうえお」という文字列を検知⇒処理
 
handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
単独なタグ検知時の処理をします。
例:<br />⇒brタグを検知⇒処理

コールバック処理の例

<html>
<head>
<title>タイトル</title>
</head>
<body>
あいうえお
</body>
</html>

titleタグ内の文字列を取得したい場合
public class Htmlparsercallback extends HTMLEditorKit.ParserCallback {
    boolean tagon = false;

    public void handleStartTag(HTML.Tag tag,MutableAttributeSet attr, int pos){
        if(tag.equals(HTML.Tag.TITLE)){
            tagon = ture;
        }
    }

    public void handleText(char[] data,int pos){
        if(tagon){
            System.out.println(data);
        }
    }

    public void handleEndTag(HTML.Tag tag,int pos){
        if(tag.equals(HTML.Tag.TITLE)){
            tagon = false;
        }
    }
}

コールバック処理の呼び出し

BufferedReader bstr = new BufferedReader(new InputStreamReader(httpoc.getInputStream()));
Htmlparsercallback htmlpc = new Htmlparsercallback();
ParserDelegator pd = new ParserDelegator();
pd.parse(bstr, htmlpc, true);

コールバック処理の呼び出しは以上です。
あとは自己流にコードを書き換えればスクレイピングを実現できます。
サンプルコードとしてTREE構造を考慮した簡易的なスクレイピングプログラムを載せておきます。
かなりごり押しぎみですが・・・

サンプルコード

main
public class Analyzer {
    public static void main(String args[]) {
        try {
        URL url = new URL(" ");
        HttpURLConnection httpoc = (HttpURLConnection)url.openConnection();
        httpoc.connect();
        
        BufferedReader bstr = new BufferedReader(new InputStreamReader(httpoc.getInputStream()));
        Htmlparsercallback htmlpc = new Htmlparsercallback();
        ParserDelegator pd = new ParserDelegator();
        pd.parse(bstr, htmlpc, true);
        httpoc.disconnect();
        System.out.println(SearchStr);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }
} 


callback
public class Htmlparsercallback extends HTMLEditorKit.ParserCallback {



  //左から順に書き換えてください。

    String[] htmltags = {"html", "head", "title"};
    int maxhtmltags = 3;



/*---------------------------------------------------------------------*/
    int j = 0;
    List<Integer> slist = new ArrayList<Integer>(Arrays.asList(0));
    List<Integer> klist = new ArrayList<Integer>(Arrays.asList(0));
    List<String> ktags = new ArrayList<String>(Arrays.asList(""));
    public void handleStartTag(HTML.Tag tag,MutableAttributeSet attr, int pos){
        if(klist.get(j)>=1){
            if(tag.toString().equals(htmltags[0])){
                if(slist.get(0)!=0){
                    slist.add(1);
                    klist.add(0);
                    ktags.add("");
                    j++;
                }
                else if(slist.get(0)==0){
                    slist.set(0, 1);
                }
            }
            else if(tag.toString().equals(ktags.get(j))){
                klist.set(j, klist.get(j)+1);
            }
        }
        else if(tag.toString().equals(htmltags[slist.get(j)])){
            slist.set(j, slist.get(j)+1);
        }
        else if(slist.get(j)>=1){
            klist.set(j, 1);
            ktags.set(j,tag.toString());
        }        
    }
    
    public void handleText(char[] data,int pos){
        if(slist.get(j)==maxhtmltags){
            System.out.println(data); 
        }
    }
    
    public void handleEndTag(HTML.Tag tag,int pos){
        if(tag.toString().equals(htmltags[0])){
            if(j!=0){
                slist.remove(j);
                klist.remove(j);
                ktags.remove(j);
                j--;
            }
            else if(j==0){
                slist.set(0, 0);
                klist.set(0, 0);
            }    
        }
        else if(tag.toString().equals(ktags.get(j))){
            klist.set(j, klist.get(j)-1);
            
        }
        else if(tag.toString().equals(htmltags[slist.get(j)-1])){
            slist.set(j, slist.get(j)-1);
        }
    }
    
    
}

2012年10月16日火曜日

JAVAでスクレイピングを実現するための覚書 1

第1回の投稿はスクレイピングについてです。
スクレイピングとはウェブサイトなどのほしいデータを抽出して利用することをいいます。
最近では大手サイトではAPIが提供されていますが、スクレイピングを必要とする場面はまだまだ多いです。

スクレイピングの流れ

大きく分けて以下3過程になります
  • 接続
  • 取得
  • 解析 
最も難しい過程は解析になります。
HTML解析はフリーから有料のものまで検索をかけると様々ありますが。
今回は簡易的なものを自作をしていきます。
この投稿では取得したサイトのHTMLソースの表示まで行います。

接続

1.URLオブジェクトの生成
 URL url = new URL("任意のURL");
2.接続オブジェクトの取得
 HttpURLConnection httpoc = (HttpURLConnection)url.openConnection();
3.接続
 httpoc.connect();

接続はこれで完了です。
ここでは接続オブジェクトの取得後、HTTPメソッド、ヘッダを指定して接続できます。
接続切断はdisconnect()で行います。

取得

入力ストリームを取得、表示
BufferedReader bstr = new BufferedReader(new InputStreamReader(httpoc.getInputStream()));
        String str;
            while ( (str=bstr.readLine())!= null ){
                System.out.println(str);
            }
        bstr.close();

 バッファリングすることで、入力ストリームから効率良く読み込んでいきます。
 以上で取得、表示は完了です。

次回はParserCallbackを利用した簡易なHTML解析を行います。


サンプルソース


  URL url = new URL("");
  HttpURLConnection httpoc = (HttpURLConnection)url.openConnection();
  httpoc.connect();
  
  
  BufferedReader bstr = new BufferedReader(new InputStreamReader(httpoc.getInputStream()));
  String str;
   while ( (str=bstr.readLine())!= null ){
    System.out.println(str);
   }
  bstr.close();
  httpoc.disconnect();







あいさつ

人生じめてのブログになります。
内容はプログラム、ネット関連の情報ブログにしていくつもりです。
情報といっても覚書程度なので丁寧な解説とかはありません。
更新ペースは遅くなると思いますが、できるだけ早く更新できるようがんばります。
よろしくお願いします。

当ブログのプログラムは自由に使っていただいてかまいませんですが、なんらかの不備が生じても責任はおえません。
すべて自己責任でお使いください。