📝
Twitterの埋め込みツイート取得API叩いてみる
Twitterのツイート埋め込みHTML取得の仕様について
endpoint
https://publish.twitter.com/oembed?url={url}&partner=&hide_thread=false

公開されていて、特に制限がなさそう(?)
→叩いてみる
% curl "https://publish.twitter.com/oembed?url=https%3A%2F%2Ftwitter.com%2FTwitterJP%2Fstatus%2F1587301348604841987&partner=&hide_thread=false" | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1181  100  1181    0     0   7249      0 --:--:-- --:--:-- --:--:--  7474
{
  "url": "https://twitter.com/TwitterJP/status/1587301348604841987",
  "author_name": "Twitter Japan",
  "author_url": "https://twitter.com/TwitterJP",
  "html": "<blockquote class=\"twitter-tweet\"><p lang=\"ja\" dir=\"ltr\">ジブリさん (<a href=\"https://twitter.com/JP_GHIBLI?ref_src=twsrc%5Etfw\">@JP_GHIBLI</a>) に書き下ろしていただいたヘッダーを、ジブリパークのオープンを記念して、みなさんにも使っていただけることになりました🤩<br><br>常識の範囲内でつかって下さい。 <a href=\"https://t.co/HQ94KU3YAI\">pic.twitter.com/HQ94KU3YAI</a></p>— Twitter Japan (@TwitterJP) <a href=\"https://twitter.com/TwitterJP/status/1587301348604841987?ref_src=twsrc%5Etfw\">November 1, 2022</a></blockquote>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n",
  "width": 550,
  "height": null,
  "type": "rich",
  "cache_age": "3153600000",
  "provider_name": "Twitter",
  "provider_url": "https://twitter.com",
  "version": "1.0"
}
- input(query param)
- url
- TweetのURLをエンコードした値
 
 
 - url
 - output(json)
- author_name
 - author_url
 - html
- これを使ってみる
 
 - cache_age
 - height
 - width
 - provider_name
 - provider_url
 - type
 - url
 - version
 
 
Next.jsのページに組み込んでHTMLを取得して表示までやる
src/pages/test/index.tsx
import { useState } from "react";
import parse from "html-react-parser";
const TestIndex = () => {
  const [url, setUrl] = useState("");
  const [tweetHTML, setTweetHTML] = useState("");
  const handleURLChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setUrl(e.target.value);
  }
  const submit = async (url: string) => {
    const res = await fetch("/api/test", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ url: url }),
    });
    setTweetHTML((await res.json()).response.html);
    // ツイート表示用のスクリプトを追加
    const head = document.getElementsByTagName("head")[0] as HTMLElement;
    const script = document.createElement("script");
    script.src = "https://platform.twitter.com/widgets.js";
    script.async = true;
    script.type = "text/javascript";
    head.appendChild(script);
  }
  return (
    <>
      <h2>Tweet 埋め込みHTML 取得ページ</h2>
      <input type="text" value={url} onChange={handleURLChange} />
      <button onClick={() => submit(url)}>submit</button>
      <div>{parse(tweetHTML)}</div>
    </>
  );
};
export default TestIndex;
src/pages/api/test/index.ts
import fetch from "node-fetch";
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "POST") {
    res.status(405).json({ message: "Method Not Allowed" });
    return;
  }
  if (req.body == null) {
    res.status(405).json({ message: "Bad Request" });
  }
  const tweetURL: string = req.body.url;
  const publishTwitterAPIURL = `https://publish.twitter.com/oembed?url=`;
  const param = `&partner=&hide_thread=false`;
  const endpoint = publishTwitterAPIURL + encodeURIComponent(tweetURL) + param;
  const response = await fetch(endpoint);
  const resData = (await response.json());
  res.status(200).json({ response: resData });
}

注意
レスポンスのHTMLをそのままparse(html)しても正しく描画されない。以下のようにTwitterのスクリプトを非同期に読み込む必要があった
さいごに
特定用途にツイートのURLを大量に保存しておいて、表示させたいときに使えそう(?)
Discussion