AndroidでFacebookみたいにOGP情報を取得する方法です。
スクレイピングにはjsoupを使います。HTML5などにも対応していて便利。
build.gradle
dependencies {
compile 'org.jsoup:jsoup:1.7.3'
}
AndroidManifest.xml
<!-- 追記する -->
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
Ogp.java
/**
* OGP取得クラス
* @author shikato
*
*/
public class Ogp {
private Context _mContext = null;
private Handler _mHandler = null;
private String _mUa = "Mozilla/5.0 (Linux; Android 4.4.2; SOT21 Build/17.1.1.C.1.45) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36";
/**
* Ogpリスナー
* @author shikato
*/
public interface OgpListener {
public static final int NETWORK_ERROR = -1;
public static final int UNSUPPORTED_MIME_TYPE_ERROR = -2;
public static final int UNKNOWN_HOST_ERROR = -3;
public static final int TIMEOUT_ERROR = -4;
public static final int UNKNOWN_ERROR = -5;
public void onSuccess( final OgpData aOgpData );
public void onError( final int aErrorCode );
public void onHttpError( final int aHttpStatusCode );
}
public Ogp( final Context aContext ) {
_mContext = aContext.getApplicationContext();
_mHandler = new Handler();
}
public Ogp( final Context aContext, final String aUa ) {
_mContext = aContext.getApplicationContext();
_mHandler = new Handler();
_mUa = aUa;
}
public void getOgp( final String aUrl, final OgpListener aListener ) {
// ネットワークに接続しているかどうか
if ( !_isConnectedNetwork( _mContext ) ) {
aListener.onError( OgpListener.NETWORK_ERROR );
return;
}
( new Thread( new Runnable() {
@Override
public void run() {
try {
final Connection.Response response =
Jsoup.connect( aUrl ).userAgent( _mUa ).timeout( 5000 ).execute();
final int statusCode = response.statusCode();
if ( statusCode != 200 ) {
_mHandler.post( new Runnable() {
@Override
public void run() {
aListener.onHttpError( statusCode );
}
} );
return;
}
final Document document = response.parse();
final OgpData ogpData = new OgpData();
ogpData.setUrl( aUrl );
ogpData.setTitle( _getTitle( document ) );
ogpData.setDescription( _getDescription( document ) );
ogpData.setImage( _getImage( document, aUrl ) );
_mHandler.post( new Runnable() {
@Override
public void run() {
aListener.onSuccess( ogpData );
}
} );
} catch ( UnsupportedMimeTypeException e ) {
e.printStackTrace();
_postError( OgpListener.UNSUPPORTED_MIME_TYPE_ERROR, aListener );
} catch ( UnknownHostException e ) {
e.printStackTrace();
_postError( OgpListener.UNKNOWN_HOST_ERROR, aListener );
} catch ( SocketTimeoutException e ) {
e.printStackTrace();
_postError( OgpListener.TIMEOUT_ERROR, aListener );
} catch ( Exception e ) {
e.printStackTrace();
_postError( OgpListener.UNKNOWN_ERROR, aListener );
}
}
} ) ).start();
}
private String _getTitle( final Document aDocument ) {
// OGPタイトル取得
final Elements elements = aDocument.getElementsByAttributeValue( "property", "og:title" );
if ( elements.hasAttr( "content" ) ) {
return elements.attr( "content" );
}
// OGPセットされてない場合はtitleタグの内容を返す
final String title = aDocument.title();
if ( title == null ) {
return "";
}
return title;
}
private String _getDescription( final Document aDocument ) {
// OGP description取得
Elements elements = aDocument.getElementsByAttributeValue( "property", "og:description" );
if ( elements.hasAttr( "content" ) ) {
return elements.attr( "content" );
}
// OGPセットされてない場合はdescriptionタグの内容を返す
elements = aDocument.getElementsByAttributeValue( "property", "description" );
if ( elements.hasAttr( "content" ) ) {
return elements.attr( "content" );
}
return "";
}
private String _getImage( final Document aDocument, final String aUrl ) {
// OGP image取得
Elements elements = aDocument.getElementsByAttributeValue( "property", "og:image" );
if ( elements.hasAttr( "content" ) ) {
String imgPath = elements.attr( "content" );
// http or httpsで始まるフルパスを取得する
imgPath = _getFullPath( imgPath, aUrl );
if ( imgPath != null ) {
return imgPath;
}
}
// OGPない場合はitemprop属性を見る
elements = aDocument.getElementsByAttributeValue( "itemprop", "image" );
for ( Element element : elements ) {
String imgPath = element.attr( "content" );
imgPath = _getFullPath( imgPath, aUrl );
if ( imgPath == null ) {
continue;
}
return imgPath;
}
// itemprop属性も無い場合はimgタグを見る
// リクエスト増えるけどサイズやMIMEタイプ見たりしても良いかも
elements = aDocument.getElementsByTag( "img" );
for ( Element element : elements ) {
String imgPath = element.attr( "src" );
imgPath = _getFullPath( imgPath, aUrl );
if ( imgPath == null ) {
continue;
}
return imgPath;
}
return "";
}
private String _getFullPath( final String aImagePathStr, final String aOgpUrlStr ) {
if ( aImagePathStr.indexOf( "http://" ) == 0 || aImagePathStr.indexOf( "https://" ) == 0 ) {
return aImagePathStr;
}
try {
final URI ogpUri = new URI( aOgpUrlStr );
final URI imgUri = ogpUri.resolve( aImagePathStr );
return imgUri.toString();
} catch ( URISyntaxException e ) {
return null;
}
}
private void _postError( final int aErrorCode, final OgpListener aListener ) {
_mHandler.post( new Runnable() {
@Override
public void run() {
aListener.onError( aErrorCode );
}
} );
}
private static boolean _isConnectedNetwork( final Context aContext ) {
final ConnectivityManager connectivityManager =
(ConnectivityManager)aContext.getSystemService( Context.CONNECTIVITY_SERVICE );
final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if ( networkInfo != null && networkInfo.isConnected() ) {
return true;
}
return false;
}
}
OgpData.java
/**
* OGPデータクラス
* @author shikato
*
*/
public class OgpData {
private String _mUrl;
private String _mTitle;
private String _mDescription;
private String _mImage;
public String getUrl() {
return _mUrl;
}
public void setUrl( final String aUrl ) {
_mUrl = aUrl;
}
public String getTitle() {
return _mTitle;
}
public void setTitle( final String aTitle ) {
_mTitle = aTitle;
}
public String getDescription() {
return _mDescription;
}
public void setDescription( final String aDescription ) {
_mDescription = aDescription;
}
public String getImage() {
return _mImage;
}
public void setImage( final String aImage ) {
_mImage = aImage;
}
}
ex.
public class SampleActivity extends Activity {
@Override
protected void onCreate( final Bundle aSavedInstanceState ) {
super.onCreate( aSavedInstanceState );
setContentView( R.layout.activity_my );
final Ogp ogp = new Ogp( getApplicationContext() );
ogp.getOgp( "http://sample.com", new Ogp.OgpListener() {
@Override
public void onSuccess( final OgpData aOgpData ) {
// 成功時の処理
// 良い感じにOGPを表示する
}
@Override
public void onError( final int aErrorCode ) {
// エラー時の処理
}
@Override
public void onHttpError( final int aHttpStatusCode ) {
// HTTPエラー時の処理
}
} );
}
}
画像の表示にはメモリやディスクキャッシュを細かく設定できる、Universal Image Loader for Androidが便利。