Scrapbox、いろいろな用途につかえて便利だが、Scrapboxには書き込みAPIがない。
実はこれは今後実装予定とかでもなくて、Scrapboxの思想に合わないので、実装されていない ということらしい。
この思想が間違ってるとは思わないが、たまにプログラムからScrapboxへ書き込みしたくなることがある。 ブラウザでリンクにアクセスするとページが作られるという方法 はあるがどうしてもブラウザは必要になる。
puppeteer を使ってブラウザ操作をAPI化する
ブラウザが必要であれば、プログラムからブラウザを操作すればいいじゃないということで puppeteer というソフトウェアが使える。
じつは、すでに過去のScrapboxのイベントで既にやっている方がいる。
ここに書いてある方法で早速試してみたら、たしかに書き込みができた!
書き込みの正確さと速度をさらに上げる
しかし、上記の方法ではページの本文を1文字ずつキーボード入力をエミュレートすることでやっているため、長文になると時間がかかる&たまにカーソル位置がずれるという問題があった。
これをどうにかできないか考えていたら、そういえば、最初から本文を入力した状態で作る方法 があったじゃん!と思い出した。
?body={本文}
とURLにつけることで本文が入力された状態で新しいページを作ることができる。これを使えば、キー入力をエミュレートする必要はなくなる。
というわけで、Scrapbox に新しいページを書き込むだけの関数を作った。
import puppeteer from 'puppeteer'; export const writeToScrapbox = async (sid: string, project: string, pageName: string, text: string) => { const url = new URL(`https://scrapbox.io/${project}/${encodeURIComponent(pageName)}?body=${encodeURIComponent(text)}`); const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'], }); const page = await browser.newPage(); await page.setCookie({ name: 'connect.sid', value: sid, domain: 'scrapbox.io' }); await page.goto(url.toString()); await page.waitFor('#editor'); await new Promise((resolve) => setTimeout(() => resolve(), 1000)); await browser.close(); };
connect.sid
というのはScrapboxのログイン情報で、対象のScrapboxに書き込みできるアカウントの認証情報を入れる。これは次の記事に書かれていた。
これで、単一の関数呼び出しだけでプログラムからScrapboxに書き込めるようになった!
たとえば、次のようなコードを実行すると
import { writeToScrapbox } from 'path/to/scrapbox'; const project = 'xxxxx'; const sid = 'xxxxxxxxxxx...'; const pageName = 'test-title'; const text = 'test-text\n[test]\n[test2]\n[test3]'; await writeToScrapbox(sid, project, pageName, text)
ページが作られた!🎉