読書メーターとブクログに登録した本&コメントを同期するプログラムをバージョンアップしました
先日のブクログのリニューアルに対応し、読書メーターとブクログを同期するプログラムをバージョンアップしました。
使い方は以前に作成したプログラムと同様ですので、詳しくは読書メーターとブクログに登録した本&コメントを同期するプログラムを作ったよを参照ください。
ソースコード
以下、バージョンアップ後のソースコードです。
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; String status; String tags; String create_on_y; String create_on_m; String create_on_d; String create_on_h; String create_on_i; String create_on_s; // ブクログに本が登録されていることを確認する。 if ( booklog.containsKey( isbn ) ) { // ブクログのカテゴリを取得する。 cate = booklog.get( isbn ).get( "cate" ); // ブクログのランクを取得する。 rank = booklog.get( isbn ).get( "rank" ); // ブクログの読書状況を取得する。 status = booklog.get( isbn ).get( "status" ); // ブクログのタグを取得する。 tags = booklog.get( isbn ).get( "tags" ); // ブクログの登録日時を取得する。 create_on_y = booklog.get( isbn ).get( "create_on_y" ); create_on_m = booklog.get( isbn ).get( "create_on_m" ); create_on_d = booklog.get( isbn ).get( "create_on_d" ); create_on_h = booklog.get( isbn ).get( "create_on_h" ); create_on_i = booklog.get( isbn ).get( "create_on_i" ); create_on_s = booklog.get( isbn ).get( "create_on_s" ); } else { cate = "0"; rank = "0"; status = "0"; tags = ""; create_on_y = ""; create_on_m = ""; create_on_d = ""; create_on_h = ""; create_on_i = ""; create_on_s = ""; } // 更新する本の情報をマップに格納する。 Map<String, String> updateInfo = new HashMap<String, String>(); updateInfo.put( "isbn", isbn ); updateInfo.put( "comment", comment ); updateInfo.put( "cate", cate ); updateInfo.put( "rank", rank ); updateInfo.put( "status", status ); updateInfo.put( "tags", tags ); updateInfo.put( "create_on_y", create_on_y ); updateInfo.put( "create_on_m", create_on_m ); updateInfo.put( "create_on_d", create_on_d ); updateInfo.put( "create_on_h", create_on_h ); updateInfo.put( "create_on_i", create_on_i ); updateInfo.put( "create_on_s", create_on_s ); // 更新する本の情報を一覧に追加する。 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 = "UTF-8"; /** * クッキーを取得する。 * @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( "/login", cookie ); // ログイン情報を送信する。 String query = "account=" + userid + "&password=" + 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( "<dd class=\"byebye\">([^<]*) さん" ); 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( "<a href=\"/edit/([^\"]*)\" title=\"[^\"]*\">" ); // 「本の編集・削除画面」の全ページについて、以下を繰り返す。 while ( true ) { // 本の編集・削除画面に接続する。 HttpURLConnection conn = openConnection( "/list?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( "/edit/" + isbn, cookie ); // 本の画面からHTMLを取得する。 String html = getHTML( conn ); // 接続を閉じる。 closeConnection( conn ); ////////////////////////////////////////////////////////////////// // HTMLから本の情報を取得する。 ////////////////////////////////////////////////////////////////// String tmp; // コメント String comment = findGroup( html, "<textarea name=\"description\" class=\"inputarea\" style=\"height:180px;\">([^<]*)</textarea>" ); // カテゴリ tmp = findGroup( html, "<select id=\"category_edit\" name=\"category_id\" class=\"inputselect\">(.*?)</select>" ); String cate = findGroup( tmp, "<option value=\"([^\"]*)\" selected=\"selected\">" ); // ランク tmp = findGroup( html, "<select name=\"rank\" class=\"inputselect\">(.*?)</select>" ); String rank = findGroup( tmp, "<option value=\"([^\"]*)\" selected=\"selected\">" ); // 読書状況 tmp = findGroup( html, "<select name=\"status\" class=\"inputselect\">(.*?)</select>" ); String status = findGroup( tmp, "<option value=\"([^\"]*)\" selected=\"selected\">" ); // タグ String tags = findGroup( html, "<input type=\"text\" name=\"tags\" value=\"([^\"]*)\" class=\"inputtext\" />" ); // 登録日時 String create_on_y = findGroup( html, "<input type=\"text\" id=\"create_on_y\" name=\"create_on_y\" value=\"([^\"]*)\" maxlength=\"4\" class=\"inputtext\" style=\"width:40px;\" />" ); String create_on_m = findGroup( html, "<input type=\"text\" id=\"create_on_m\" name=\"create_on_m\" value=\"([^\"]*)\" maxlength=\"2\" class=\"inputtext\" style=\"width:20px;\" />" ); String create_on_d = findGroup( html, "<input type=\"text\" id=\"create_on_d\" name=\"create_on_d\" value=\"([^\"]*)\" maxlength=\"2\" class=\"inputtext\" style=\"width:20px;\" />" ); String create_on_h = findGroup( html, "<input type=\"text\" id=\"create_on_h\" name=\"create_on_h\" value=\"([^\"]*)\" maxlength=\"2\" class=\"inputtext\" style=\"width:20px;\" />" ); String create_on_i = findGroup( html, "<input type=\"text\" id=\"create_on_i\" name=\"create_on_i\" value=\"([^\"]*)\" maxlength=\"2\" class=\"inputtext\" style=\"width:20px;\" />" ); String create_on_s = findGroup( html, "<input type=\"text\" id=\"create_on_s\" name=\"create_on_s\" value=\"([^\"]*)\" maxlength=\"2\" class=\"inputtext\" style=\"width:20px;\" />" ); // 本の情報をマップに格納する。 Map<String, String> info = new HashMap<String, String>(); info.put( "comment", comment ); info.put( "cate", cate ); info.put( "rank", rank ); info.put( "status", status ); info.put( "tags", tags ); info.put( "create_on_y", create_on_y ); info.put( "create_on_m", create_on_m ); info.put( "create_on_d", create_on_d ); info.put( "create_on_h", create_on_h ); info.put( "create_on_i", create_on_i ); info.put( "create_on_s", create_on_s ); 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" ); String status = book.get( "status" ); String tags = book.get( "tags" ); String create_on_y = book.get( "create_on_y" ); String create_on_m = book.get( "create_on_m" ); String create_on_d = book.get( "create_on_d" ); String create_on_h = book.get( "create_on_h" ); String create_on_i = book.get( "create_on_i" ); String create_on_s = book.get( "create_on_s" ); // 本の編集画面に接続する。 HttpURLConnection conn = openConnection( "/edit/" + isbn, cookie ); // 本の追加情報を送信する。 String query = "_method=add"; 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 ); // 本の編集画面に接続する。 conn = openConnection( "/edit/" + isbn, cookie ); // 本の変更情報を送信する。 query = "_method=edit&category_id=" + cate + "&rank=" + rank + "&status=" + status + "&description=" + comment + "&tags=" + tags + "&create_on_y=" + create_on_y + "&create_on_m=" + create_on_m + "&create_on_d=" + create_on_d + "&create_on_h=" + create_on_h + "&create_on_i=" + create_on_i + "&create_on_s=" + create_on_s; conn.setDoOutput( true ); conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" ); conn.setRequestProperty( "Content-Length", query.length() + "" ); 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 ); } }