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);
        }
    }
    
    
}