ここでは、Yahoo!Financeの株価時系列データをJavaCCで解析します。

 

JavaCCとは?

  1. BNFなどで示される、ある文法に則って書かれた文章を解析するプログラムを作るためのプログラムです。
  2. CC( 解析プログラム(Compiler) を 作るプログラム(Compiler) )

JJTree と JTB

BNFとは?

  1. 文の構造を表す方法です
  2. Backus Naur Form
    1. 1959 John Backus が発明
    2. 1960 Peter Naur が改良
    3. ALGOL60言語の定義に用いられる
  3. BNFの基本構造。
    終端記号。実際に文の上に出現する記号です。
    <〜>非終端記号。配下に非終端記号と終端記号を持ちます。
    ::=定義(左辺は、右辺の内容に展開される)
    +1回以上の繰り返し
    *0回以上の繰り返し
    ?0回または1回出現(有っても無くても良い)
    or
  4. 拡張BNF
    1. ABNF http://www.rfc-editor.org/rfc/rfc2234.txt
    2. EBNF
      プロトコルの定義などで、その定義を行うために独自にBNFを拡張している場合がある。
      ex.HTTP1.1(RFC2068) http://www.y-adagio.com/public/standards/tr_http11_2068/toc.htm
  5. BNFの例
    <長歌>   ::= <57> <57> <57> <57>* <7>
    <短歌>   ::= <57> <57> <7>
    <俳句>   ::= <57> <5>
    
    <57>   ::= <5> <7>
    <5>     ::= <かな> <かな> <かな> <かな> <かな>
    <7>     ::= <かな> <かな> <かな> <かな> <かな> <かな> <かな>
    <かな>   ::= い | ろ | は | に | ほ | へ | と | ち | り | ぬ | る | を |
                 わ | か | よ | た | れ | そ | つ | ね | な | ら | む | う |
                 ゐ | の | お | く | や | ま | け | ふ | こ | え | て | あ |
                 さ | き | ゆ | め | み | し | ゑ | ひ | も | せ | す 

JavaCCのインストール

  1. JavaCCのインストール
    https://javacc.dev.java.net/
    から、
    javacc-3.2.zip
    をダウンロードして適当な所に展開します。
    ここでは、 C:\eclipse311\javacc-3.2 以下にコピーしました。
  2. JTBのインストール
    http://compilers.cs.ucla.edu/jtb/
    から、
    jtb132.jar
    をダウンロードして適当なところに展開します。
    ここでは、 C:\eclipse311\javacc-3.2\bin\lib 以下にコピーしました。
  3. JavaCCプラグイン
    1. 取得
      http://perso.wanadoo.fr/eclipse_javacc/
      から、
      rk.eclipse.javacc_1.3.1.zip
      をダウンロードします。
    2. インストール
      rk.eclipse.javacc_1.3.1.zip
      を展開して出来た plugin を C:\eclipse311\plugin にコピーします。
    3. 設定
      プロジェクトの設定([ウィンドウ(W)]-[設定(P)] ではない)で、javacc.jar、jtb132.jarのフルパスを設定します。
      JavaCCSetting.png

jjファイルの文法

JavaCCプログラムは*.jjファイルに記述します。jjファイルは以下のような構成になっています。

<jjファイル>    ::= <OPTION> <PARSER_CLASS> <TOKEN_DEF> <PARSER_METHOD>+ <JAVA_CODE>

<OPTION>        ::= コンパイラ・コンパイラとなるクラスの設定をします。

<PARSER_CLASS>  ::= コンパイラ・コンパイラとなるクラスを定義します

<TOKEN_DEF>     ::= <SKIP>* <TOKEN>* <SPECIAL_TOKEN>*
<SKIP>          ::= 無視して読み飛ばされる字句を定義します。
<TOKEN>         ::= 構文を構成する字句を定義します。
<SPECIAL_TOKEN> ::= 文法に関係無くどこにでも現れる可能性のある特殊な字句を定義します。

<PARSER_METHOD> ::= 字句によって構成される構文を定義し、
                    見つかった構文に対する処理を記述します。 

<JAVA_CODE>     ::= 構文解析とは関係ないJava Codeを書きます

HTMLTableParser?.jj

HTML文書のTABLEタグの内容を取得するHTMLTableParser?.jjを作成します。ここではとりあえず<TD>タグの中身をSystem.outに出力します(データの取り込みは後述するJTBを使ってこのプログラムを拡張して行います)。

  1. <OPTION>
    OPTION部では、JavaCCがJavaプログラムを作る際のオプションを指定します。
    /*****************************************************************************
     * オプション定義                                                            *
     *****************************************************************************/
    options {
    	STATIC=false;
    	JAVA_UNICODE_ESCAPE=false;
    	UNICODE_INPUT=true;
    	DEBUG_PARSER=false;
    	DEBUG_TOKEN_MANAGER=false;
    }
     
    項目設定内容デフォルト値
    STATICtrueにすると生成されるメソッドがstaticになります。当然マルチスレッドで使えないのでfalseにするのが吉true
    JAVA_UNICODE_ESCAPEtrueにすると、ParserはUnicode Escapeされた文字が入力されると見なします。昔はASCII以外の文字をJavaCCで解析するにはこのオプションを使ったが、UNICODE_INPUTが使えるようになったのでfalseにしておくfalse
    UNICODE_INPUTtrueにすると、ParserはUCS2(つまりはJavaのString型)が入力されると見なします。日本語を使うならtrueにしますfalse
    DEBUG_TOKEN_MANAGERJavaCCによって生成されたParserにデバックトレースを入れるfalse
    DEBUG_PARSERJavaCCのよって生成されたParserにデバックトレースを入れるfalse
  2. <PARSER_CLASS>
    PARSER_CLASS部では、JavaCCによって生成されるクラスを定義します。import宣言やフィールド変数、コンストラクタなどを定義します。
    /*****************************************************************************
     * Javaクラスの生成                                                          *
     * このJavaクラスのメソッドとして構文解析プログラムが自動生成されます        *
     *****************************************************************************/
    PARSER_BEGIN(HTMLTableParser)
    
    package com.snail.parser.table;
    
    /**
     * HTML TABLE PARSER
     * @author  Hondoh Atsushi
     * @version $Id$
     */
    public class HTMLTableParser{
    }
    
    PARSER_END(HTMLTableParser)
  3. <SKIP>
    SKIP部では、無視して読み飛ばされる字句を定義します。
    /**************************************************************/
    /* SKIP :                                                     */
    /* 無視して読み飛ばされるもの。空白、タブ、改行文字など。     */
    
    SKIP : {
    	<SPACE : " " | "\t" | "\n" | "\r" | "\f">
    }
  4. <SPECIAL_TOKEN>
    文法に関係無くどこにでも現れる可能性のある特殊な字句を定義します。基本的には無視する字句を定義します。ここではTABLE内に示された「情報」という観点から必要のないHTMLタグを定義しています
    /**************************************************************/
    /* SPECIAL_TOKEN :                                            */
    /* 文法に関係無くどこにでも現れる可能性のある特殊なトークン   */
    
    SPECIAL_TOKEN : {
    	<COMMENT : "<!" (~[">"])* ">" >                   |
    	<META    : "<META" (~[">"])* ">"                  |
    		  "<meta" (~[">"])* ">" >                |
    	<BR      : "<BR" (~[">"])* ">"                    |
    		  "<br" (~[">"])* ">" >                  |
    	<HR      : "<HR" (~[">"])* ">"                    |
    		  "<hr" (~[">"])* ">" >                  |
    	<P       : "<P>" | "</P>"                         |
    		  "<p>" | "</p>" >                       |
    	<B       : "<B>" | "</B>"                         |
    		  "<b>" | "</b>">                        |
    	<SCRIPT  : "<SCRIPT" (~["<"])* "</SCRIPT>"        |
    		  "<script" (~["<"])* "</script>" >      |
    	<NOSCRIPT: "<NOSCRIPT>" | "</NOSCRIPT>"           |
    	         	  "<noscript>" | "</noscript>" >         |
    	<CENTER  : "<CENTER>"   | "</CENTER>"             |
    	           "<center>"   | "</center>" >           |
    	<FONT    : "<FONT" (~[">"])* ">" | "</FONT>"      |
    	           "<font" (~[">"])* ">" | "</font>" >    |
    	<SMALL   : "<SMALL>" | "</SMALL>"                 |
    		  "<small>" | "</small>" >               |
    	<IMG     : "<IMG" (~[">"])* ">"                   |
    		  "<img" (~[">"])* ">" >                 |
    	<INPUT   : "<INPUT" (~[">"])* ">"                 |
    	           "<input" (~[">"])* ">" >               |
    	<SELECT  : "<SELECT" (~[">"])* ">" | "</SELECT>"  |
    	           "<select" (~[">"])* ">" | "</select>"> |
    	<OPTION  : "<OPTION" (~[">"])* ">" | "</OPTION>"  |
    	           "<option" (~[">"])* ">" | "</option>"> |
    	<TBODY  :  "<TBODY>" | "</TBODY>"                 |
    		  "<tbody>" | "</tbody>">                |
    	<FORM   :  "<FORM" (~[">"])* ">" | "</FORM>"      |
    	           "<form" (~[">"])* ">" | "</form>">     |
    	<DIV    :  "<DIV" (~[">"])* ">" | "</DIV>"        |
    	           "<div" (~[">"])* ">" | "</div>">
    }
  5. <TOKEN>
    TOKENには、構文を構成する字句を定義します。ここではTABLE内の情報を取得するために処理する必要のあるHTMLタグを定義します
    /**************************************************************/
    /* TOKEN:                                                     */
    /* 構文を構成する要素                                         */
    
    TOKEN : {
    	<STRING_LITERAL : (~["<","\n","\r","\f"] )+>
    }
    TOKEN : {
    	<HTML   : "<HTML>"     |
    	          "<html>" >   |
    	<EHTML  : "</HTML>"    |
    	          "</html>" >  |
    	<HEAD   : "<HEAD>"     |
    	          "<head>" >   |
    	<EHEAD  : "</HEAD>"    |
    	          "</head>" >  |
    	<TITLE  : "<TITLE>"    |
    	          "<title>" >  |
    	<ETITLE : "</TITLE>"   |
    	          "</title>" > |
    	<BODY   : "<BODY>"     |
    	          "<body>" >   |
    	<EBODY  : "</BODY>"    |
    	          "</body>" >
    }
    TOKEN : {
    	<TABLE  : "<TABLE" (~[">"])* ">"   |
    	          "<table" (~[">"])* ">" > |
    	<ETABLE : "</TABLE>"               |
    	          "</table>">              |
    	<TR     : "<TR" (~[">"])* ">"      |
    	          "<tr" (~[">"])* ">" >    |
    	<ETR    : "</TR>"                  |
    	          "</tr>" >                |
    	<TD     : "<TD" (~[">"])* ">"      |
    	          "<td" (~[">"])* ">"      |
    	          "<TH" (~[">"])* ">"      |
    	          "<th" (~[">"])* ">" >    |
    	<ETD    : "</TD>"                  |
    	          "</td>"                  |
    	          "</TH>"                  |
    	          "</th>" >                |
    	<LINK   : "<A" (~[">"])* ">"       |
    	          "<a" (~[">"])* ">" >     |
    	<ELINK  : "</A>" | "</a>" >
    }
  6. <PARSER_METHOD>
    いよいよメインディシュです。TOKENによって構成される構文を定義し、見つかった構文に対する処理を記述します。 定義方法は
    void ${メソッド名} : {
      Javaコード
    }{
      TOKEN {TOKENを処理するJavaコード}
      (構文)*
      TOKEN
    }
    というように定義します。TOKENを受け取るにはTokenというオブジェクトを使います。
    ここでは、htmlを処理するメソッドから始めます。
    void html() : {
    }{
    	<HTML>
    	<HEAD>
    	<TITLE>
    	<STRING_LITERAL>
    	<ETITLE>
    	<EHEAD>
    	
    	<BODY>
    	
    	( table() | <STRING_LITERAL> | link() )*
    	
    	<EBODY>
    	<EHTML>
    	
    	<EOF>
    }
    
    void table() : {
    }{
    	<TABLE>
    	(row())*
    	<ETABLE>
    }
    
    void row() : {
    }{
    	<TR>
    	(col())*
    	<ETR>
    }
    
    void col() : {
    	Token token;
    }{
    	<TD>
    	(token=<STRING_LITERAL>{System.out.println( token.image );} |
    	 table() | link())*
    	<ETD>
    }
    
    void link() : {
    	Token token;
    }{
    	token=<LINK>{System.out.println( token.image );}
    	
    	(token=<STRING_LITERAL>{System.out.println( token.image );})*
    	
    	(<ELINK>|<LINK>)
    }
    ※ link ::= <LINK> <STRING_LITERAL> ( <ELINK> | <LINK> )となっているのは、Yahoo!の株価ページで "<a hrer="..."> ... <a>" となっている部分があったから
  7. <JAVA_CODE>
    最後に、構文解析とは関係ないJava CodeはJAVA_CODE部に書かれます
    /*****************************************************************************
     * 任意のメソッドの定義。                                                    *
     * トークンとも構文とも無関係な任意のJavaコードを書き込みます。              *
     *****************************************************************************/
    JAVACODE
    void skip_form(){
    	Token t;
    	do {
    		t = getNextToken();
    	} while ( t.kind != EOF );
    }

生成されたプログラムを実行する

  1. これらをHTMLTableParser?.jjに記述して、ファイルをセーブするとJavaCC Eclipse Pluginにより自動的にJavaCCが起動されJavaコードが生成されます。
    JJScreenShot.PNG
  2. 生成されたParserを使うには、InputStream?をコンストラクタの引数にしてHTMLTableParser?をインスタンス化し、トップレベルの構文解析メソッド( html() )を呼び出します。
    次のコードは、Yahoo!Financeから、8035.t(東京エレクトロン)の時系列データを読み出す例です。
    package com.snail.parser.table;
    
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    
    public final class HTMLTableReader {
        public HTMLTableReader() {
            super();
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            URL url;
    
            try {
                String[] range = { "1980", "1", "1", "2020", "12", "31", "8035.t" };
    
                StringBuffer sbuf = new StringBuffer();
                sbuf.append("http://table.yahoo.co.jp/t");
                sbuf.append("?c=" + range[0]);
                sbuf.append("&a=" + range[1]);
                sbuf.append("&b=" + range[2]);
                sbuf.append("&f=" + range[3]);
                sbuf.append("&d=" + range[4]);
                sbuf.append("&e=" + range[5]);
                sbuf.append("&s=" + range[6]);
                sbuf.append("&y=0");
                sbuf.append("&z=" + range[6]);
    
                url = new URL(sbuf.toString());
    
                HttpURLConnection con = (HttpURLConnection) url.openConnection();
                con.setRequestMethod("GET");
    
                HTMLTableParser parser = new HTMLTableParser(new InputStreamReader(
                            con.getInputStream(), "EUC_JP"));
    
                parser.html();
    
                con.disconnect();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }
  3. 実行結果
    <a href="http://quote.yahoo.co.jp/">
    <a href="http://www.yahoo.co.jp/">
    Yahoo! JAPAN
     - 
    <a href="http://my.yahoo.co.jp/">
    My Yahoo!
     - 
    <a href="http://help.yahoo.co.jp/help/jp/fin/">
    ヘルプ
    
    (中略)
    
    信用残時系列データ
    日付
    始値
    高値
    安値
    終値
    出来高
    調整後終値*
    2005年11月21日
    6,780
    6,830
    6,700
    6,730
    1,892,000
    6,730
    2005年11月18日
    6,680
    6,820
    6,680
    6,710
    3,025,800
    6,710
    2005年11月17日
    6,500
    6,650
    6,390
    6,600
    2,270,800
    6,600
    2005年11月16日
    6,430
    
    (後略)

構文木の生成

  1. JJTree は、jjt ファイルから、構文木を生成するようなjjファイルを作成します。
                 <JJTreeによる生成>         <JavaCCによる生成>
                       
    HTMLTableParser.jjt -+--> HTMLTableParser.jj ----> 構文解析
                         |                             Javaプログラム
                         |                                 :
                         |                                 :(use)
                         |                                 ↓
                         +---------------------------> 構文木生成
                <JJTreeによる生成>                     Javaプログラム
  2. jjtファイルの作り方
    1. jjファイルの拡張子をjjtに変換します。
    2. 構文木は、解析プログラムの中では、SimpleNode?型 のjjtThisオブジェクトとして扱われます。
      • SimpleNode?クラスは、JTB によりソースコードが自動生成されます。
      • jjファイルのトップレベルの構文解析メソッド( html() )の返値を呼び出し、 SimpleNode? を返値とする parse() メソッドを作ります。
         
        HTMLTableParser?.jjt(jjファイルとの変更点)
        SimpleNode parse() : {
        }{
            html() <EOF>
            {
               return jjtThis;
            }
        }
        
        void html() : {
        }{
        	<HTML>
        	<HEAD>
        	<TITLE>
    3. 外部からはこのメソッドを呼び出すようにします。
      HTMLTableReader?.java (変更点)
      url = new URL(sbuf.toString());
      
      HttpURLConnection con = (HttpURLConnection) url.openConnection();
      con.setRequestMethod("GET");
      
      HTMLTableParser parser = new HTMLTableParser(new InputStreamReader(
                    con.getInputStream(), "EUC_JP"));
      
      SimpleNode root = parser.parse();
      
      con.disconnect();
      
      root.dump("  ");
    4. jjtファイルをセーブ(ctrl+s)すると、jjファイルと構文木生成プログラムが生成され、さらにjjファイルから構文解析プログラムが生成されます。
      execJJT.png
    5. HTMLTableReader? を実行すると構文木が出来ています。すばらしい
       parse
        html
         table
          row
           col
            link
           col
            table
             row
              col
               link
               link
               link
         link
         table
  3. SimpleNode?を拡張し、構文ノードのデータを埋め込む
    1. SimpleNode?の構造
      SimpleNode?は一種の双方向リストになっています。各SimpleNode?は、一つのparentと複数のchild(children[])を持ちます。
      SimpleNode.png
    2. SimpleNode?にデータ格納領域を作る。
      それぞれの構文解析メソッド(html()やtable()、col()など)では、構文木上の今解析しているところを jjtThis オブジェクトとして参照することが出来ます。そこで、SimpleNode?にデータを格納するフィールド(内部変数)を作ってやって、構文解析メソッド中でデータを埋め込んでやれば目的を達成することが出来ます。
      1. SimpleNode?.java (変更点)
        ここでは、テーブル連番・テーブルに格納されたデータ(URL・テキスト)を格納できるようにSImpleNode?を拡張します。また、SimpleNode?#dump()でノードの内容を表示するようにSimpleNode?#toString()に手を入れてやります。
        public class SimpleNode implements Node {
         
         /** テーブル連番 */
         protected int tableNo;
         public void setTableNo(int tableNo) {
           this.tableNo = tableNo;
         }
         public int getTableNo() {
           return tableNo;
         }
         
         /** link() の場合には URLを格納する */
         protected String url = "";
         public void setURL(String pUrl) {
           url = url + pUrl;
         }
         public String getURL() {
           int first = url.indexOf("\"") + 1;
           int last = url.indexOf("\"", first);
         
           return url.substring(first, last); // <a href="〜"> の 〜のみを返す 
         }
         
         /** col() / link() の場合には テキスト を格納する */
         protected String text = "";
         
         public void setText(String pText) {
           text = text + pText;
         }
         
         public String getText() {
           return text;
         }
         
         public String toString() {
           String str = HTMLTableParserTreeConstants.jjtNodeName[id];
           
           if( "table".equals(str) ){
             str = str + "[" + tableNo + "]";
           }
        
           if (!text.equals("")) {
             str = str + ":" + getText();
           }
        
           if (!url.equals("")) {
             str = str + "(" + getURL() + ")";
           }
        
           return str;
         }
         
         (後略)
      2. HTMLTableParser?.jjt(jjファイルとの変更点)
        PARSER_BEGIN(HTMLTableParser)
        
        package com.snail.parser.table;
        
        /**
         * HTML TABLE PARSER
         * @author  Hondoh Atsushi
         * @version $Id$
         */
        public class HTMLTableParser{
          private int tableNo = 0;
        }
        
        PARSER_END(HTMLTableParser)
        
        (中略)
        
        SimpleNode parse() : {
        }{
          html() <EOF>
            {
               return jjtThis;
            }
        }
        
        void html() : {
        }{
          <HTML>
          <HEAD>
          <TITLE>
          <STRING_LITERAL>
          <ETITLE>
          <EHEAD>
          
          <BODY>
          
          ( table() | <STRING_LITERAL> | link() )*
          
          <EBODY>
          <EHTML>
          
          <EOF>
        }
        
        void table() : {
          jjtThis.setTableNo( ++tableNo );
        }{
          <TABLE>
          (row())*
          <ETABLE>
        }
        
        void row() : {
        }{
          <TR>
          (col())*
          <ETR>
        }
        
        void col() : {
          Token token;
        }{
          <TD>
          (token=<STRING_LITERAL>{jjtThis.setText( token.image );} |
           table() | link())*
          <ETD>
        }
        
        void link() : {
          Token token;
        }{
          token=<LINK>{jjtThis.setURL( token.image );}
          
          (token=<STRING_LITERAL>{jjtThis.setText( token.image );})*
          
          (<ELINK>|<LINK>)
        }
  4. 解析結果
     parse
      html
       table[1]
        row
         col
          link(http://quote.yahoo.co.jp/)
         col
          table[2]
           row
       
       (中略)
       
       table[10]
        row
         col:東京エレクトロン(株)(東証1部: 8035.T)
       
       (中略)
       
             table[16]
              row
               col
                link:信用残時系列データ(/bt?s=8035.t&a=1&b=1&c=1980&d=12&e=31&f=2020&g=d&k=20051122)
            col
          table[17]
           row
            col
          table[18]
           row
            col
             table[19]
              row
               col:日付
               col:始値
               col:高値
               col:安値
               col:終値
               col:出来高
               col:調整後終値*
              row
               col:2005年11月22日
               col:6,820
               col:7,000
               col:6,810
               col:6,890
               col:4,322,300
               col:6,890
              row
               col:2005年11月21日
               col:6,780
               col:6,830
               col:6,700
               col:6,730
               col:1,892,000
               col:6,730
              row
       
       (中略)
       
               col:1,024,900
               col:6,220
          table[20]
           row
            col:* 分割による調整については、を参照してください。
             link:こちら(http://help.yahoo.co.jp/help/jp/fin/quote/historical/his_07.html)
            col:[]
             link:次の50件(t?s=8035.t&a=1&b=1&c=1980&d=12&e=31&f=2020&g=d&q=t&y=50&z=8035.t&x=.csv)
       table[21]
       
       (後略)

構文木から株価データを取得する

  1. 生成された構文木を見ると必要なデータが何番目のテーブルにあるのかが分かります
    テーブル番号情報
    10銘柄名
    16信用取引時系列データへのリンク
    19株価時系列データ
    20株価時系列データ(次の50件)へのリンク
  2. そこで、生成された構文木をたどってn番目のテーブルを探し出すプログラムを作ってやれば構文木から株価データを取得できます。ここでは、1000日分の株価をMapのCollectionとして読み出します。尚連続して読み込むとYahooから接続拒否されてしまうので、1ページ(50日分)読み込む毎に100ms休憩を入れています。
    package com.snail.stock;
    
    import com.snail.parser.table.HTMLTableReader;
    import com.snail.parser.table.Node;
    import com.snail.parser.table.ParseException;
    import com.snail.parser.table.SimpleNode;
    
    import java.io.IOException;
    
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.LinkedHashMap;
    import java.util.LinkedList;
    import java.util.Map;
    
    
    public final class YahooFinanceReader {
      public YahooFinanceReader() {
        super();
      }
    
      /**
      * @param args
      */
      public synchronized static void main(String[] args) {
        String[] range = { "1980", "1", "1", "2020", "12", "31", "8035.t" };
        
        Collection<Map> stockArray = new LinkedList<Map>();
    
        for (int y = 0; y < 1000; y += 50) {
          StringBuffer sbuf = new StringBuffer();
          sbuf.append("http://table.yahoo.co.jp/t");
          sbuf.append("?c=" + range[0]);
          sbuf.append("&a=" + range[1]);
          sbuf.append("&b=" + range[2]);
          sbuf.append("&f=" + range[3]);
          sbuf.append("&d=" + range[4]);
          sbuf.append("&e=" + range[5]);
          sbuf.append("&s=" + range[6]);
          sbuf.append("&y=");
          sbuf.append(y);
          sbuf.append("&z=" + range[6]);
          
          System.out.print("Reading " + sbuf + "...");
          
          stockArray.addAll(readPage(sbuf.toString()));
          
          System.out.println("done");
          
          try {
            Thread.sleep(100);
          } catch (InterruptedException e) {
            e=null;
          }
        }
        
        for (Iterator it=stockArray.iterator();it.hasNext();){
          System.out.println(it.next());
        }
      }
    
      private static Collection<Map> readPage(String url) {
    
        try {
          HTMLTableReader reader = new HTMLTableReader(url, "EUC_JP");
    
          // 銘柄名は10番目のテーブルに格納されている
          // String name = getStockName(reader.getBranch(10));
          // System.out.println(name);
    
          // 信用残時系列情報へのリンクは16番目のテーブルに格納されている
          // String balance = getBalanceLink(reader.getBranch(16));
          // System.out.println(balance);
    
          // 次の50件へのリンクは20番目のテーブルに格納されている
          // nextLink = getNextLink(reader.getBranch(20));
          // System.out.println(nextLink);
    
          // 株価時系列情報は19番目のテーブルに格納されている
          return getStockValues(reader.getBranch(19));
        } catch (IOException e) {
          e.printStackTrace();
        } catch (ParseException e) {
          e.printStackTrace();
        }
    
        return new LinkedList<Map>();
      }
    
      private static String getStockName(SimpleNode subtree) {
        // subtree.dump("  ");
        Node row = subtree.jjtGetChild(0);
        Node col = row.jjtGetChild(0);
    
        return ((SimpleNode) col).getText();
      }
    
      private static String getBalanceLink(SimpleNode subtree) {
        // subtree.dump("  ");
        Node row = subtree.jjtGetChild(0);
        Node col = row.jjtGetChild(0);
        Node link = col.jjtGetChild(0);
    
        return ((SimpleNode) link).getURL();
      }
    
      private static String getNextLink(SimpleNode subtree) {
        // subtree.dump("  ");
        Node row = subtree.jjtGetChild(0);
        Node col = row.jjtGetChild(1);
        Node link = col.jjtGetChild(0);
    
        return ((SimpleNode) link).getURL();
      }
    
      private static Collection<Map> getStockValues(SimpleNode subtree) {
        // subtree.dump("  ");
        Collection<Map> col = new LinkedList<Map>();
    
        int rows = subtree.jjtGetNumChildren();
    
        for (int cnt = 0; cnt < rows; cnt++) {
          Node row = subtree.jjtGetChild(cnt);
          Map<String,String> map = new LinkedHashMap<String,String>();
          map.put("day", ((SimpleNode) row.jjtGetChild(0)).getText());
          map.put("start", ((SimpleNode) row.jjtGetChild(1)).getText());
          map.put("high", ((SimpleNode) row.jjtGetChild(2)).getText());
          map.put("low", ((SimpleNode) row.jjtGetChild(3)).getText());
          map.put("end", ((SimpleNode) row.jjtGetChild(4)).getText());
          map.put("amount", ((SimpleNode) row.jjtGetChild(5)).getText());
          map.put("adjEnd", ((SimpleNode) row.jjtGetChild(6)).getText());
          col.add(map);
        }
    
        return col;
      }
    }
  3. 実行結果
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=0&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=50&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=100&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=150&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=200&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=250&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=300&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=350&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=400&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=450&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=500&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=550&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=600&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=650&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=700&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=750&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=800&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=850&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=900&z=8035.t...done
    Reading http://table.yahoo.co.jp/t?c=1980&a=1&b=1&f=2020&d=12&e=31&s=8035.t&y=950&z=8035.t...done
    {day=日付, start=始値, high=高値, low=安値, end=終値, amount=出来高, adjEnd=調整後終値*}
    {day=2005年11月30日, start=7,400, high=7,400, low=7,270, end=7,270, amount=1,432,200, adjEnd=7,270}
    {day=2005年11月29日, start=7,350, high=7,460, low=7,300, end=7,360, amount=2,502,600, adjEnd=7,360}
    {day=2005年11月28日, start=7,370, high=7,640, low=7,360, end=7,480, amount=4,686,200, adjEnd=7,480}
    {day=2005年11月25日, start=7,110, high=7,260, low=7,060, end=7,240, amount=2,786,200, adjEnd=7,240}
    {day=2005年11月24日, start=7,200, high=7,500, low=7,200, end=7,310, amount=14,894,600, adjEnd=7,310}
    {day=2005年11月22日, start=6,820, high=7,000, low=6,810, end=6,890, amount=4,322,300, adjEnd=6,890}
    
    (中略)
    
    {day=2001年11月8日, start=5,510, high=5,620, low=5,330, end=5,590, amount=530,900, adjEnd=5,590}
    {day=2001年11月7日, start=5,740, high=5,750, low=5,460, end=5,500, amount=880,900, adjEnd=5,500}
    {day=2001年11月6日, start=5,670, high=5,860, low=5,600, end=5,840, amount=1,432,200, adjEnd=5,840}
    {day=2001年11月5日, start=5,520, high=5,610, low=5,460, end=5,570, amount=910,200, adjEnd=5,570}
    {day=2001年11月2日, start=5,430, high=5,450, low=5,310, end=5,420, amount=1,134,200, adjEnd=5,420}

参考文献

  1. Yohta's Object World, http://www002.upp.so-net.ne.jp/ys_oota/
  2. Takahisa Hasegawa, 卒業研究, http://ltm.cs.uec.ac.jp/~takahisa/study/index.html
  3. 村田(沖電気), JavaHouse? ML, JavaCCで日本語を扱う方法, http://www.ingrid.org/java/javacc/murata.html
  4. 倉澤 邦美(学芸大), DROP IN !!!, http://apollo.u-gakugei.ac.jp/~kurasawa/
  5. JavaCC Eclipse Plug-in, http://perso.wanadoo.fr/eclipse_javacc/
  6. JavaCC, https://javacc.dev.java.net/

Java


添付ファイル: fileexecJJT.png 1116件 [詳細] fileSimpleNode.png 1178件 [詳細] fileJavaCCSetting.png 1229件 [詳細] fileJJScreenShot.PNG 1035件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS   sitemap
Last-modified: 2012-03-18 (日) 21:56:35 (1723d)
ISBN10
ISBN13
9784061426061