🦉

【JavaScript】MutationObserverを使用してDOMの変更を監視する

2022/10/09に公開

はじめに

この記事ではMutationObserverを使用してYouTubeLiveのコメントを取得する方法を紹介します。

MutationObserverとは?

MutationObserverはDOMの変更を監視することができます。DOMに変更が加えられると、コンストラクタに渡したコールバック関数が呼び出されます。
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver

YouTubeLiveのコメントを取得してみよう!

MutationObserverを使用してYouTubeLiveのチャット欄を監視し、コメントを取得してみましょう。

チュートリアル

Chromeで好きなYouTubeLiveのページを開き、DevelopperToolを開きます。

【鬼畜ゲー】しょぼんのるきみん!やってみます!!!!!!!!!!!!ぺこ!【ホロライブ/兎田ぺこら】

コンソールに以下のJavaScriptコードを貼り付けます。

// 監視対象の要素
const element = (
    document
    .querySelector("iframe#chatframe")
    .contentDocument
    .querySelector("#chat")
    .querySelector("#items")
);

// 追加された子要素を取得するためのオプション
const options = {
    childList: true,
};

// 要素からメッセージだけを抽出する
const parseMessage = (node) => {
    const container = node.querySelector('#message')
    const children = [...container.childNodes];
    return children.reduce((message, e) => {
        if (e.nodeName === 'IMG') {
            message += e.getAttribute('shared-tooltip-text') ?? '';
        } else if (e.nodeName === '#text') {
            message += e.textContent ?? '';
        }
        return message;
    }, '');
};

// 子要素が追加されるたびに実行される
const callback = (mutationsList, _) => {
    for(const mutation of mutationsList) {
        mutation.addedNodes.forEach(node => {
            const message = parseMessage(node);
            console.log(message);
        });
    }
};

const obs = new MutationObserver(callback);
obs.observe(element, options);

実行するとコメントが表示されます!

コメントが表示される様子

簡単な解説

監視対象の要素を取得します。今回はYouTubeLiveのチャットを囲んでいる要素を指定しています。

const element = (
    document
    .querySelector("iframe#chatframe")
    .contentDocument
    .querySelector("#chat")
    .querySelector("#items")
);

MutationObserver.observe()に渡すオプションを定義しています。オプションの一覧はこちらで確認することができます。今回は小要素の追加を検知したいのでchildListをtrueに設定しています。

const options = {
    childList: true,
};

チャットの要素からメッセージだけを取得する関数です。メッセージには画像とテキストが混ざっています。なので、画像の場合はidを表示し、テキストの場合はそのテキストを表示するようにしています。

const parseMessage = (node) => {
    const container = node.querySelector('#message')
    const children = [...container.childNodes];
    return children.reduce((message, e) => {
        if (e.nodeName === 'IMG') {
            message += e.getAttribute('shared-tooltip-text') ?? '';
        } else if (e.nodeName === '#text') {
            message += e.textContent ?? '';
        }
        return message;
    }, '');
};

MutationObserverに渡すcallback関数を定義しています。オプションでchildListをtrueに設定したので、子要素が追加された時と削除されたときに実行されます。MutationRecordの配列が第一引数に渡されるので、MutationRecord.addedNodesで追加された要素だけを取得しています。

const callback = (mutationsList, _) => {
    for(const mutation of mutationsList) {
        mutation.addedNodes.forEach(node => {
            const message = parseMessage(node);
            console.log(message);
        });
    }
};

MutationObserverのコンストラクタにcallback関数を渡し、インスタンス化しています。observe関数を実行することで監視が開始されます。

const obs = new MutationObserver(callback);
obs.observe(element, options);

おわりに

この記事では、MutationObserverを使用してDOMの変更を監視する方法を、YouTubeLiveのコメントを取得する例を通して解説しました。今回使用したコードを基にYouTubeLiveのコメントを取得するツールを公開しています。

https://github.com/fksk36/ylcs

最後まで読んでいただきましてありがとうございました。

Discussion