KazMuzik.net
Music / Technology / Healthcare / Immigration / アメリカ
Google
 
<< Kaz Muzik Blog Google Search Project #5Kaz Muzik Blog Backup Project #28 - Kaz Muzik Blog Google Search Project #6 >>

Kaz Muzik Blog Backup Project #27 - LiveJournalMonthlyParser & LivrJournalMonthlyManager - KazMuzik Blog
2007-11-11 10:47

以前の方法では、このブログのバックアップがとれなくなったため、新しい方法が必要になりました。ヒントは Google Search にありました。うざいと思っていた calendar の月の summary page を、逆に利用してしまう方法です。このブログは、去年の 9月から始めたので、それからの月ごとのページをすべて fetch してくれば、エントリの内容まではわかりませんが、ID やタイトル、時刻の一覧表は作成できます。以前の方法では、エントリの数が多くなると、例え可能だったとしても、"/?skip=NNN" で何回アクセスすればいいかわかりませんでしたが、このアイデアによる方法では、月の数だけアクセスすれば、必ず、すべての ID が取得できます。今月だったら、(2007 - 2006) x 12 + (11 - 9) + 1 = 15回です。

まずは、月の summary page を parse するクラスです。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Calendar;
import java.util.Date;

public class LiveJournalMonthlyParser extends BufferedReader {

  private int yyyy;
  private int mm;
  private int dd;

  public LiveJournalMonthlyParser(Reader in) throws IOException {
    super(in);
  }

  public void close() throws IOException {
    super.close();
  }

  public LiveJournalEntry parse() throws IOException {
    int mode = 0;
    while (true) {
      String line = readLine();
      if (line == null) {
        break;
      }
      if (mode == 1) {
        int n = line.indexOf(".livejournal.com/");
        yyyy = Integer.parseInt( line.substring(n+17, n+21) );
        mm   = Integer.parseInt( line.substring(n+22, n+24) );
        dd   = Integer.parseInt( line.substring(n+25, n+27) );
        mode = 0;
        continue;
      }
      if (mode == 2) {
        int n = line.indexOf(':');
        int _hh = Integer.parseInt( line.substring(n-2,n) );
        int _mm = Integer.parseInt( line.substring(n+1,n+3) );
        if (line.charAt(n+4) == 'p') {
          _hh += 12;
        }
        Calendar cal = Calendar.getInstance();
        cal.set(yyyy, mm-1, dd, _hh, _mm);
        Date date = cal.getTime();
        n = line.indexOf(".livejournal.com/");
        int m = line.indexOf('.', n+17);
        int id = Integer.parseInt( line.substring(n+17,m) );
        n = line.indexOf("</a>", m+7);
        String title = line.substring(m+7,n);
        LiveJournalEntry entry = new LiveJournalEntry(id);
        entry.setTitle(title);
        entry.setDate(date);
        return entry;
      }
      if (line.indexOf("class=\"entryDate\"") >= 0) {
        mode = 1;
        continue;
      }
      if (line.indexOf("class=\"entry\"") >= 0) {
        mode = 2;
        continue;
      }
    }
    return null;
  }
}

次は、これを利用して、月ごとに entry を管理するクラスです。
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.Formatter;
import java.util.List;

public class LiveJournalMonthlyManager {
  public LiveJournalMonthlyManager() {
  }

  public List getEntries(int yyyy, int mm)
      throws IOException {
    String urlString = getURLString(yyyy, mm);
    URL url = new URL( getURLString(yyyy, mm) );
    InputStream is = null;
    try {
      is = url.openStream();
    }
    catch (Exception e) {
      System.err.printf("! %s : %s%n", urlString, e.getMessage());
      return null;
    }
    if (is == null) {
      return null;
    }
    LiveJournalMonthlyParser parser
      = new LiveJournalMonthlyParser(new InputStreamReader(is, "UTF-8"));
    List list = new ArrayList();
    while (true) {
      LiveJournalEntry entry = parser.parse();
      if (entry == null) {
        break;
      }
      list.add(entry);
    }
    parser.close();
    return list;
  }

  private static String getURLString(int yyyy, int mm) {
    Formatter f = new Formatter();
    f.format("http://kazuomik.livejournal.com/%04d/%02d/", yyyy, mm);
    return f.toString();
  }
  
  public static void main(String[] args) throws Exception {
    LiveJournalMonthlyManager manager = new LiveJournalMonthlyManager();
    int yyyy = 2006;
    int mm = 9;
    while (true) {
      List list = manager.getEntries(yyyy, mm);
      if (list == null || list.size() < 1) {
        break;
      }
      for (LiveJournalEntry entry : list) {
        Date time = entry.getDate();
        System.out.printf("%tF %tR\t%d\t%s%n",
          time, time, entry.getId(), entry.getTitle());
      }
      if (++mm > 12) {
        yyyy++;
        mm -= 12;
      }
    }
  }
}

main() メソッドで、すべてのエントリの時刻、ID、タイトルをプリントします。次(#28)は、これを実行します。

Tags: programming