概要
Chrome拡張機能とは
Chromeの機能を拡張するアドオンプログラムです。
JavaScriptで作成可能で、開いているページ上で、画面の操作や補助など作業の効率化が図れます。
画面表示時に広告をブロックしてくれるAdBlockや、画面上の英文を変換してくれるGoogle翻訳などが有名かと思います。
RSSとは
RSSとは、ニュースやブログなど各種のウェブサイトの更新情報を配信するための文書フォーマットの総称です。XML形式で配信され、大きく分けるとRSS1.0
RSS2.0
ATOM
のフォーマットがあります。
今回のやりたいこと
RSS解析のために様々なサイトのRSSを取得したいというのと、Chromeの拡張機能を作成してみて、Chromeの拡張機能の開発手法を理解したいというのが目的です。
そのため、画面表示時にRSSのURLがページ上に存在していた場合に、RSSのURLを表示してくれるChromeの拡張機能を作成します。
完成したもの
Chrome拡張機能へのリンク
実際の動作
RSSのURLがあった場合に、拡張機能のアヒルのアイコンにRSS数のバッチをつけて、クリックをするとリンク一覧が表示されます。
(※開いたXMLの可読性がよくなるJSONVue
というChromeの拡張機能を使用しています。使いやすいので愛用しています。皆さんもぜひ!)
ディレクトリ構成
ディレクトリは以下のような構成にしました。
manifest.json
やicon
なども必要なのですが、今回は、HTMLとJavaScriptの説明のみのさせてください。
├ popup/
│ ├ popup.html
│ ├ popup.js
│ └ popup.css
├ content/
│ └ content.js
└ background/
└ background.js
クロームの拡張機能の構造は、以下の3つに分かれており、私はこのような解釈で実装しております。
- popup : 拡張機能のアイコンをクリックすると表示されるウインドウを実装
- content : 表示されているページについての処理を実装
- background : タブや拡張機能のバッチなどブラウザ自体の機能やイベントを実装
プログラム説明
簡単に作成したプログラムについて説明します。
popupについて
拡張機能のアイコンをクリックすると表示されるウインドウをjquery
やbootstrap
を用いて実装しています。URLを別タブで開く処理ですが、Chromeの拡張機能ではHTMLのhrefではエラーになってしまうため、js側で開くような処理になっています。
popup.htmlの中身
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../lib/jquery/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="../lib/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="popup.css">
</head>
<body>
<div class="header">
Feeduck
</div>
<div id="rss_url_list" class="container">
<p class="not_find">RSSが見つかりませんでした</p>
</div>
<script src="popup.js"></script>
</body>
</html>
popup.cssの中身
.hide {
display: none;
}
body {
min-width:500px;
padding: 5px;
}
.header {
border-bottom: solid 1px gray;
margin-bottom: 10px;
font-size: 18px;
text-align: center;
padding: 6px;
font-weight: bold;
}
.not_find {
text-align: center;
padding: 10px;
}
#rss_url_list {
display: block;
padding: 0 5px;
}
.rss_url_list {
padding: 0 10px;
margin-bottom: 5px;
}
popup.jsの中身
//タブの情報を取得
chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) {
//現在のタブIDを取得
var tabId = tabs[0]['id'];
//現在のタブIDの情報のみ表示
chrome.storage.local.get(String(tabId),function(urls){
if ( urls[tabId].length !== 0 ) {
//RSSが見つかりませんでしたの表示を削除する
$('#rss_url_list').empty();
//URLを表示する
$.each( urls[tabId], function(i, url) {
$('#rss_url_list').append('<div class="row rss_url_list"><input class="col form-control" type="text" value="'+ url +'" readonly><button data-link="'+ url +'" class="col-2 btn btn-primary LinkOpenBtn">開く</button></div>');
});
}
});
});
// 読み込み完了後の処理
window.addEventListener('load', load, false);
function load(e) {
var timer = setInterval(jsLoaded, 1000);
function jsLoaded() {
if (document.querySelector('.rss_url_list') != null) {
// setInterval()解除
clearInterval(timer);
// フォーカスが当たったときに全選択にする
$('.rss_url_list input').focus(function(){
$(this).select();
});
// 開くボタンクリック時のイベント
document.querySelectorAll('.LinkOpenBtn').forEach(function (button) {
button.addEventListener('click', LinkOpen);
});
}
}
}
// URLを開く
function LinkOpen() {
window.open(this.getAttribute('data-link'));
}
contentについて
今表示しているページで動作する処理を記載しています。
そのため、RSSのURLをスクレイピングしてくる処理がメインになります。
content.jsの中身
$(function() {
// background.jsにメッセージを送信
chrome.runtime.sendMessage({rssUrls: rssUrlGet()});
});
//RSSをスクレイピングして取得
function rssUrlGet() {
var rssUrls = [];
$("link[type='application/rss+xml']").each(function(k,e){
var href = $(e).attr('href');
rssUrls.push( absolutePath(href) );
});
$("link[type='application/atom+xml']").each(function(k,e){
var href = $(e).attr('href');
rssUrls.push( absolutePath(href) );
});
//重複の削除
rssUrls = rssUrls.filter( function(element, index) {
return rssUrls.indexOf(element) === index;
});
return rssUrls;
}
// 相対パスを絶対パスに変換
function absolutePath(path) {
var e = document.createElement('a');
e.href = path;
return e.href;
}
backgroundについて
タブを切り替えたときや閉じたときの処理のイベント処理や、拡張機能アイコンに表示される数字バッチなど管理しています。
background.jsの中身
// messageが送された時のイベント
chrome.runtime.onMessage.addListener(
function(message, sender, callback) {
// タブの情報を取得してバッチの表示処理を行う
chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) {
if (tabs[0]) {
var tabId = tabs[0]['id'];
} else {
return;
}
//タブのバッチを初期化する
chrome.action.setBadgeText({
text: '',
tabId: tabId
});
// バッチの表示
if ( message.rssUrls.length == 0 || message.rssUrls.length == null ) {
chrome.action.setBadgeText({
text: '',
tabId: tabId
});
} else {
chrome.action.setBadgeText({
text: message.rssUrls.length + '',
tabId: tabId
});
}
chrome.storage.local.set({[tabId]: message.rssUrls});
});
}
);
// タブ切り替え時のイベント
chrome.tabs.onActivated.addListener(function (activeInfo) {
//保持しているカウントを取り出して表示する
chrome.storage.local.get(String(activeInfo.tabId),function(urls){
if ( urls[activeInfo.tabId] ) {
if ( urls[activeInfo.tabId].length !== 0 ) {
chrome.action.setBadgeText({
text: urls[activeInfo.tabId].length + '',
tabId: activeInfo.tabId
});
} else {
chrome.action.setBadgeText({
text: '',
tabId: activeInfo.tabId
});
}
} else {
chrome.action.setBadgeText({
text: '',
tabId: activeInfo.tabId
});
}
});
});
// タブを閉じたときのイベント
chrome.tabs.onRemoved.addListener(function(tabId, info) {
chrome.storage.local.remove(String(tabId));
});
まとめ
作成したChromeの拡張機能を紹介しました。
この拡張機能を用いることで、RSSを収集が可能となり、RSS解析が捗りそうです。
皆さんもぜひ使ってみてください。
あと、リリースする際に、ZIPファイルにまとめる必要がありますが、jquery
やBootstrap
などのjsのライブラリの管理方法やリリース方法もある程度自動化することを確立できたので、いつか説明できたらと思います
今後も、Chromeの拡張機能を作ってみたいなと思います。
ここまで読んでいただきありがとうございました。