Chrome 拡張機能を作ろう前提知識&ウォーミングアップ編

p5.js での演習を通して身に付けたプログラミング言語 JavaScript を利用して、ウェブブラウザの1つである Google Chrome の拡張機能を作ってみましょう。 JavaScript がさらに身に付き、将来、ウェブアプリを作るときに役立つ様々な知識も身に付くはずです。

目次

  1. ウェブブラウザって何?拡張機能って何?
  2. HTML と CSS
  3. 手動でウェブページを書き換えてみよう
  4. Console にプログラムを入力してウェブページを書き換えてみよう

準備

ウェブブラウザとして Edge か Chrome が必要です。 Windows であれば最初からインストールされている Edge を使うことができます。 それ以外の方は Chrome をインストールしてください。 補足:Edge と Chrome は中身はほとんど同じで高い互換性があります。

ウェブブラウザって何?拡張機能って何?

ウェブページ (ホームページ) は、インターネット上のコンピューターから HTML 文書を受信し、その記述に基づいてウェブブラウザと呼ばれる種類のアプリが表示を行うという仕組みになっています。 ウェブブラウザには Edge, Safari, Chrome, Firefox など多くの種類があります。

受信した HTML 文書を表示する処理に介入して、自分好みにカスタマイズできるプログラムのことを 拡張機能 と呼びます。

Chrome 拡張機能でなにがうれしいの?

うれしいこと1:ブラウザが便利になってうれしい

多くのブラウザで拡張機能を開発・利用できる仕組みが備わっていて、 たとえば Chrome では Chrome ウェブストア で配布されているものを簡単にインストールすることができます。 たとえば私はウェブページ全体のスクリーンショットを撮る拡張機能などを使っています。まずはお好みの拡張機能を探してみてはいかがでしょうか。

うれしいこと2:特定のウェブページを改造できてうれしい

ある特定のウェブページを見るとき専用の拡張機能を作ることもできます。 たとえば神戸大学の教務情報システム「うりぼーネット」を改造する拡張機能 Uribo-Net extension を私は作りました。 (インストールすると15分で自動ログアウトさせられる機能が無効になります。使用は自己責任でお願いします。) そのプログラムを公開 しておいたら学生がまた別のうりぼーネット拡張機能を作って 公開 したようです。 最近も神戸大学のLMS (BEEF+) を改造しました(BEEF++プログラム)。

卒論のプロジェクトとして既存のアプリに加えたい新機能の研究をしたいという場合にも使えます。 既存のアプリとほとんど同じものをまるまる作ってさらに新機能を付け加えるというのはとても大変ですが、 Chrome 拡張機能を使えば既存のウェブアプリに新しい機能の部分だけを付けくわえることが可能です。 これまでにも以下のような研究を Chrome 拡張機能を作って行いました。

改造元のウェブアプリがアップデートされたときにあわせて拡張機能もアップデートしないと動かなくなってしまう場合があるので注意が必要です。 (実際、下2つの拡張機能は動かなくなってしまってメンテ中です。)

うれしいこと3:黒歴史を生み出さずにウェブページの作り方を学べてうれしい

ウェブページの作り方の練習になります。 ウェブページの作り方を学ぶとき、作りたいページのネタがないと、たいていの場合、黒歴史的な自己紹介ページができあがります。 Chrome 拡張機能は、ネタとして既に存在する無数のウェブページが使えますから、無暗に黒歴史を生成する必要がありません。

HTML と CSS

拡張機能を作るには JavaScript に加えて、HTML と CSS についても知っている必要があります。 HTML と CSS については他の授業で演習の機会があったものと思いますので、ここではごく簡単に振り返ります。 あらためてしっかり勉強したいという方には プログラミング学習サービス ProgateHTML & CSS コース をおススメします。

HTML
ウェブページの内容を記述するための言語
CSS
ウェブページの見た目を記述するための言語

HTML で記述されたウェブページはたとえば以下のような文書です。 文中 <h1>...</h1> はそこが一番大きいレベルの見出しであることを表します。 このようにして文章の各パーツを挟んでその意味するところを指定していくことができるのが HTML の特徴です。 <h1>, <h2>, <p> などの文書パーツを挟むために使う文字列のことを タグ (tag) と呼び、 タグと挟まれた中身を合わせて 要素 (element) と呼びます。

<body>
  <h1><strong class="keyaki">欅坂46</strong>プログラミング</h1>
  <p>
    今回は<strong class="keyaki">欅坂46</strong>を題材としたプログラム作成を通じて、
    好きなものを題材とするとモチベーションが上がるだけでなく、
    作品を多くの人に見てもらえるということを学びます。
    <strong>※この記事はフィクションです</strong>
  </p>
  <h2>目次</h2>
  <ol>
    <li><a href="#extension">欅坂46 Chrome拡張機能</a></li>
    <li><a href="#songlesync">アニメーション作品 by Songle Sync</a></li>
    ...
  </ol>
  <h2 id="extension">欅坂46 Chrome拡張機能</h2>
  ...
</body>

タグには <a href="#extension">...</a>, <h2 id="extension">...</h2> のように情報を追加することができます。 これらの情報のことを 属性 (attributes) と呼びます。 先の例でいうと「h2 要素の id 属性の値が "extension"」といった言い方になります。 どのようなタグがあるか、どのような属性があるか、ここですべてを列挙することはしません。 html リファレンス とウェブ検索すると一覧が見つかるはずです。

続いて CSS です。HTML と組み合わせて「こういう要素はこのように表示してください」というルールを列挙していくものです。 対象とする要素の指定方法には主に3種類あります: 1. タグで指定, 2. idで指定, 3. classで指定です。 これらの指定方法は JavaScript で変更を加えたい部分を指定するときにも使う ので覚えておきたいところです。

CSS での要素の指定方法

1. タグで指定

シンプルにタグの名前で指定します。以下の例のように CSS を記述すると HTML 文書中の strong 要素のすべてが赤色になります。

strong {
  color: red;
}

実践的には同じタグでも異なる見た目を指定したいことが多いので、残り2つの方法を組み合わせて使っていきます。

2. idで指定

ある特定の要素1つを指定したい場合にはid属性の値で指定するのが簡単です。 以下の例のように記述するとid属性として extension が指定されている要素のテキストに下線が引かれます。 # (シャープ)に続く文字列はid値だとみなされるということです。

#extension{
  text-decoration: underline;
}

この指定方法を使うためには HTML 文書の方で要素にidが指定されている必要があります。 idは、ある学校の特定の学生を学籍番号で示すように、ある文書中の特定の要素を示すためのもので、文書内での重複がないように設定されます。 重複があるとしたら作成ミスです。

拡張機能は他の誰かが作った HTML 文書を書き換えるものですので、元ページ中の書き換えたい要素にidが指定されていなくてこの方法が使えないこともよくあります。

3. classで指定

複数の要素を仲間としてまとめることができるのがclassです。 以下のように記述するとclass名として keyaki が指定されている要素の色をまとめて指定することができます。 . (ピリオド)に続く文字列はclass名だとみなされるということです。

.keyaki{
  color: #5fb955;
}

この指定方法を使うためには HTML 文書の方で要素にclassが指定されている必要があります。 要素の見た目をまとめて指定することができるのは便利なのでclassが用いられることは多く、 拡張機能で書き換え対象の要素をclassで指定する機会も多いです。

手動でウェブページを書き換えてみよう

デベロッパーツールを使うと、表示中のウェブページの HTML や CSS を確認できるだけでなく、書き換えてみることができます。 手動で書き換えを行ってみることは、プログラムを書く前のウォーミングアップとしておすすめです。 (ここでは Chrome で説明しますが、 Edge や Safari など他のブラウザでも同じようなことができます。) 自分が受信したデータを書き換えているだけなので他の人の表示に影響はありませんし、再読み込みすれば書き換え前に戻ります。 安心していじくり倒してください。

デベロッパーツールは、メニューの「その他のツール > デベロッパーツール」かキーボードショートカット (Windowsでは Ctrl + Shift + I Mac では Option + Command + I)で開きます。

デベロッパーツール上 Elementsというタブの左側に表示されているのが HTML です。 HTML の上でマウスカーソルを動かすと、表示されているウェブページの対応する部分がハイライトされます。 ウェブページとデベロッパーツールを横に並べて見比べてみましょう。 さらに HTML 中の要素をクリックで選択すると、その要素に適用されている CSS が右側に表示されます。 表示しているウェブページから要素を選択することもできます。 ウェブページ中で確認したい部分の上で右クリックして、メニューから「検証」を選ぶと、デベロッパーツール上でその要素が選択されます。

選択の仕方がわかったら次は書き換えてみましょう。

HTMLを書き換えてみる

デベロッパーツール上で書き換えたい要素を右クリックするとメニューが表示され、各種の書き換えを行うことができます。 一番わかりやすいのは Delete element でしょうか。 再読み込みすると元に戻ってしまうのであまり意味はないですが、広告などを消してしまうと気持ちがよいです。

CSSを書き換えてみる

デベロッパーツール右側に表示されているCSSの上にマウスカーソルを乗せるとチェックボックスが表れます。 このチェックを外すことでその表示ルールを無効にすることができます。 その効果は即座にウェブページの表示に反映されます。

設定されている値をクリックすると入力できるようになり、書き換えることができます。 新しい表示ルールを追加することもできます(上図右下のボタンからメニューを表示)。

練習

普段見ている色々なページで実際に書き換えを試してみてください。わけがわからなくなったら再読み込みしましょう。

Consoleにプログラムを入力してウェブページを書き換えてみよう

HTMLとCSSをなんとなく思い出せたら、いよいよプログラミングです。ここからはデベロッパーツールの Console タブで作業します。

Consoleにはプログラム中で console.log(...) を実行したときの出力や、 プログラム実行中に発生したエラーなどに関する情報が出力されますので、プログラム作成中には頻繁に確認することになります。 しかし、それだけでなくConsoleに直接プログラムを入力して実行することもできるのです。

Consoleで1行プログラミング

このページを表示した状態でConsoleを開き、console.log("test") と入力して Enter キーを押してみてください。 プログラムが実行され、以下のように表示されると思います。

今は test と出力するプログラムを実行しましたので、そう出力されるのは想定通りですが、 undefined はどういうことでしょうか。 その説明も兼ねて、次は document.querySelectorAll("h2") と入力して同じように実行してみてください。

今度は NodeList と表示されました。 これは document.querySelectorAll("h2") で関数を実行した戻り値です。 先の console.log(...) には戻り値がないので undefined と表示されたというわけです。 関数や戻り値について忘れてしまったという人は こちらを読んで思い出してください

document.querySelectorAll(...) は、文書中で指定した条件を満たす要素が含まれる NodeList を返します。 NodeList は配列に似ていて、複数の要素を繰り返しで処理することができます。 Console 上で NodeList をクリックすると含まれる要素の詳細を見ることができます。

似た機能として、条件を満たす最初の要素1つを返す document.querySelector(...) もあります。 条件を満たす要素が見つからない場合には null を返します。 null は「無い」ということを表すための特別な値です。

練習

Console 上で document.querySelectorAll(...) を使ってみましょう。 条件の指定方法は 先ほど学んだCSSでの要素指定方法 と同じですので、色々な条件に変えて試してみてください。 Consoleで上矢印キーを押すとこれまでに入力したプログラムが再度入力されるので、条件の部分だけ書き換えて実行すると楽です。

Consoleで拡張機能を試作する

Consoleでも変数を宣言したり、関数を定義したりすることができますので、もっと複雑なプログラムを実行することもできます。 たとえば、以下のプログラムをコピペして実行すると、文書中の見出しに番号が振られます。 textContent は要素のテキスト部分のことで、新しい文字列を代入することで書き換えています。

let headings = document.querySelectorAll("h2");
for(let i = 0; i < headings.length; i++){
  let e = headings[i];
  e.textContent = i + ". " + e.textContent;
}

もう一つ別の例を見てみましょう。 食べログのページ を開いた状態で以下のプログラムを実行すると予約カレンダーを消してしまうことができます。 カレンダー部分には HTML で同じ class が設定されていますのでそれを条件として書き換えたい要素の NodeList を取得しています。 こういうプログラムを書くときには元の HTML をよく観察して、ほしい要素を取得できる条件の指定方法を考えることが必要です。

let calendars = document.querySelectorAll(".list-rst__calendar-frame");
for(let i = 0; i < calendars.length; i++){
  let e = calendars[i];
  e.style.display = 'none';
}

条件分岐を使うと、条件を満たす店だけ消すことなんかもできますね。

let es = document.querySelectorAll(".list-rst");

for(let i = 0; i < es.length; i++){
  let e = es[i];
  let genreNode = e.querySelector(".list-rst__area-genre");
  if(genreNode && genreNode.textContent.includes("居酒屋")){
    e.style.display = 'none';
  }
}

この例に登場する e.querySelector(".list-rst__area-genre") では、要素 e の中で、条件を満たす要素を求めています。 このように文書全体ではなくある要素の中だけで要素を検索することもできます。

先に説明した通り、querySelector(...)null を返すことがあり、 存在しないことを示す null についてプログラムを実行するとエラーが発生します。 これを回避するためには条件分岐を使って「null ではない場合、処理を行う」ようにプログラムを書く必要があります。 ある変数が null でないことを調べるには if(変数) と書きます。 if(genreNode && genreNode.textContent.includes("居酒屋")) は、 1つ目の条件で null ではないことをチェックしつつ、2つ目の条件で「居酒屋」という文字列が含まれているかをチェックしています。

練習

Console で実行するプログラムは再読み込みすると実行前の状態に戻ってしまいます。 そのたびに今のように手動で実行するのではなく、ページが読み込まれた瞬間に実行するようにすると拡張機能の出来上がりです。 同様に、ページが読み込まれた瞬間に用意しておいたCSSを適用するということもできます。 その具体的な方法については次回扱います。

ウォーミングアップ編は以上です。次はいよいよ拡張機能を作っていきます!

おまけ:1行プログラミング

上のプログラムは1行で書くこともできます。これまでに説明していない書き方を2つ使います。

以上を踏まえて、以下のプログラムを読んでみてください。(これらがわからなくても大丈夫なように進めていきますので、わからなくても気にしなくて大丈夫です。)

見出しに番号を振る1行版

document.querySelectorAll("h2").forEach((e, i) => { e.textContent = i + ". " + e.textContent })

食べログ予約カレンダー削除1行版

document.querySelectorAll(".list-rst__calendar-frame").forEach(e => e.style.display = 'none')