読書メーターとブクログに登録した本&コメントを同期するプログラムを作ったよ
背景
僕は読書関連ネットサービスを2つ利用しています。
読書メーターの良い点は、先月のコメントをまとめられる点です。まとめた内容はブログに貼りつけることができます。一方、ブクログの良い点は、登録した本を「本棚」として見せられる点です。本棚はブログパーツとしても利用できます。
どちらにも良い点があるので同時に使っていますが、本やコメントの登録を2回ずつするのが面倒です。
実行環境
jdk1.5以上があれば動くと思います。以下の環境で動作確認しました。
OS | jdk |
---|---|
Windows XP SP2 | jdk 1.6.0_10 |
Ubuntu 8.10 | jdk 1.6.0_10 |
SunOS 5.10 | jdk 1.5.0_12 |
使い方
1. ソースコードのコンパイル
ソースコードは以下の三つです。(後ろの方に全文掲載しています。)
これらをjavacコマンドでコンパイルします。
javac DokushoMeterBooklogMatching.java DokushoMeterAccess.java BooklogAccess.java
2. プログラムの起動
javaコマンドで、プログラムを起動します。
java DokushoMeterBooklogMatching
すると、以下の内容が表示されます。
■■読書メータとブクログの情報を比較します。■■
3. アカウント情報の入力
その後、アカウント情報の入力が求められるので、自分のアカウント情報を入力します。
アカウント情報を入力してください。 ■読書メーター メールアドレス: 読書メーターのメールアドレスを入力する。 パスワード: 読書メーターのパスワードを入力する。 ■ブクログ ユーザID: ブクログのユーザIDを入力する。 パスワード: ブクログのパスワードを入力する。
もし、アカウント情報を手で入力するのが面倒な場合は、アカウント情報をファイルに記録しておくこともできます。
アカウントファイルの先頭の4行に以下の内容を書き込んでおきます。
読書メーターのメールアドレス 読書メーターのパスワード ブクログのユーザID ブクログのパスワード
プログラムの起動時に「-l」オプションでアカウントファイルの名前を指定すると、ファイルからアカウント情報が取得されます。
java DokushoMeterBooklogMatching -lアカウントファイルの名前
以下のように表示され、アカウント情報の入力が不要になります。
アカウント情報をファイルから取得しました。ファイル名=[アカウントファイルの名前]
4. 読書メーターとブクログの情報取得
アカウント情報の入力後、プログラムは読書メーターとブクログから本の情報を取得します。アカウント情報の入力ミスによりログインに失敗すると、プログラムはエラー終了します。
本の登録数によっては、この処理には時間がかかることがあります。
ソースコード
以下に、ソースコードを全文掲載します。
DokushoMeterBooklogMatching.java
import java.io.*; import java.util.*; /** * 読書メーター・ブクログの比較・同期プログラム * @author nattou_curry */ public class DokushoMeterBooklogMatching { /** * メインルーチン */ public static void main( String[] args ) throws Exception { System.out.println( "■■読書メータとブクログの情報を比較します。■■" ); System.out.println(); ////////////////////////////////////////////////////////// // アカウント情報を取得取得する。 ////////////////////////////////////////////////////////// String mail_DokushoMeter = ""; // メールアドレス(読書メーター) String password_DokushoMeter = ""; // パスワード(読書メーター) String userid_Booklog = ""; // ユーザID(ブクログ) String password_Booklog = ""; // パスワード(ブクログ) boolean accountOK = false; // アカウント情報取得成功フラグ // 引数を確認する。 if ( args.length >= 1 && args[0].startsWith( "-l" ) ) { // 「-l」が指定されている: ////////////////////////////////////////////////////////// // アカウント情報をアカウントファイルから取得する。 ////////////////////////////////////////////////////////// // アカウントファイルの名前を取得する。 String accountFile = args[0].substring( 2 ); BufferedReader reader = null; try { // アカウントファイルを開く。 reader = new BufferedReader( new FileReader( accountFile ) ); // アカウントファイルからアカウント情報を読み取る。 mail_DokushoMeter = reader.readLine(); password_DokushoMeter = reader.readLine(); userid_Booklog = reader.readLine(); password_Booklog = reader.readLine(); // アカウント情報取得成功。 accountOK = true; System.out.println( "アカウント情報をファイルから取得しました。ファイル名=[" + accountFile + "]" ); } catch ( IOException e ) { System.out.println( "アカウント情報を正常に読み込めませんでした。ファイル名=[" + accountFile + "]" ); System.out.println(); } finally { // ファイルを閉じる。 if ( reader != null ) { try { reader.close(); } catch ( IOException e ) { /* 無視 */ } } } } if ( ! accountOK ) { ////////////////////////////////////////////////////////// // アカウント情報を入力してもらう。 ////////////////////////////////////////////////////////// System.out.println( "アカウント情報を入力してください。" ); System.out.println( "■読書メーター" ); mail_DokushoMeter = getInput( "メールアドレス: " ); password_DokushoMeter = getInput( "パスワード: " ); System.out.println( "■ブクログ" ); userid_Booklog = getInput( "ユーザID: " ); password_Booklog = getInput( "パスワード: " ); } System.out.println(); ////////////////////////////////////////////////////////// // 読書メータに登録した本の情報を取得する。 ////////////////////////////////////////////////////////// Map<String, Map<String, String>> dokushoMeter = getDokushoMeterBookInfo( mail_DokushoMeter, password_DokushoMeter ); ////////////////////////////////////////////////////////// // ブクログに登録した本の情報を取得する。 ////////////////////////////////////////////////////////// Map<String, Map<String, String>> booklog = getBooklogBookInfo( userid_Booklog, password_Booklog ); ////////////////////////////////////////////////////////// // 読書メータとブクログの登録内容を比較し、 // 以下の条件に該当する本の一覧を作成する。 // [条件] // ・読書メータに登録しているが、ブクログには登録していない。 // ・読書メータとブクログでコメントが異なる。 ////////////////////////////////////////////////////////// List<String> diffList = new ArrayList<String>(); // 読書メーターに登録した全ての本について、以下を繰り返す。 for ( String isbn : dokushoMeter.keySet() ) { // ブクログに同じ本を登録していることを確認する。 if ( ! booklog.containsKey( isbn ) ) { // ブクログに登録していない: diffList.add( isbn ); } else { // 読書メータとブクログのコメントが一致することを確認する。 String dokushoComment = dokushoMeter.get( isbn ).get( "comment" ); String booklogComment = booklog.get( isbn ).get( "comment" ); if ( ! dokushoComment.equals( booklogComment ) ) { // コメントが異なる: diffList.add( isbn ); } } } ////////////////////////////////////////////////////////// // 比較結果を出力 ////////////////////////////////////////////////////////// // 読書メータとブクログの本の情報に違いがあることを確認する。 int diffSize = diffList.size(); if ( diffSize == 0 ) { // 違いがない: System.out.println( "●違いは見つかりませんでした。" ); // 処理を終了する。 return; } // 違いがある本のタイトルを出力する。 System.out.println( "●" + diffSize + "冊の本で違いが見つかりました。" ); for ( int i = 0; i < diffList.size(); ++i ) { String isbn = diffList.get( i ); String title = dokushoMeter.get( isbn ).get( "title" ); System.out.println( "・" + title ); } System.out.println(); ////////////////////////////////////////////////////////// // 読書メータのコメントをブクログに反映する。 ////////////////////////////////////////////////////////// System.out.println( "■■読書メータのコメントをブクログに反映します。■■" ); // 処理を継続するかユーザに確認する。 String result = getInput( "読書メーターのコメントをブクログに反映してよろしいですか?(y or n): " ); System.out.println(); result = result.toLowerCase(); if ( ! result.equals( "y" ) ) { // ユーザが処理の中断を選ぶ: System.out.println( "処理を中断しました。" ); return; } // 全ての違いがある本について以下を繰り返し、更新する本の情報の一覧を作成する。 List<Map<String, String>> updateBooks = new ArrayList<Map<String, String>>(); for ( int i = 0; i < diffList.size(); ++i ) { String isbn = diffList.get( i ); // 読書メーターのコメントを取得する。 String comment = dokushoMeter.get( isbn ).get( "comment" ); String cate; String rank; // ブクログに本が登録されていることを確認する。 if ( booklog.containsKey( isbn ) ) { // ブクログのカテゴリを取得する。 cate = booklog.get( isbn ).get( "cate" ); // ブクログのランクを取得する。 rank = booklog.get( isbn ).get( "rank" ); } else { cate = "-1"; rank = "3"; } // 更新する本の情報をマップに格納する。 Map<String, String> updateInfo = new HashMap<String, String>(); updateInfo.put( "isbn", isbn ); updateInfo.put( "comment", comment ); updateInfo.put( "cate", cate ); updateInfo.put( "rank", rank ); // 更新する本の情報を一覧に追加する。 updateBooks.add( updateInfo ); } // ブクログの更新を行う。 updateBooklogBooks( userid_Booklog, password_Booklog, updateBooks ); System.out.println( "ブクログの更新を終了しました。" ); } /** * 読書メータに登録した本の情報を取得する。 * @param mail メールアドレス * @param password パスワード * @return 本の情報 */ public static Map<String, Map<String, String>> getDokushoMeterBookInfo( String mail, String password ) throws Exception { // 読書メーターにログインする。 String cookie = DokushoMeterAccess.login( mail, password ); // ログイン情報を取得し、ログインに成功したことを確認する。 Map<String, String> loginInfo = DokushoMeterAccess.getLoginInfo( cookie ); if ( ! mail.equals( loginInfo.get( "mail" ) ) ) { // ログイン失敗: throw new Exception( "ログイン失敗" ); } // ログイン情報からユーザIDを取得する。 String userid = loginInfo.get( "userid" ); // 読み終わった本の一覧を取得する。 String[] bookList = DokushoMeterAccess.getBookList( cookie, userid ); // 全ての本について、以下を繰り返す。 Map<String, Map<String, String>> bookInfo = new HashMap<String, Map<String, String>>(); for ( int i = 0; i < bookList.length; ++i ) { String isbn = bookList[i]; // 本のコメントを取得する Map<String, String> info = DokushoMeterAccess.getBookInfo( cookie, isbn ); // 本の情報をマップに格納する。 bookInfo.put( isbn, info ); } return bookInfo; } /** * ブクログに登録した本の情報を取得する。 * @param userid ユーザID * @param password パスワード * @return 本の情報 */ public static Map<String, Map<String, String>> getBooklogBookInfo( String userid, String password ) throws Exception { // ブクログからクッキーを取得する。 String cookie = BooklogAccess.getCookie(); // ブクログにログインする。 BooklogAccess.login( cookie, userid, password ); // ログイン情報を取得し、ログインに成功したことを確認する。 Map loginInfo = BooklogAccess.getLoginInfo( cookie ); if ( ! userid.equals( loginInfo.get( "username" ) ) ) { // ログイン失敗: throw new Exception( "ログイン失敗" ); } // 本一覧を取得する。 String[] itemList = BooklogAccess.getBookList( cookie ); // 全ての本について、以下を繰り返す。 Map<String, Map<String, String>> bookInfo = new HashMap<String, Map<String, String>>(); for ( int i = 0; i < itemList.length; ++i ) { String isbn = itemList[i]; // 本の情報を取得する Map<String, String> info = BooklogAccess.getBookInfo( cookie, isbn ); // 本の情報をマップに格納する。 bookInfo.put( isbn, info ); } return bookInfo; } /** * ブクログの本の情報を更新する。 * @param userid ユーザID * @param password パスワード * @param books 本の情報 * @return 本の情報 */ public static void updateBooklogBooks( String userid, String password, List<Map<String, String>> updateBooks ) throws Exception { // ブクログからクッキーを取得する。 String cookie = BooklogAccess.getCookie(); // ブクログにログインする。 BooklogAccess.login( cookie, userid, password ); // ログイン情報を取得し、ログインに成功したことを確認する。 Map loginInfo = BooklogAccess.getLoginInfo( cookie ); if ( ! userid.equals( loginInfo.get( "username" ) ) ) { // ログイン失敗: throw new Exception( "ログイン失敗" ); } // 本の情報を更新する。 for ( int i = 0; i < updateBooks.size(); ++i ) { Map<String, String> book = updateBooks.get( i ); BooklogAccess.updateBook( cookie, book ); } } /** * ユーザの入力値を取得する。 * @param prompt 表示するプロンプト * @return 入力値 */ private static String getInput( String prompt ) throws Exception { System.out.print( prompt ); BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) ); return reader.readLine(); } }
DokushoMeterAccess.java
import java.net.*; import java.io.*; import java.util.*; import java.util.regex.*; /** * 読書メーター接続 * @author nattou_curry */ public class DokushoMeterAccess { // 読書メータのエンコード private static final String ENCODING = "UTF-8"; /** * ログインする。 * @param mail メールアドレス * @param password パスワード * @return クッキー */ public static String login( String user, String password ) throws Exception { // ログイン画面への接続を開く。 HttpURLConnection conn = openConnection( "/login" ); // ログイン情報を送信する。 String query = "mail=" + user + "&password=" + password + "&work="; conn.setDoOutput( true ); conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" ); conn.setRequestProperty( "Content-Length", query.length() + "" ); OutputStreamWriter out = new OutputStreamWriter( conn.getOutputStream(), ENCODING ); out.write( query ); out.flush(); out.close(); // レスポンスヘッダより、クッキーを取得する。 Map<String, List<String>> header = conn.getHeaderFields(); List<String> cookies = header.get( "Set-Cookie" ); if ( cookies == null ) { // クッキーが取得できない。 throw new Exception( "ログイン失敗" ); } String cookie = ""; for ( int i = 0; i < cookies.size(); ++i ) { cookie += cookies.get( i ) + "; "; } // 接続を閉じる。 closeConnection( conn ); return cookie; } /** * ログイン情報を取得する。 * @param cookie クッキー * @param ログイン情報のマップ。userid: ユーザID、username: ユーザ名。 */ public static Map<String, String> getLoginInfo( String cookie ) throws Exception { // トップ画面への接続を開く。 HttpURLConnection conn = openConnection( "/account", cookie ); // トップ画面のHTMLを取得する。 String html = getHTML( conn ); // 接続を閉じる。 closeConnection( conn ); // HTMLからログイン情報を見つける。 Pattern p = Pattern.compile( "<a href=\"/u/([^\"]*)\">([^<]*)</a>でログイン中" ); Matcher m = p.matcher( html ); if ( ! m.find() ) { // ログイン情報が見つからない: throw new Exception( "ログインしていません。" ); } // ログイン情報をマップに設定する。 Map<String, String> loginInfo = new HashMap<String, String>(); loginInfo.put( "userid", m.group( 1 ) ); p = Pattern.compile( "<th><label for=\"mail\">メールアドレス</label></th>[\\r\\n\\t ]*<td>([^ ]*) \\[<a href=\"/mail_edit.php\">変更する</a>\\]</td>" ); m = p.matcher( html ); if ( ! m.find() ) { // メールアドレスが見つからない: throw new Exception( "メールアドレスが見つかりません。" ); } loginInfo.put( "mail", m.group( 1 ) ); return loginInfo; } /** * 読み終わった本の一覧を取得する。 * @param cookie クッキー * @param userid ユーザID * @return 本(isbn)の一覧 */ public static String[] getBookList( String cookie, String userid ) throws Exception { List<String> booklist = new ArrayList<String>(); // 本(isbn)の一覧 int page = 1; // ページ番号 // 「読み終わった本の一覧画面」の全ページについて、以下を繰り返す。 while ( true ) { // 読み終わった本の一覧画面に接続する。 HttpURLConnection conn = openConnection( "/u/" + userid + "/booklist&p=" + page, cookie); // 読み終わった本の一覧画面のHTMLを取得する。 String html = getHTML( conn ); // 接続を閉じる。 closeConnection( conn ); // HTMLに本の情報が含まれていることを確認する。 if ( html.contains( "まだ登録した本はありません。" ) ) { // 本の情報が含まれていない: // 処理を中断する。 break; } // 本の情報を取得する。 Pattern p = Pattern.compile( "<div class=\"book\"><a href=\"/b/([^\"]*)\">" ); Matcher m = p.matcher( html ); while ( m.find() ) { // 本(isbn)を一覧に追加する。 booklist.add( m.group( 1 ) ); } // 次のページに進む。 ++page; } return booklist.toArray( new String[0] ); } /** * 本の情報を取得する。 * @param cookie クッキー * @param isbn 本のISBN * @return 本の情報のマップ。title: タイトル、comment: コメント。 */ public static Map<String, String> getBookInfo( String cookie, String isbn ) throws Exception { // 本の画面に接続する。 HttpURLConnection conn = openConnection( "/b/" + isbn, cookie ); // 本の画面からHTMLを取得する。 String html = getHTML( conn ); // 接続を閉じる。 closeConnection( conn ); Pattern p; Matcher m; // HTMLからタイトルを取得する。 p = Pattern.compile( "<h1 id=\"title\">([^<]*)</h1>" ); m = p.matcher( html ); m.find(); String title = m.group( 1 ); // HTMLからコメントを取得する。 p = Pattern.compile( "<input type=\"text\" name=\"comment\" value=\"([^\"]*)\" class=\"input_b_comment\">" ); m = p.matcher( html ); m.find(); String comment = m.group( 1 ); // 本の情報をマップに格納する。 Map<String, String> info = new HashMap<String, String>(); info.put( "title", title ); info.put( "comment", comment ); return info; } /** * 読書メーターへの接続を開く。 * @param requestURI リクエストURI */ public static HttpURLConnection openConnection( String requestURI ) throws Exception { return openConnection( requestURI, null ); } /** * 読書メーターへの接続を開く。 * @param requestURI リクエストURI * @param cookie クッキー */ public static HttpURLConnection openConnection( String requestURI, String cookie ) throws Exception { URL url = new URL( "http://book.akahoshitakuya.com" + requestURI ); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setInstanceFollowRedirects( false ); conn.setRequestProperty( "Host", "book.akahoshitakuya.com" ); conn.setRequestProperty( "User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6" ); conn.setRequestProperty( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ); conn.setRequestProperty( "Accept-Language", "ja,en-us;q=0.7,en;q=0.3" ); conn.setRequestProperty( "Accept-Encoding", "gzip,deflate" ); conn.setRequestProperty( "Accept-Charset", "Shift_JIS,utf-8;q=0.7,*;q=0.7" ); conn.setRequestProperty( "Keep-Alive", "300" ); conn.setRequestProperty( "Connection", "keep-alive" ); conn.setRequestProperty( "Referer", "http://book.akahoshitakuya.com" ); if ( cookie != null ) { conn.setRequestProperty( "Cookie", cookie ); } return conn; } /** * 読書メーターへの接続を閉じる。 * @param conn 接続 */ public static void closeConnection( HttpURLConnection conn ) { try { OutputStream out = conn.getOutputStream(); out.close(); } catch ( Exception e ) {} try { InputStream in = conn.getInputStream(); in.close(); } catch ( Exception e ) {} } /** * 接続先のHTMLを取得する。 * @param conn 接続 * @return HTML */ public static String getHTML( HttpURLConnection conn ) throws Exception { BufferedReader in = new BufferedReader( new InputStreamReader( conn.getInputStream(), ENCODING ) ); StringBuffer buf = new StringBuffer(); int c; while ( ( c = in.read() ) != -1 ) { buf.append( (char) c ); } in.close(); return buf.toString(); } }
BooklogAccess.java
import java.net.*; import java.io.*; import java.util.*; import java.util.regex.*; /** * ブクログ接続 * @author nattou_curry */ public class BooklogAccess { // ブクログのエンコード private static final String ENCODING = "EUC-JP"; /** * クッキーを取得する。 * @reurn クッキー */ public static String getCookie() throws Exception { // トップ画面への接続を開く。 HttpURLConnection conn = openConnection( "/" ); // クッキーを取得する。 String cookie = conn.getHeaderField( "Set-Cookie" ); // 接続を閉じる。 closeConnection( conn ); return cookie; } /** * ログインする。 * @param userid ユーザID * @param password パスワード */ public static void login( String cookie, String userid, String password ) throws Exception { // ログイン画面への接続を開く。 HttpURLConnection conn = openConnection( "/uhome.php", cookie ); // ログイン情報を送信する。 String query = "account=" + userid + "&pw=" + password + "&st=1"; conn.setDoOutput( true ); conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" ); conn.setRequestProperty( "Content-Length", query.length() + "" ); OutputStreamWriter out = new OutputStreamWriter( conn.getOutputStream(), ENCODING ); out.write( query ); out.flush(); out.close(); // 接続を閉じる。 closeConnection( conn ); } /** * ログイン情報を取得する。 * @param cookie クッキー * @param ログイン情報を設定したマップ。username: ユーザ名。 * @return ログイン情報 */ public static Map<String, String> getLoginInfo( String cookie ) throws Exception { // トップ画面への接続を開く。 HttpURLConnection conn = openConnection( "/", cookie ); // トップ画面のHTMLを取得する。 String html = getHTML( conn ); // 接続を閉じる。 closeConnection( conn ); // HTMLからログイン情報を見つける。 Pattern p = Pattern.compile( "<a href=\"/setup.php\">ようこそ([^<]*)さん</a>" ); Matcher m = p.matcher( html ); if ( ! m.find() ) { // ログイン情報が見つからない: throw new Exception( "ログインしていません。" ); } // ログイン情報をマップに設定する。 Map<String, String> loginInfo = new HashMap<String, String>(); loginInfo.put( "username", m.group( 1 ) ); return loginInfo; } /** * 本の一覧を取得する。 * @param cookie クッキー * @return 本(isbn)の一覧 */ public static String[] getBookList( String cookie ) throws Exception { List<String> itemList = new ArrayList<String>(); // 本(isbn)の一覧 int page = 0; // ページ番号 Pattern p = Pattern.compile( "<td class=\"cell2\"><a href=\"http://booklog.jp/users/[^/]*/archives/([^\"]*)\" target=\"_blank\"><img src=\"[^\"]*\" width=\"50\"></a></td>" ); // 「本の編集・削除画面」の全ページについて、以下を繰り返す。 while ( true ) { // 本の編集・削除画面に接続する。 HttpURLConnection conn = openConnection( "/editbook.php?page=" + page, cookie ); // 本の編集・削除画面のHTMLを取得する。 String html = getHTML( conn ); // 接続を閉じる。 closeConnection( conn ); // 本の情報を取得する。 Matcher m = p.matcher( html ); if ( !m.find() ) { break; } do { // 本(isbn)を一覧に追加する。 itemList.add( m.group( 1 ) ); } while ( m.find() ); // 次のページに進む。 ++page; } return itemList.toArray( new String[0] ); } /** * 本の情報を取得する。 * @param cookie クッキー * @param isbn 本のisbn * @return 本の情報を格納したマップ。comment: コメント、cate: カテゴリ、rank: ランク */ public static Map<String, String> getBookInfo( String cookie, String isbn ) throws Exception { // 本の画面に接続する。 HttpURLConnection conn = openConnection( "/addbook.php?mode=ItemLookup&asin=" + isbn, cookie ); // 本の画面からHTMLを取得する。 String html = getHTML( conn ); // 接続を閉じる。 closeConnection( conn ); ////////////////////////////////////////////////////////////////// // HTMLから本の情報を取得する。 ////////////////////////////////////////////////////////////////// String tmp; // コメント String comment = findGroup( html, "<textarea name=\"comment\" id=\"comment\" style=\"width: 100%; height: 200px;\">([^<]*)</textarea>" ); // カテゴリ tmp = findGroup( html, "<select name=\"cate\" id=\"cate\">(.*?)</select>" ); String cate = findGroup( tmp, "<option value=\"([^\"]*)\" selected>" ); // ランク tmp = findGroup( html, "<select name=\"rank\">(.*?)</select>" ); String rank = findGroup( tmp, "<option value=\"([^\"]*)\" selected>" ); // 本の情報をマップに格納する。 Map<String, String> info = new HashMap<String, String>(); info.put( "comment", comment ); info.put( "cate", cate ); info.put( "rank", rank ); return info; } /** * 本を更新する。 * @param cookie クッキー * @book 本の情報 * @comment コメント */ public static void updateBook( String cookie, Map<String, String> book ) throws Exception { String isbn = book.get( "isbn" ); String cate = book.get( "cate" ); String rank = book.get( "rank" ); String comment = book.get( "comment" ); // 本の更新画面に接続する。 HttpURLConnection conn = openConnection( "/addbook.php?searchindex=&keywords=&mode=ItemLookup&pages=&asin=" + isbn, cookie ); // 本の更新情報を送信する。 String query = "cate=" + cate + "&cate_name=&cate_info=&rank=" + rank + "&comment=" + comment + "&st=1&book_asin=" + isbn; conn.setDoOutput( true ); conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" ); conn.setRequestProperty( "Content-Length", query.length() + "" ); OutputStreamWriter out = new OutputStreamWriter( conn.getOutputStream(), ENCODING ); out.write( query ); out.flush(); out.close(); // 接続を閉じる。 closeConnection( conn ); } /** * ブクログへの接続を開く。 * @param requestURI リクエストURI * @return 接続 */ public static HttpURLConnection openConnection( String requestURI ) throws Exception { return openConnection( requestURI, null ); } /** * ブクログへの接続を開く。 * @param requestURI リクエストURI * @param cookie クッキー */ public static HttpURLConnection openConnection( String requestURI, String cookie ) throws Exception { URL url = new URL( "http://booklog.jp" + requestURI ); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setInstanceFollowRedirects( false ); conn.setRequestProperty( "Host", "booklog.jp" ); conn.setRequestProperty( "User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6" ); conn.setRequestProperty( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ); conn.setRequestProperty( "Accept-Language", "ja,en-us;q=0.7,en;q=0.3" ); conn.setRequestProperty( "Accept-Encoding", "gzip,deflate" ); conn.setRequestProperty( "Accept-Charset", "Shift_JIS,utf-8;q=0.7,*;q=0.7" ); conn.setRequestProperty( "Keep-Alive", "300" ); conn.setRequestProperty( "Connection", "keep-alive" ); conn.setRequestProperty( "Referer", "http://booklog.jp" ); if ( cookie != null ) { conn.setRequestProperty( "Cookie", cookie ); } return conn; } /** * ブクログへの接続を切断する。 * @param conn 接続 */ public static void closeConnection( HttpURLConnection conn ) { try { OutputStream out = conn.getOutputStream(); out.close(); } catch ( Exception e ) {} try { InputStream in = conn.getInputStream(); in.close(); } catch ( Exception e ) {} } /** * 接続先のHTMLを取得する。 * @param conn 接続 * @return HTML */ public static String getHTML( HttpURLConnection conn ) throws Exception { BufferedReader in = new BufferedReader( new InputStreamReader( conn.getInputStream(), ENCODING ) ); StringBuffer buf = new StringBuffer(); int c; while ( ( c = in.read() ) != -1 ) { buf.append( (char) c ); } in.close(); return buf.toString(); } /** * 入力文字列中で、正規表現の一番目の括弧(グループ)にマッチする部分文字列を返す。 * @param regex 正規表現 * @param input 入力文字列 * @return マッチする部分文字列。マッチしない場合、null。 */ public static String findGroup( String input, String regex ) { // 正規表現によるマッチングを行う。 Pattern p = Pattern.compile( regex, Pattern.DOTALL ); Matcher m = p.matcher( input ); if ( ! m.find() ) { // マッチしない: return null; } // 一番目の括弧(グループ)にマッチする部分文字列を取得する。 return m.group( 1 ); } }