Bloggerに接続するためのJavaコード

Bloggerに接続し、最新記事の取得と記事の投稿、削除を行うためのJavaソースコードです。
まずは、メモまで。

ソースコード

以下、ソースコードの全文です。

import java.net.*;
import javax.net.ssl.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import java.util.zip.*;
import java.text.*;

/**
 * Blogger接続
 * @author nattou_curry
 */
public class BloggerAccess {
	
	// Bloggerのエンコード
	private static final String ENCODING = "UTF-8";

	/**
	 * 動作確認用のmainメソッド。
	 */
	public static void main( String[] args ) throws Exception {

		// ログインする(SSL)。
		String cookie = loginWithSSL( "ユーザID", "パスワード" );
		
		// ログイン情報を取得する。
		Map<String, String> loginInfo = getLoginInfo( cookie );
		
		String url = loginInfo.get( "url" );
		String blogID = loginInfo.get( "blogID" );
		
		
		Map<String, String> postInfo = new HashMap<String, String>();
		postInfo.put( "url", url );
		postInfo.put( "blogID", blogID );
		postInfo.put( "pubDate", "2009/10/24 20:54" );
		postInfo.put( "title", "自動投稿DDD" );
		postInfo.put( "postBody", "投稿本文" );
		
		postNewEntry( cookie, postInfo );

		// 最新の記事情報の一覧を取得する。
		List< Map<String, String>> articleList = getArticleList( loginInfo );

		// 取得した記事情報を表示する。
		for ( int i = 0; i < articleList.size(); ++i ) {
			Map<String, String> articleInfo = articleList.get( i );
			
			String title = articleInfo.get( "title" );
			String link = articleInfo.get( "link" );
			String pubDate = articleInfo.get( "pubDate" );
			String content = articleInfo.get( "content" );
			
			System.out.println( title + " " + link + " " + pubDate + " " + content );
			
		}
	}

	/**
	 * ログインする(SSL)。
	 * @param mail メールアドレス
	 * @param password パスワード
	 * @return クッキー
	 */
	public static String loginWithSSL( String Email, String Passwd ) throws Exception {
		
		// クッキー
		String cookie = null;
		// クッキー編集用のマップ
		Map<String, String> cookiesMap = new HashMap<String, String>();
		
		// リダイレクト先URL
		String redirectURL;
		
		//////////////////////////////////////////////////////////////////
		// bloggerのログイン画面に接続し、ログインセキュリティトークンを取得する。
		//////////////////////////////////////////////////////////////////

		String loginSecurityToken = null;

		HttpURLConnection conn = null;
		try {
			// https://www.blogger.com/start
			conn = openConnection( "https://www.blogger.com/start" );
			
			String html = getHTML( conn );
			
			// ログインセキュリティトークンを取得する。
			Pattern p = Pattern.compile( "<input name=\"loginSecurityToken\" type=\"hidden\" value=\"([^\"]*)\">" );
			Matcher m = p.matcher( html );
			if ( ! m.find() ) {
				throw new Exception( "loginSecurityTokenを取得できません。" );
			}
			
			loginSecurityToken = m.group ( 1 );
			
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// bloggerのログイン画面に接続し、ログイン情報を送信する。
		//////////////////////////////////////////////////////////////////

		conn = null;
		try {
			// https://www.blogger.com/start
			conn = openConnection( "https://www.blogger.com/start" );

			// ログイン情報を送信する。
			String query = "loginSecurityToken=" + URLEncoder.encode( loginSecurityToken, ENCODING )
				+ "&d=" + URLEncoder.encode( "/home", ENCODING )
				+ "&Email=" + URLEncoder.encode( Email, ENCODING )
				+ "&Passwd=" + URLEncoder.encode( Passwd, ENCODING )
				+ "&ok=" + URLEncoder.encode( "ログイン", ENCODING );
			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();

			// クッキーを取得し、編集用のマップに設定する。
			putCookiesToMap( conn, cookiesMap );

			// 編集用のマップからクッキー文字列を作成する。
			cookie = cookiesMapToString( cookiesMap );
			
			// リダイレクト先URLを取得する。
			redirectURL = conn.getHeaderField( "Location" );
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// google.comのサービスログイン画面に接続し、GALXを取得する。
		//////////////////////////////////////////////////////////////////

		String galx;
		
		conn = null;
		try {
			// https://www.google.com/accounts/ServiceLogin
			conn = openConnection( redirectURL, cookie );
			
			// クッキーを取得し、編集用のマップに設定する。
			putCookiesToMap( conn, cookiesMap );

			// 編集用のマップからクッキー文字列を作成する。
			cookie = cookiesMapToString( cookiesMap );
			
			String html = getHTML( conn );
				
			// galxを取得する。
			Pattern p = Pattern.compile( "<input type=\"hidden\".*?name=\"GALX\".*?value=\"(.*?)\" />", Pattern.DOTALL );
			Matcher m = p.matcher( html );
			if ( ! m.find() ) {
				throw new Exception( "GALXを取得できません。" );
			}
			
			galx = m.group( 1 );
			
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		conn = null;

		//////////////////////////////////////////////////////////////////
		// google.comのサービスログイン認証画面に接続し、認証情報を送信する。
		//////////////////////////////////////////////////////////////////

		try {
			// https://www.google.com/accounts/ServiceLoginAuth
			conn = openConnection( "https://www.google.com/accounts/ServiceLoginAuth?service=blogger", cookie );
		
			// ログイン情報を送信する。
			String query = "continue=" + URLEncoder.encode( "https://www.blogger.com/loginz?d=%2Fhome&a=ADD_SERVICE_FLAG", ENCODING )
				+ "&service=blogger"
				+ "&naui=8"
				+ "&fpui=2"
				+ "&skipvpage=true"
				+ "&rm=false"
				+ "&hl=ja"
				+ "&alwf=true"
				+ "&alinsu=0"
				+ "&GALX=" + galx
				+ "&Email=" + Email
				+ "&Passwd=" + Passwd
				+ "&rmShown=1"
				+ "&signIn=" + URLEncoder.encode( "ログイン", ENCODING )
				+ "&asts=";
			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();

			// クッキーを取得し、編集用のマップに設定する。
			putCookiesToMap( conn, cookiesMap );

			// 編集用のマップからクッキー文字列を作成する。
			cookie = cookiesMapToString( cookiesMap );
			
			// リダイレクト先URLを取得する。
			redirectURL = conn.getHeaderField( "Location" );

		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// google.comのクッキー確認画面に接続する。
		//////////////////////////////////////////////////////////////////

		try {
			// https://www.google.com/accounts/CheckCookie
			conn = openConnection( redirectURL, cookie );
			conn.setRequestProperty( "Host", "www.google.com" );
			
			// クッキーを取得し、編集用のマップに設定する。
			putCookiesToMap( conn, cookiesMap );

			// 編集用のマップからクッキー文字列を作成する。
			cookie = cookiesMapToString( cookiesMap );
			
			String html = getHTML( conn );
			
			// Javascriptより、リダイレクト先URLを取得する。
			Pattern p = Pattern.compile( "location.replace\\(\"([^\"]*)\"\\)" );
			Matcher m = p.matcher( html );
			if ( ! m.find() ) {
				throw new Exception( "リダイレクト先URLが見つかりません。" );
			}
			redirectURL = m.group( 1 );
			redirectURL = redirectURL.replaceAll( "\\\\x3d", "=" );
			redirectURL = redirectURL.replaceAll( "\\\\x26", "&" );

		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// google.co.jpのSID設定画面に接続する。
		//////////////////////////////////////////////////////////////////

		try {
			// http://www.google.co.jp/accounts/SetSID
			conn = openConnection( redirectURL );
			conn.setRequestProperty( "Host", "www.google.co.jp" );
			
			// クッキーを取得し、編集用のマップに設定する。
			putCookiesToMap( conn, cookiesMap );

			// 編集用のマップからクッキー文字列を作成する。
			cookie = cookiesMapToString( cookiesMap );
			
			// リダイレクト先URLを取得する。
			redirectURL = conn.getHeaderField( "Location" );
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// google.comのサービスログイン画面に接続する。
		//////////////////////////////////////////////////////////////////

		conn = null;
		try {
			// https://www.google.com/accounts/ServiceLogin
			conn = openConnection( redirectURL, cookie );
			conn.setRequestProperty( "Host", "www.google.com" );
			
			// クッキーを取得し、編集用のマップに設定する。
			putCookiesToMap( conn, cookiesMap );

			// 編集用のマップからクッキー文字列を作成する。
			cookie = cookiesMapToString( cookiesMap );
			
			// リダイレクト先URLを取得する。
			redirectURL = conn.getHeaderField( "Location" );
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// bloggerのログインz画面に接続する。
		//////////////////////////////////////////////////////////////////

		conn = null;
		try {
			// https://www.blogger.com/loginz
			conn = openConnection( redirectURL, cookie );
			conn.setRequestProperty( "Host", "www.blogger.com" );
			
			// クッキーを取得し、編集用のマップに設定する。
			putCookiesToMap( conn, cookiesMap );

			// 編集用のマップからクッキー文字列を作成する。
			cookie = cookiesMapToString( cookiesMap );
			
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		return cookie;
	}
	
	/**
	 * レスポンスヘッダよりクッキーを取得し、編集用のマップに設定する。
	 * @param conn HTTP接続
	 * @param cookieMap クッキー編集用のマップ
	 */
	private static void putCookiesToMap( HttpURLConnection conn, Map<String, String> cookiesMap ) {

		List<String> cookies = null;

		// レスポンスヘッダより、クッキーを取得する。
		Map<String, List<String>> header = conn.getHeaderFields();
		for ( String key : header.keySet() ) {
			if ( key != null && key.compareToIgnoreCase( "set-cookie" ) == 0 ) {
				cookies = header.get( key );
				break;
			}
		}
		
		if ( cookies == null ) {
			// クッキーが取得できない場合:
			return;
		}
		
		// クッキーを分解し、編集用のマップに設定する。
		for ( int i = 0; i < cookies.size(); ++i ) {
			String cookieLine = cookies.get( i );
			String[] keyValuePairs = cookieLine.split( "; *" );
			
			for ( int j = 0; j < keyValuePairs.length; ++j ) {
				String keyValuePair = keyValuePairs[j];
				String[] keyValue = keyValuePair.split( "=", 2 );
				String key = keyValue[0];
				String value = null;
				
				if ( keyValue.length >= 2 ) {
					value = keyValue[1];
				}
				
				if ( "Domain".equals( key ) ) continue;
				if ( "HttpOnly".equals( key ) ) continue;
				if ( "Expires".equals( key ) ) continue;
				if ( "Secure".equals( key ) ) continue;
				if ( "Path".equals( key ) ) continue;

				if ( "EXPIRED".equals( value ) )continue;
				
				cookiesMap.put( key, value );
			}
		}
	}
	
	/**
	 * 編集用のマップからクッキー文字列を作成する。
	 * @param cookieMap クッキー編集用のマップ
	 * @return クッキー文字列
	 */
	private static String cookiesMapToString( Map<String, String> cookiesMap ) {
		
		StringBuffer cookie = new StringBuffer();
		for ( String key: cookiesMap.keySet() ) {
			String value = cookiesMap.get( key );
			
			if ( value != null ) {
				cookie.append( key + "=" + value + "; " );
			} else {
				cookie.append( key + "; " );
			}
		}
		
		return cookie.toString();
	}

	/**
	 * ログイン情報を取得する。
	 * @param cookie クッキー
	 * @param ログイン情報のマップ。urlPart: URLのユーザ固有部分。
	 */
	public static Map<String, String> getLoginInfo( String cookie ) throws Exception {

		String html;
		
		//////////////////////////////////////////////////////////////////
		// トップ画面に接続する。
		//////////////////////////////////////////////////////////////////

		HttpURLConnection conn = null;
		try {
			conn = openConnection( "http://www.blogger.com/home?pli=1", cookie );
			conn.setRequestProperty( "Host", "www.blogger.com" );
	
			// トップ画面のHTMLを取得する。
			html = getHTML( conn );
			
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// トップ画面のHTMLより、ログイン情報を取得する。
		//////////////////////////////////////////////////////////////////

		// ブログのURLを取得する。
		Pattern p = Pattern.compile( "<a href=\"http://((.*).blogspot.com)/\">ブログを表示</a>" );
		Matcher m = p.matcher( html );
		if ( ! m.find() ) {
			// URLが見つからない:
			throw new Exception( "URLが見つかりません。" );
		}
		String url = m.group( 1 );
		String urlPart = m.group( 2 );
			
		// ブログIDを取得する。
		p = Pattern.compile( "<a href=\"posts.g\\?blogID=(.*?)\">投稿を編集</a>" );
		m = p.matcher( html );
		if ( ! m.find() ) {
			// ブログIDが見つからない:
			throw new Exception( "ブログIDが見つかりません。" );
		}
		String blogID = m.group( 1 );

		Map<String, String> loginInfo = new HashMap<String, String>();
		loginInfo.put( "url", url );
		loginInfo.put( "urlPart", urlPart );
		loginInfo.put( "blogID", blogID );
		
		return loginInfo;
	}
	
	/**
	 * 最新の記事情報の一覧を取得する。
	 * @param cookie クッキー
	 * @param loginInfo ログイン情報。urlPart: URLのユーザ固有部分。
	 * @param 最新の記事情報の一覧。title: タイトル、link: 記事のURL、pubDate: 投稿日、content: 内容、postID: 投稿ID。
	 */
	public static List<Map<String, String>> getArticleList( Map<String, String> loginInfo ) throws Exception {
		
		List<Map<String, String>> articleList = new ArrayList<Map<String, String>>();

		//////////////////////////////////////////////////////////////////
		// RSSに接続し、最新の記事一覧を取得する。
		//////////////////////////////////////////////////////////////////
		
		String urlPart = loginInfo.get( "urlPart" );
		
		String rss;
		
		// RSSへの接続を開く。
		HttpURLConnection conn = null;
		try {
			
			conn = openConnection( "http://" + urlPart + ".blogspot.com/feeds/posts/default?alt=rss" );
			conn.setRequestProperty( "Host", urlPart + ".blogspot.com" );
			
			// RSSを取得する。
			rss = getHTML( conn );
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}

		//////////////////////////////////////////////////////////////////
		// RSSの各アイテムから記事情報を取得する。
		//////////////////////////////////////////////////////////////////

		Pattern p_item = Pattern.compile( "<item>(.*?)</item>", Pattern.DOTALL );
		Pattern p_title = Pattern.compile( "<title>([^<]*)</title>" );
		Pattern p_link = Pattern.compile( "<link>([^<]*)</link>" );

		Pattern p_postContent = Pattern.compile( "<div class='post-body entry-content'>(.*)<div style='clear: both;'></div>.*?</div>.*?<div class='post-footer'>", Pattern.DOTALL );
		Pattern p_published = Pattern.compile( "<abbr class='published' title='(.*?)'>" );
		Pattern p_postID = Pattern.compile( "<a href='http://www.blogger.com/post-edit.g\\?blogID=.*?&postID=(.*?)' title='投稿を編集'>" );
		
		SimpleDateFormat sdf_published = new SimpleDateFormat( "yyyy-MM-dd'T'HHmmssZ", Locale.US );
		SimpleDateFormat sdf_yyyymmddhhmm = new SimpleDateFormat( "yyyy/MM/dd HH:mm", Locale.US );

		Matcher m = p_item.matcher( rss );
		while( m.find() ) {
			String item = m.group( 1 );

			// タイトルを取得する。
			String title = null;
			Matcher m2 = p_title.matcher( item );
			if ( m2.find() ) {
				title = m2.group( 1 );
			}

			// 記事のURLを取得する。
			String link = null;
			m2 = p_link.matcher( item );
			if ( m2.find() ) {
				link = m2.group( 1 );
			}
			
			// URLにユーザ固有部分を含まない記事を除外する。
			if ( link.indexOf( urlPart ) == -1 ) {
				continue;
			}
			
			String html = null;
			
			//////////////////////////////////////////////////////////////////
			// 記事のURLに接続する。
			//////////////////////////////////////////////////////////////////

			conn = null;
			try {
				
				conn = openConnection( link );
				conn.setRequestProperty( "Host", urlPart + ".blogspot.com" );
				
				html = getHTML( conn );
			} finally {
				// 接続を閉じる。
				closeConnection( conn );
			}

			//////////////////////////////////////////////////////////////////
			// 記事の内容を取得する。
			//////////////////////////////////////////////////////////////////

			// 記事の内容を取得する。
			m2 = p_postContent.matcher( html );

			String content = "";
			if ( m2.find() ) {
				content = m2.group( 1 );
			
				// 内容の前後の空白を取り除く。
				content = content.trim();
			}

			// 投稿日時を取得する。
			m2 = p_published.matcher( html );
			
			String pubDate = "";
			if ( m2.find() ) {
				String published = m2.group( 1 );
				Date temp = sdf_published.parse( published.replace( ":", "" ) );
				pubDate = sdf_yyyymmddhhmm.format( temp );
			}
			
			// 投稿IDを取得する。
			m2 = p_postID.matcher( html );
			
			String postID = "";
			if ( m2.find() ) {
				postID = m2.group( 1 );
			}

			Map<String, String> articleInfo = new HashMap<String, String>();
			articleInfo.put( "title", title );
			articleInfo.put( "link", link );
			articleInfo.put( "pubDate", pubDate );
			articleInfo.put( "content", content );
			articleInfo.put( "postID", postID );
			
			articleList.add( articleInfo );
		}
		
		return articleList;
	}
	
	/**
	 * 記事を投稿する。
	 * @param cookie クッキー
	 * @param postInfo 投稿情報。blogID: ブログID、url: ブログのURL、title: タイトル、postBody: 内容、pubDate: 投稿日時
	 */
	public static void postNewEntry( String cookie, Map<String, String> postInfo ) throws Exception {

		String blogID = postInfo.get( "blogID" );
		String url = postInfo.get( "url" );
		String title = postInfo.get( "title" );
		String postBody = postInfo.get( "postBody" );
		String pubDate = postInfo.get( "pubDate" );
		
		String security_token;
		String securityToken;
		
		//////////////////////////////////////////////////////////////////
		// 投稿日付を編集する。
		//////////////////////////////////////////////////////////////////

		SimpleDateFormat sdf_pubDate = new SimpleDateFormat( "yyyy/MM/dd HH:mm", Locale.US );
		Date date = sdf_pubDate.parse( pubDate );
		
		SimpleDateFormat sdf_postDate = new SimpleDateFormat( "yy/MM/dd" );
		SimpleDateFormat sdf_postTime = new SimpleDateFormat( "HH:mm" );

		String postDate = sdf_postDate.format( date );
		String postTime = sdf_postTime.format( date );

		//////////////////////////////////////////////////////////////////
		// 記事の投稿画面に接続する。
		//////////////////////////////////////////////////////////////////

		String html;
		
		HttpURLConnection conn = null;
		try {
			conn = openConnection( "http://www.blogger.com/post-create.g?blogID=" + blogID, cookie );
	
			// 投稿画面のHTMLを取得する。
			html = getHTML( conn );
			
			Pattern p = Pattern.compile( "<input type=\"hidden\" name=\"security_token\" value=\"(.*?)\">" );
			Matcher m = p.matcher( html );
			if ( ! m.find() ) {
				throw new Exception( "セキュリティトークン(security_token)が見つかりません。" );
			}
			security_token = m.group( 1 );
			
			p = Pattern.compile( "<input name=\"securityToken\" type=\"hidden\" value=\"(.*?)\">" );
			m = p.matcher( html );
			if ( ! m.find() ) {
				throw new Exception( "セキュリティトークン(securityToken)が見つかりません。" );
			}
			securityToken = m.group( 1 );
			
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// 記事を投稿する。
		//////////////////////////////////////////////////////////////////

		try {
			conn = openConnection( "http://www.blogger.com/post-create.do", cookie );
		
			String query = "security_token=" + security_token
				+ "&blogID=" + blogID
				+ "&blogURL=" + URLEncoder.encode( url, "UTF-8" )
				+ "&toggleTime=1"
				+ "&editorModeDefault=1"
				+ "&javascriptEnabled=true"
				+ "&changeLanguage=false"
				+ "&securityToken=" + securityToken
				+ "&postID="
				+ "&title=" + URLEncoder.encode( title, "UTF-8" )
				+ "&postBody=" + URLEncoder.encode( postBody, "UTF-8" )
				+ "&postLabels="
				+ "&commentsMode=ON"
				+ "&postDate=" + URLEncoder.encode( postDate, "UTF-8" )
				+ "&postTime=" + URLEncoder.encode( postTime, "UTF-8" )
				+ "&publish=" + URLEncoder.encode( "投稿を公開", "UTF-8" );
			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();

			html = getHTML( conn );
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}

	}
	
	/**
	 * 記事を削除する。
	 * @param cookie クッキー
	 * @param blogID ブログID
	 * @param postID 投稿ID
	 */
	public static void deleteEntry( String cookie, String blogID, String postID ) throws Exception {

		String security_token;
		String securityToken;
		
		//////////////////////////////////////////////////////////////////
		// 記事の削除画面に接続する。
		//////////////////////////////////////////////////////////////////

		String html;
		
		HttpURLConnection conn = null;
		try {
			conn = openConnection( "http://www.blogger.com/post-delete.g?blogID=" + blogID + "&postID=" + postID, cookie );
	
			// 投稿画面のHTMLを取得する。
			html = getHTML( conn );
			
			Pattern p = Pattern.compile( "<input type=\"hidden\" name=\"security_token\" value=\"(.*?)\">" );
			Matcher m = p.matcher( html );
			if ( ! m.find() ) {
				throw new Exception( "セキュリティトークン(security_token)が見つかりません。" );
			}
			security_token = m.group( 1 );
			
			p = Pattern.compile( "<input name=\"securityToken\" type=\"hidden\" value=\"(.*?)\">" );
			m = p.matcher( html );
			if ( ! m.find() ) {
				throw new Exception( "セキュリティトークン(securityToken)が見つかりません。" );
			}
			securityToken = m.group( 1 );
			
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
		
		//////////////////////////////////////////////////////////////////
		// 記事を削除する。
		//////////////////////////////////////////////////////////////////

		try {
			conn = openConnection( "http://www.blogger.com/post-delete.do", cookie );

			String query = "security_token=" + security_token
				+ "&postID=" + postID
				+ "&blogID=" + blogID
				+ "&securityToken=" + securityToken
				+ "&publish=" + URLEncoder.encode( "削除", "UTF-8" );
			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();

			html = getHTML( conn );
		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}

	}

	/**
	 * HTTP接続を開く。
	 * @param requestURL リクエストURL
	 * @return HTTP接続
	 */
	public static HttpURLConnection openConnection( String requestURL ) throws Exception {
		return openConnection( requestURL, null );
	}
	
	/**
	 * HTTP接続を開く。
	 * @param requestURL リクエストURL
	 * @param cookie クッキー
	 * @return HTTP接続
	 */
	public static HttpURLConnection openConnection( String requestURL, String cookie ) throws Exception {
		URL url = new URL( requestURL );
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setInstanceFollowRedirects( false );
		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" );
		if ( cookie != null ) {
			conn.setRequestProperty( "Cookie", cookie );
		}
		
		return conn;
	}
	
	/**
	 * HTTP接続を閉じる。
	 * @param conn HTTP接続
	 */
	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 {
		
		//////////////////////////////////////////////////////////////////
		// レスポンスヘッダより、GZIPを使用しているか判定する。
		//////////////////////////////////////////////////////////////////

		boolean usingGZIP = false;
		
		List<String> contentEncodings = conn.getHeaderFields().get( "Content-Encoding" );
		if ( contentEncodings != null ) {
			for ( int i = 0; i < contentEncodings.size(); ++i ) {
				String contentEncoding = contentEncodings.get( i );
				if ( contentEncoding.equals( "gzip" ) ) {
					usingGZIP = true;
					break;
				}
			}
		}
			
		//////////////////////////////////////////////////////////////////
		// レスポンスデータを取得する。
		//////////////////////////////////////////////////////////////////

		StringBuffer buf = new StringBuffer();

		BufferedReader in = null;
		try {
			// GZIPを使用しているかどうかにより、レスポンスの入力方法を変える。
			if ( usingGZIP ) {
				// GZIPを使用している:
				in = new BufferedReader(
					new InputStreamReader(
						new GZIPInputStream( conn.getInputStream() )
						, ENCODING ) );
			} else {
				// GZIP を使用していない。
				in = new BufferedReader(
					new InputStreamReader( conn.getInputStream(), ENCODING ) );
			}
				
			int c;
			while ( ( c = in.read() ) != -1 ) {
				buf.append( (char) c );
			}
			
		} finally { 
			if ( in != null ) {
				in.close();
			}
		}
		
		return buf.toString();
	}
	
	/**
	 * 【デバッグ用】レスポンスヘッダを表示する。
	 * @param conn HTTP接続
	 */
	private static void printHeader( HttpURLConnection conn ) {
		Map<String, List<String>> header = conn.getHeaderFields();
		for ( String key : header.keySet() ) {
			List<String> list = header.get( key );
			System.out.println( "[" + key + "]" );
			for ( int i = 0; i < list.size(); ++i ) {
				System.out.println( list.get( i ) );
			}
		}
	}
	
}