【Workplace】Workchatをcsvエクスポートする方法!APIを使わず可能に

はじめに
今回はWorkplace for MetaのWorkchatのチャット情報をcsvファイルとしてエクスポートする方法をご紹介します。

APIを使用せずに実現可能な方法なので、技術的な知識がなくても簡単に実行できます。
通常Workchatのデータをダウンロードするには管理者の権限もしくは許可が必要です。
ですが今回はブックマークレットという方法を利用して自動で画面を操作し、過去のチャット情報を読み取る形でcsvでダウンロードする方法を紹介します。
ブックマークレットとは?
ブックマークレットは、ブラウザのブックマークとして保存できるプログラムです。 「javascript:」で始まる短いスクリプトで、ブックマークをクリックすることで任意の処理を実行できます。
ブックマークレットは便利なツールですが、悪意のあるスクリプトが含まれている可能性もあるため、信頼できるソースからのスクリプトのみを使用してください。

実行前にAIツールなどでスクリプトを確認してもらい、外部への送信や悪意のあるダウンロードを行う処理がないか内容を確認してもらうことを推奨します!
ブックマークレットの導入方法 (Chrome)
Chrome右上のメニュー(⋮) > ブックマーク > ブックマークバーを表示します。
または Ctrl + Shift + B
(Windows/Linux) / Command + Shift + B
(Mac)でも表示が可能です。
ブックマークバーを右クリック > 「ページを追加」を選択します。
名前: 任意の名前(例: Workchat Export)
URL: 下記のJavaScriptコードをコピー&ペースト
保存をクリック
javascript:(async function(){ var statusDiv = document.createElement('div'); statusDiv.style.position = "fixed"; statusDiv.style.bottom = "0"; statusDiv.style.right = "0"; statusDiv.style.zIndex = "9999"; statusDiv.style.background = "rgba(0, 0, 0, 0.7)"; statusDiv.style.color = "white"; statusDiv.style.padding = "10px"; statusDiv.style.fontSize = "12px"; statusDiv.style.maxWidth = "300px"; statusDiv.style.lineHeight = "1.2em"; statusDiv.style.fontFamily = "Arial, sans-serif"; statusDiv.innerHTML = "Starting..."; document.body.appendChild(statusDiv); function updateStatus(msg) { statusDiv.innerHTML = msg; } var main = document.querySelector('[role="main"]'); if(!main){ updateStatus("Main div not found."); return; } var targetDivs = main.querySelectorAll('div'); if(targetDivs.length < 7){ updateStatus("Not enough divs in main."); return; } var scrollContainer = targetDivs[6]; var processed = new Set(); var csvLines = []; var iteration = 0; while(true){ iteration++; updateStatus("Iteration: " + iteration + " - Checking for unprocessed chats..."); var containers = Array.from(document.querySelectorAll('div[data-virtualized="false"]')); var unprocessed = containers.filter(el => !processed.has(el)); if(unprocessed.length > 0){ unprocessed.sort((a, b) => b.getBoundingClientRect().top - a.getBoundingClientRect().top); let chatContainer = unprocessed[0]; processed.add(chatContainer); let chatContent = ""; let contentElem = chatContainer.querySelector('div[dir="auto"].html-div'); if(contentElem){ chatContent = contentElem.textContent; console.log("Chat content:", chatContent); } let chatDatetime = ""; let messagesTables = chatContainer.querySelectorAll('div[data-scope="messages_table"]'); let messagesTable = null; if(messagesTables.length > 1){ messagesTable = messagesTables[1]; } else if(messagesTables.length === 1){ messagesTable = messagesTables[0]; } if(messagesTable){ let children = messagesTable.children; for(let i = 0; i < children.length; i++){ if(children[i].tagName.toUpperCase() !== "DIV") continue; let role = children[i].getAttribute("role"); if(role === "presentation" || role === "none") continue; chatDatetime = children[i].textContent; console.log("Chat datetime:", chatDatetime); break; } } let userText = ""; if(messagesTable){ let userElem = messagesTable.querySelector('div[role="presentation"]'); if(userElem){ userText = userElem.textContent; console.log("User text:", userText); } } let csvLine = '"' + chatContent.replace(/"/g,'""') + '","' + chatDatetime.replace(/"/g,'""') + '","' + userText.replace(/"/g,'""') + '"'; csvLines.push(csvLine); console.log("Processed chat:", csvLine); updateStatus("Processed chats: " + csvLines.length); chatContainer.scrollIntoView(); await new Promise(r => setTimeout(r, 1000)); continue; } else { updateStatus("No unprocessed chats found. Scrolling up..."); let prevScrollTop = scrollContainer.scrollTop; scrollContainer.scrollTop = prevScrollTop - 100; console.log("Scrolled up. New scrollTop:", scrollContainer.scrollTop); await new Promise(r => setTimeout(r, 1000)); if(scrollContainer.scrollTop <= 0 || scrollContainer.scrollTop === prevScrollTop){ updateStatus("Reached top. Waiting for new chats..."); let waited = 0; let newChatFound = false; while(waited < 10){ await new Promise(r => setTimeout(r, 1000)); waited++; containers = Array.from(document.querySelectorAll('div[data-virtualized="false"]')); unprocessed = containers.filter(el => !processed.has(el)); if(unprocessed.length > 0){ newChatFound = true; updateStatus("New chats loaded after waiting " + waited + " seconds."); break; } } if(newChatFound){ continue; } else { updateStatus("No new chats after waiting for 10 seconds. Finishing up..."); break; } } } } let csvContent = csvLines.join("\n"); let bom = "\uFEFF"; let blob = new Blob([bom + csvContent], {type:"text/csv;charset=utf-8"}); let url = URL.createObjectURL(blob); let a = document.createElement("a"); a.href = url; a.download = "chats.csv"; a.click(); updateStatus("CSV file downloaded. Total chats: " + csvLines.length); console.log("CSV file downloaded."); })();
これで設定は完了です。
Workchatをブラウザで開き、ダウンロードを取得したいチャットを開きます。
あとは作成したブックマークをクリックすると、 スクリプトが実行されメッセージの読み込みとエクスポートが開始されます。
ブックマークレットの動作
実行すると、右下にステータスが表示され画面に表示されているチャットを取得します。
実行中:画面の自動スクロール
画面内のすべてのチャットを取得すると、上部までスクロールして過去メッセージを読み込みます。
全メッセージの処理完了後、csvファイルをダウンロードします。
csvにはメッセージ内容、チャット日、ユーザを記録します。