これでコピペを楽にしつつファイル出力も楽にできる。grep検索もできた。
ブツ
前回と同じリポジトリで編集した。
ひとつの記事あたりひとつのファイルとして出力する。
- monaledge/backup/
- list.tsv(記事IDとタイトル)
- 記事ID.md(記事の数だけ作成する)
前回まで
- モナレッジから自分の記事のマークダウンをすべて取得したい
- ラズパイ4にseleniumとchromedriver-binaryをインストールする
- seleniumで手動ログイン後に自動処理を行おうと試みるも失敗
- モナレッジにログインできなかった件
- Calcで記事をバックアップする
モナレッジに投稿した自分の記事をすべて一括でローカルにファイル保存したかった。が、その前にモナレッジのバックエンドAPIサーバが落ちた。この作業が原因かもしれないため一旦自動化を断念して手動でのバックアップに切り替えることにした。
Calcにコピペすることでコピペ作業を少しだけ軽減できるようにした。
記事ID、カテゴリ、タイトルを取得する
mypageにアクセスし、デベロッパツールで以下のように記事データを取得できることを確認する。
const links = Array.from(document.querySelectorAll(`a[href^='/article/']`))
const ids = links.map(e=>parseInt(e.getAttribute('href').replace(/.*[\/\\]/, '')))
const dateViewCates = links.map(e=>e.querySelector('div.v-card__subtitle').textContent.trim().split('\n').map(s=>s.trim()))
for (let i=0; i<dateViewCates.length; i++) {dateViewCates[i][1]=parseInt(dateViewCates[i][1])}
const titles = links.map(e=>e.querySelector('div.v-card__title').textContent.trim())
const monas = links.map(e=>e.querySelector('span.subheading').textContent)
//const categories = links.map(e=>e.querySelector('span.v-chip__content').textContent.trim())
console.debug(links, ids, dateViewCates, titles, categories, monas)
console.debug(ids.map((id,i)=>`${id}\t${titles[i]}`).join('\n'))
これをTSV形式にしてクリップボードにコピーする。
// モナレッジのmypageから記事ID、カテゴリ、タイトルをTAB区切でクリップボード出力するブックマークレット
javascript:(async()=>{const links = Array.from(document.querySelectorAll(`a[href^='/article/']`));const ids = links.map(e=>parseInt(e.getAttribute('href').replace(/.*[\/\\]/, '')));const categories = links.map(e=>e.querySelector('span.v-chip__content').textContent.trim());const titles = links.map(e=>e.querySelector('div.v-card__title').textContent.trim());await navigator.clipboard.writeText(ids.map((id,i)=>`${id}\t${categories[i]}\t${titles[i]}`).join('\n')).catch(e=>console.error(e))})();
これをaタグにしてHTML表示する。
<a href="javascript:(async()=>{const links = Array.from(document.querySelectorAll(`a[href^='/article/']`));const ids = links.map(e=>parseInt(e.getAttribute('href').replace(/.*[\/\\]/, '')));const categories = links.map(e=>e.querySelector('span.v-chip__content').textContent.trim());const titles = links.map(e=>e.querySelector('div.v-card__title').textContent.trim());await navigator.clipboard.writeText(ids.map((id,i)=>`${id}\t${categories[i]}\t${titles[i]}`).join('\n')).catch(e=>console.error(e))})();">モナレッジのmypageから記事ID、カテゴリ、タイトルをTAB区切でクリップボード出力するブックマークレット</a>
以下をブラウザでブックマークして、mypageで実行し、Calcファイルのシートmonaledge-articles.odsにペーストする。これを1ページずつ全ページ行う。
モナレッジのmypageから記事ID、カテゴリ、タイトルをTAB区切でクリップボード出力するブックマークレット
あとはURL作成セルをクリックして記事編集画面を開き、そこからマークダウンをコピーし、シートのセルにペーストする。
こうして記事IDとマークダウンを貼り付けたら、次はこれを一記事ごとにファイル出力する。今回はマクロで行った。
マクロ作成
- monaledge-articles.odsファイルをCalcで開く
- メニュー→ツール→マクロ→マクロの編集をクリック
- 編集ウインドウ左のオブジェクトカタログからマイマクロ→Standard→Module1を選ぶ
- テキストエディタにコードを入力する
- 実行する(F5キーまたは)
構文や関数などはググって探した。ExcelのVBと混在しててググラビリティが低い。とりあえず最初のシートのセルA1
から値を取得するときは以下コマンド。
ThisComponent.Sheets(0).getCellByPosition(0,0).String
- UI
Msgbox
- 文字列操作
Trim
- ファイル操作
Open
FreeFile
Print
Close
全コード
' 記事IDとタイトルのTSVファイルを出力したい
Option VBASupport 1
Sub Export()
Dim row as integer
Dim col as integer
row = 1
text = ""
Do
id = ThisComponent.Sheets(0).getCellByPosition(0,row).String
title = ThisComponent.Sheets(0).getCellByPosition(2,row).String
If 0 < Len(id) Then
text = text & id & Chr(9) & title & Chr(10)
md = ThisComponent.Sheets(0).getCellByPosition(3,row).String
WriteArticles id, title, md
Else
Exit Do
End If
row = row + 1
Loop While 0 < Len(id)
WriteList(Trim(text))
Msgbox("処理完了")
End Sub
Sub WriteList(strData as String)
Dim strFileName As String
Dim intFileNo As Integer
strFileName = DirPath & "/list.tsv"
intFileNo = FreeFile()
Open strFileName For Output As #intFileNo
Print #intFileNo, strData
Close #intFileNo
End Sub
Sub WriteArticles(id as String, title as String, md as String)
Dim strFileName As String
Dim intFileNo As Integer
strFileName = DirPath & "/" & id & ".md"
intFileNo = FreeFile()
Open strFileName For Output As #intFileNo
Print #intFileNo, title & Chr(10) & Chr(10) & md
Close #intFileNo
End Sub
Function DirPath() as String
strDirPath = ThisComponent.Sheets(0).getCellByPosition(8,0).String
If 0 < Len(Trim(strDirPath)) < 1 Then
strDirPath = "/tmp/work/monaledge/backup"
End If
DirPath = strDirPath
End Function
Option VBASupport 1
はいらないかもしれない。
気になったことは以下。
- 戻り値があるときは
Sub
でなくFunction
を使う - 文字列結合子は
+
でなく&
を使う End
,Exit
, return系が煩わしい[End] [Sub|Function|If]
[Exit] [Do]
- returnは
関数名=値
で示す - ほかにも多数ありそう
- 変数の宣言と代入は同時にできない
- 変数の宣言はしなくてもいい?
- デバッグ出力がモーダルダイアログでしかできない……
マクロ実行ボタン作成
ボタンを押したらマクロを実行するようにした。
- Calcのメニュー→表示→ツールバー→フォームコントロールをチェックする
- フォームコントロールボックスからデザインモードボタンを押してONにする
- ボタンボタンを押す
- シートの適当な箇所をドラッグ&ドロップしてボタンを作成する
- 4のボタンを右クリックしてコントロールを選ぶ
- イベントタブにある実行前に作成した
Sub Export
をセットする - フォームコントロールボックスからデザインモードボタンを押してOFFにする
- 4のボタンをクリックするとマクロが実行され処理完了ダイアログが表示される
マクロ実行
ボタンを押してマクロを実行するとシートの状態に応じてファイル出力される。
TUIファイラrangerでファイル閲覧したところ↓
ファイルがたくさん作られている。中身があるのは手動でコピペした3件だけ。
grep検索
複数のファイルをまたいでキーワードselenium
で検索するときは以下。
cd /tmp/work/monaledge/backup
find . -name "*.md" | xargs grep "selenium" --color=auto
これこれ。まさにこれがやりたかった!
あとは自分の記事をすべてコピペすれば完成!