12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Chrome Extension】ポップアップから簡易スクレイピング

Last updated at Posted at 2020-07-16

はじめに

  • 特定のページからちょこっと情報を取得したいけど、NodeJSやPythonでがっつりやるのは大袈裟過ぎる
  • 非エンジニアさん向けのスクレイピングツールを作りたいけど、相手のPCに動作環境がない

こんなときはChrome Extensionとかいかがでしょうか?
Chrome Extensionなら、Google Chrome(動作環境)とExtensionの入ったフォルダさえあれば動きます。

本記事では、Chrome Extensionで簡易的なスクレイピングを行う方法を紹介します。
コード一式はこちら
PopupParser.gif

コード

以下の順番で実装していきます。

  1. Chrome Extensionでポップアップを表示する
  2. ポップアップ内のボタンを押してバックグラウンドでタブを開く
  3. 開いたタブの内容を取得してポップアップ内に表示
  4. 表示した内容をクリップボードにコピー

用途としては「管理画面の入力に必要な情報を特定のページから取得して参照する」などを想定してます。

ブラウザアクションを追加してポップアップを有効にする

manifest.jsonで、browser_actionを有効にします。

// manifest.json
{
  ...
  "browser_action": {
    // ツールバーにエクステンションを表示する設定 + 表示するアイコンのパス
    "default_icon": "icon128.png",
    // ツールバーのアイコンをクリックしたときにポップアップを表示する設定
    "default_popup": "popup/popup.html"
  }
}

ポップアップから新しいタブをバックグラウンドで開く

ポイントは2つ

  • chrome.tabs APIを使用できるように、permissionsにtabsをセットする
  • タブを開いた時点でポップアップが閉じないように、chrome.tabs.createメソッドのactiveオプションにfalseを渡す
// manifest.json
{ 
  ...
  // chrome.tabs.createなどのメソッドを使用できるように設定
  "permissions: ["tabs"]
}
// popup.js
async function loadNewTab(url, timeoutSeconds = 5) {
  return new Promise((resolve, reject) => {
    let targetTabId = null
  
    const listener = (tabId, changedProps) => {
      if (tabId != targetTabId || changedProps.status != 'complete') {
        return
      }
      chrome.tabs.onUpdated.removeListener(listener)
      resolve(tabId)
    }
    chrome.tabs.onUpdated.addListener(listener)
          
    // ポップアップが閉じないように、active: falseを設定する
    chrome.tabs.create({ url, active: false }, (tab) => {
      // 開いたtabのidをスコープの変数にセットする
      targetTabId = tab.id
    })
   
    setTimeout(() => {
      reject(new Error('Time out...'))
    }, timeoutSeconds * 1000)
  })
}

loadNewTabメソッドをpopup.htmlに設置したボタンのイベントリスナー内で呼び出します。
Promiseで包んでasyncにしていますが、普通にコールバック内で結果を受けるようにしても問題ありません。

新しく開いたタブから情報を取得してポップアップに表示する

ここでは例として、英語版Wikipediaのトップページから本日の記事のテキストを取得します。

ポイントは3つ

  • permissionsに情報を取得したいURLを指定する(ホストだけでもOKのようです)
  • chrome.tabs.executeScriptの第一引数にtabIdを渡すことで、非アクティブのタブでスクリプトを実行可能
  • chrome.tabs.executeScriptのコールバックでスクリプトの結果を取得可能
// manifest.json
{
  ...
  "permissions": [
     "tabs",
     "https://en.wikipedia.org/wiki/Main_Page"
   ]
// popup.js
async function parseWikipedia(tabId) {
  return new Promise((resolve, reject) => {
    chrome.tabs.executeScript(
      tabId,
      { file: 'parser/parseWikipedia.js' },
      (results) => {
        if (results[0] === null) {
          reject(new Error('Failed to parse wikipedia.'))
        } else {
          resolve(results[0])
        }
      }
    )
  })
}

// parseWikipedia.js
;(() => {
  function parse() {
    // Get text from "From today's featured article"
    return document.querySelector('#mp-tfa p').textContent
  }
   
  try {
    return parse()
  } catch (e) {
    console.log(e)
    return null
  }
})()

chrome.tabs.executeScriptに渡すスクリプトでは、結果もしくはnullを返すようにしています。
スクリプト内でキャッチできない例外が発生した場合は、results[0]にはundefinedが入るようです。

ポップアップ内に表示した結果をクリップボードにコピーする

// 結果は、<textarea id="content"></textarea>のtextContentに格納されている前提
function copyResult() {
  document.querySelector('#content').select()
  document.execCommand('copy')
}

終わりに

定期的に実行するほどでもないけど、たまにスクレイピングしたいみたいなときにも便利かと思います。
ちょっとスクレイピングしたいなってときも、ボタンとURL、ページ固有のスクリプトを追加するだけで済みます。是非使ってみてください!

コード一式はこちら(再掲)。

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?