Edited at

AndroidでFacebookみたいにOGP情報を取得する

More than 5 years have passed since last update.

AndroidでFacebookみたいにOGP情報を取得する方法です。

こんなやつです。

facebookogp.png

スクレイピングにはjsoupを使います。HTML5などにも対応していて便利。

jsoup


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エラー時の処理
}
} );
}
}


Gist

画像の表示にはメモリやディスクキャッシュを細かく設定できる、Universal Image Loader for Androidが便利。