Twitterの画像をScrapboxに引用するスクリプトを作る
(のりしろ)
自分で作ることにした
できたもの
どうやって対応したの?……ってtwitterのwebページからscrapingしたのかtakker.icon
Scrapboxから実行することにこだわらないほうが簡単で便利かも?わからん。
使い方がよくわからなかったwogikaze.icon
同意tkgshn.icon
https://scrapbox.io/api/code/takker/GM_fetch/scrapbox.user.jsをTamperMonkeyにいれて https://scrapbox.io/api/code/motoso/Tweet%E3%82%92%E5%8F%96%E3%82%8A%E8%BE%BC%E3%82%80Popup_menu_v2/script.jsをUserScriptに追加すればいいのか?
そうです基素.icon
---
できるまでのログ
Twitterの画像をScrapboxに引用するスクリプトを作る
ブラウザアクセスをするとdocument.querySelector("#id__a06mgrsipeq > div > div > div > div > div > a > div > div.r-1p0dtai.r-1pi2tsx.r-1d2f490.r-u8s1d.r-ipm5af.r-13qz1uu > div > img") にある
ただし#id__a06mgrsipeqはアクセスごとに毎回変わる
Denoだとこんな感じでHTMLから復元できるなぁ
code:ts
const ACCOUNT_NAME = "motoso";
const ID = '1637434235534589952';
async function getLatestTweet() {
const browser = await puppeteer.launch();
// TwitterのプロフィールページのURLを構築する
const url = https://twitter.com/${ACCOUNT_NAME}/status/${ID};
const page = await browser.newPage();
// UAを設定しないとサポートされていないブラウザ扱いになる
page.setUserAgent(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
)
await page.goto(url);
// ツイート表示まで待つ。要素表示まで待つに変更したい
await new Promise(r => setTimeout(r, 2000));
const html = await page.content();
await browser.close();
// Cheerioを使用して、HTMLからツイートのテキストを抽出する
const $ = load(html);
const lines :string[] = [];
const tweetTextElement = $('#react-root > div > div > div.css-1dbjc4n.r-18u37iz.r-13qz1uu.r-417010 > main > div > div > div > div > div > section > div > div > div:nth-child(1) > div > div > article > div > div > div:nth-child(3) > div:nth-child(2)')
const tweetText = tweetTextElement.text()
lines.push(tweetText)
// 最初のidが毎回変わるみたい
const imageElement = $('id^="id__" > div > div > div > div > div > a > div > div.r-1p0dtai.r-1pi2tsx.r-1d2f490.r-u8s1d.r-ipm5af.r-13qz1uu > div > img') const imageURl = imageElement0.attribs.src // TODO: 画像をGyazoに送りつける
lines.push(imageURl)
return(lines.join('\n'))
}
console.log(await getLatestTweet());
こういうのをUserScriptから呼び出せるかな?
流石に重そう
API serverを立てて呼び出せば作れるtakker.icon
いい方法はあるだろうか
deno、プロジェクトを作るのを考えずにコードを書いたらすぐ動くのいいな〜
方法は2つtakker.icon
基素.iconさんの試したやつ
twitter.comの内部APIを借りて取得する
現状見る限りTwitterのAPIまわりはめちゃくちゃになっていそうなので、真面目に守る必要性をあんまり感じない
ここまでTwitterの公式APIが壊れてるなら、なりふり構ってられない
こんな感じかな基素.icon
そんな感じですtakker.icon
もう作っているひといたのか
自分だけrobots.txt守っているのもばからしいな(モラルハザード)
もっといろんなAPIを叩いていた覚えがあるのだが……
まあ試せばわかるか
code:js
window.getTweet = async (id, lang = "en") => {
const params = new URLSearchParams([
// 不要だった
]);
const res = await GM_fetch(https://cdn.syndication.twimg.com/tweet-result?${params}, {
headers: {
"content-type": "application/json; charset=utf-8",
},
});
return await res.json();
};
い け ま し たtakker.icon
https://gyazo.com/ebe0f523bba9771d49acd06016b334ff
展開先URLも含まれている
text: tweet本文
photos: 展開先画像URL
entities.urls: 展開先外部リンク
倫理面もクリア!!!
試した。やりかた基素.icon
$ await window.getTweet('1637434235534589952')
こんな感じで置換したら良さそう基素.icon
code:js
const lines = [];
const text = tweet.text
// URLの置換
let replacedText = '';
tweet.entities.urls.forEach(i => {
replacedText = text.replace(i.url, i.expanded_url)
})
lines.push(replacedText)
// TODO: Gyazoにアップロードする
lines.push(tweet.photos.map(u => u.url).join('\n'))
lines.join('\n')
とりあえず動くものはできた基素.icon
TODO
TwitterのURLの場合だけこっちが読み出されるようにしたい
Gyazoアップロード機能
連ツイはどうすれば取得できる?
これはAPIでも取れなかったのでKarel Capekではin_reply_toからやや複雑なSQLで自前で構築してます基素.icon 当時、内部向けにしかないのかーと思った
2.0なら取れるかも?
oEmbed APIを使うのが良さそうinajob.icon
認証不要、RateLimitなし
APIなのでrobot.txtで不許可にもしていない
画像ではなくHTMLが取れる
画像URLがとれないんですよね基素.icon
あ、そうか、これを使うときはwidgets.jsが取ってきて埋めてるのかな?inajob.icon
widgets.jsがiframeを作っていた、残念