twitter からサイトプレビュー用 Open Graph protocol の情報を取得した


3行まとめ

  • サイトプレビューに必要な meta 情報は meta property="og:〜" などの情報。Open Graph protocol なので OGP 情報と表記することがある。
  • 2020/6/2 ごろから twitter の URL に curl したときの結果が変わって、サイトプレビューに必要な meta 情報が含まれなくなった。
  • User-Agentbot 系のキーワードを設定したらサイトプレビューに必要な meta 情報が含まれた。

これはなに?

Slack や LINE などのチャットにはメッセージに含まれている URL を検出してプレビューしてくれる機能があります。
チャット上で内容が確認できるのでとても便利です。

同じようなサイトプレビュー機能を Chatwork で自前で実装していて便利に使っています。
チャットワークで URL のプレビューを実現する。: https://github.com/junjanjon/chatwork-ogp-webhook

2020/6/2 ごろから twitter のサイトでサイトプレビュー用 Open Graph protocol の情報取得がうまくできないということが起こりました。twitter のサイトの変更によるものでした。

解決したので記事にしました。

サイトプレビュー用 Open Graph protocol の情報取得とは

対象の URL にアクセスし、主に「タイトル」、「説明」、「プレビュー画像URL」の情報などを抜き出すことです。
主に SNS で URL を貼るとプレビューされる仕組みです。これらは Open Graph protocol に沿っているので OGP 情報と表記することがあります。

それぞれの情報は html の中で以下のように meta タグに設定されています。

<meta property="og:title" content="タイトル">
<meta property="og:description" content="ページの簡単な説明">
<meta property="og:image" content="サムネイル画像のURL>

問題発生時のサイトプレビュー実装

問題発生時、URLへのアクセスに特別な設定をしていなかったです。
アクセスは curl にすると以下のようなイメージです。

curl 'https://twitter.com/hatakenjiro/status/1267448662839357441'

このとき html に含まれていた meta タグは以下でした。
og:〜 の情報は含まれていないです。

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover" />
<meta property="fb:app_id" content="2231777543" />
<meta property="og:site_name" content="Twitter" />
<meta name="google-site-verification" content="V0yIS0Ec_o3Ii9KThrCoMCkwTYMMJ_JYx_RSaGhFYvw" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Twitter" />
<meta name="apple-mobile-web-app-status-bar-style" content="white" />
<meta name="theme-color" content="#ffffff" />
<meta http-equiv="origin-trial" content="Ap6SMBNB0lQoXpXl4I9vyTJqJ7Y0X9tPd6Q6rN697iHdubQQxBcWHy21N3N7uEz7Ba5UKMbN+eLvDczBSbi27AsAAABfeyJvcmlnaW4iOiJodHRwczovL3R3aXR0ZXIuY29tOjQ0MyIsImZlYXR1cmUiOiJCYWRnaW5nIiwiZXhwaXJ5IjoxNTY0NTgyNzY2LCJpc1N1YmRvbWFpbiI6dHJ1ZX0=" />
<meta http-equiv="origin-trial" content="Apir4chqTX+4eFxKD+ErQlKRB/VtZ/dvnLfd9Y9Nenl5r1xJcf81alryTHYQiuUlz9Q49MqGXqyaiSmqWzHUqQwAAABneyJvcmlnaW4iOiJodHRwczovL3R3aXR0ZXIuY29tOjQ0MyIsImZlYXR1cmUiOiJDb250YWN0c01hbmFnZXIiLCJleHBpcnkiOjE1NzUwMzUyODMsImlzU3ViZG9tYWluIjp0cnVlfQ==" />
<meta http-equiv="origin-trial" content="AleGS26SZL7UA8Fe1DbvXzoay74bPTvrfKKGimIu1RI8vA+RtXOSVlizUkz2zU/fQoFoOTgCiCciP6pM5teaeQgAAABjeyJvcmlnaW4iOiJodHRwczovL3R3aXR0ZXIuY29tOjQ0MyIsImZlYXR1cmUiOiJTbXNSZWNlaXZlciIsImV4cGlyeSI6MTU3OTAyMDkyMSwiaXNTdWJkb21haW4iOnRydWV9" />

解決時のサイトプレビュー実装(User-Agent の追加)

URLへのアクセスに User-Agentbot と設定して解決しました。
アクセスは curl にすると以下のようなイメージです。

curl 'https://twitter.com/hatakenjiro/status/1267448662839357441' -H 'User-Agent: bot'

このとき html に含まれていた meta タグは以下でした。
og:〜 の情報は含まれています。多かったのでog:〜 の部分のみです。

<meta  property="og:type" content="article">
<meta  property="og:url" content="https://twitter.com/hatakenjiro/status/1267448662839357441">
<meta  property="og:title" content="畑健二郎@トニカクカワイイ on Twitter">
<meta  property="og:image" content="https://pbs.twimg.com/media/EZbhpuaUYAA_Sk1.jpg:large">
<meta  property="og:image:user_generated" content="true">
<meta  property="og:description" content="“気の緩み…&#10;&#10;「100日後に結婚する二人」&#10;74日目&#10;&#10;  #100日後に結婚する二人 &#10;&#10;『トニカクカワイイ』《第11巻》絶賛発売中!&#10;&#10;そして、こちらも毎日更新!→『オルムズト・ナジャの小部屋』&#10;https://t.co/bSnLcy7l7R&#10;&#10; #トニカクカワイイ”">
<meta  property="og:site_name" content="Twitter">

追記: 2021-01-31

きっとブラウザからのアクセスの場合 Open Graph 情報は必須ではないから最初のリクエストの通信量を減らす目的で削っているんだと感じました。

User-Agent: bot と設定しようと考えたきっかけは、ほかのサービス(Slack や Facebook など)では Open Graph 情報が取得できているからでした。
それぞれ内部でクローラーを回しているようなので、通信をクローラーによせればいいのではと思い一般的なクローラーを示す User-Agent: bot を設定しました。

Facebook のシェアデバッガーの紹介

Facebook のシェアデバッガーという開発者向けツールは URL を入力すると ウェブサイトがFacebookのスクレイパーでどのように表示されるかをテストしてくれます。Open Graph 情報を見やすく表示してくれます。ドキュメントも豊富で使いやすいです。

ここでは Facebook クローラーの User-Agentfacebookexternalhit と書かれています。
シェアデバッガーだと twitter の Open Graph 情報は取れているので User-Agent: facebookexternalhit でもうまくいくと考えられます。

$ curl 'https://twitter.com/hatakenjiro/status/1267448662839357441' -H 'User-Agent: facebookexternalhit' -s | grep "og:"
    <meta  property="og:type" content="article">
    <meta  property="og:url" content="https://twitter.com/hatakenjiro/status/1267448662839357441">
    <meta  property="og:title" content="畑健二郎@トニカクカワイイ on Twitter">
    <meta  property="og:image" content="https://pbs.twimg.com/media/EZbhpuaUYAA_Sk1.jpg:large">
    <meta  property="og:image:user_generated" content="true">
    <meta  property="og:description" content="“気の緩み…&#10;&#10;「100日後に結婚する二人」&#10;74日目&#10;&#10;  #100日後に結婚する二人 &#10;&#10;『トニカクカワイイ』《第11巻》絶賛発売中!&#10;&#10;そして、こちらも毎日更新!→『オルムズト・ナジャの小部屋』&#10;https://t.co/bSnLcy7l7R&#10;&#10; #トニカクカワイイ”">
    <meta  property="og:site_name" content="Twitter">

うまくいきました。

参考

Open Graph protocol: https://ogp.me/
User-Agent に関してなにか書いていないかなと思ったけど書いていなさそう。