Flutterラボ リリース3周年記念! プロコースが1ヶ月の料金で2ヶ月間受けられる、実質半額セール (2024年3月17日まで・先着)

Flutterラボの

プレミアム会員になる

【Flutter】URLからWEBサイトのタイトル(title)、説明(description)、サムネイル等を取得する(HTML)

2021.11.22

Twitterのように、URLからWEBサイトの情報を取り出して表示する方法を紹介します。

まずは、必要なパッケージをインストールします。

  • html

    • 文字列をHTMLタグとして認識されるために使用

  • http

    • URLから情報を取得するために使用

  • url_launcher

    • 最後にそのリンクにアクセスするために使用

例として、https://flutterlabo.tech/ にアクセスして、タイトル、説明、サムネイルを取得して表示します。

const String url = 'https://flutterlabo.tech/';
Widget title;
Widget? image;
Widget? description;

// URLにアクセスして情報をすべて取得
Response response = await get(Uri.parse(url));

// HTMLパッケージでHTMLタグとして認識
var document = parse(response.body);

// ヘッダー内のtitleタグの中身を取得
title = Text(document.head!.getElementsByTagName('title')[0].innerHtml, overflow: TextOverflow.ellipsis, maxLines: 1, style: const TextStyle(fontSize: 13),);

// ヘッダー内のmetaタグをすべて取得
var metas = document.head!.getElementsByTagName('meta');
for(var meta in metas) {
  // metaタグの中からname属性がdescriptionであるものを探す
  if(meta.attributes['name'] == 'description') {
    description = Text(meta.attributes['content'] ?? '', overflow: TextOverflow.ellipsis, maxLines: 3, style: const TextStyle(fontSize: 12),);
    
  // metaタグの中からproperty属性がog:imageであるものを探す
  } else if(meta.attributes['property'] == 'og:image') {
    image = ClipRRect(
      borderRadius: const BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
      child: Image.network(
        meta.attributes['content']!,
        width: 120,
        height: 120,
        fit: BoxFit.cover,
        alignment: Alignment.center,
      ),
    );
  }
}

return ([image, title, description].every((element) => element != null)) ? InkWell(
  onTap: () async  {
    if(await canLaunch(url)) launch(url);
  },
  child: Container(
    height: 120,
    decoration: BoxDecoration(
        border: Border.all(width: 0.5, color: Colors.grey),
        borderRadius: const BorderRadius.all(Radius.circular(10))
    ),
    child: Row(
      children: [
        image!,
        Expanded(
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 8),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                title, description!
              ],
            ),
          ),
        )
      ],
    ),
  ),
) : const SizedBox();