Webサイトのリンク切れについての確認と対策について その2 : リンクサムネイルツール

2024/12/03

Tool

t f B! P L
eyecatch リンクチェッカーを、GopgleChromeブラウザで作っていきます。 今回は、拡張機能のアイコンをクリックしたら、表示しているページ内にあるリンクタグの一覧を取得して、http(https)から書かれているURLの場合、外部リンクとみなして、全てiframeで表示をしてしまおうという強引なツールを作ってみました。

基本セット

ブラウザ拡張機能は、標準セットを自分で作っておくと非常に高速に開発をすることができます。 今回は、自分の手作りセットを利用して、次のファイル構成で造ります。

ファイル構成

/root/ ├ action/ │ ├ css/ │ │ └ style.css │ ├ js/ │ │ ├ main.js │ │ ├ page.js │ │ └ view.js │ └ index.html ├ icon/ │ ├ icon_16.png │ ├ icon_32.png │ └ icon_48.png └ manifest.json

action/css.styke.css

html{ width:400px; } html,body{ margin:0; padding:0; } h1{ margin:0; padding:20px; font-size:16px; } main{ padding:20px; } .item{ width:100%; margin-bottom:30px; display:flex; flex-direction:column; gap:5px; border-bottom:1px solid black; } iframe{ width:100%; height:200px; }

action/js/main.js

import { View } from "./view.js" class Main{ constructor(){ this.init() } init(){ this.set_receive() this.get_url_lists() } set_receive(){ chrome.runtime.onMessage.addListener((message) => { if (message.type === "LINKS") { new View(message) } }) } async get_url_lists(){ // 現在のタブを取得 const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }) // コンテンツスクリプトを実行 chrome.scripting.executeScript({ target : { tabId: tab.id }, files : ["action/js/page.js"] }) } } switch(document.readyState){ case "complete": case "interactive": new Main();break default: window.addEventListener("DOMContentLoaded", (()=>new Main())) }

action/js/page.js

// DOM情報を取得 (function(){ const links = document.links const datas = [] for(const link of links){ datas.push({ html : link.outerHTML, url : link.getAttribute("href"), text : link.innerText, }) } // メッセージを送信 chrome.runtime.sendMessage({ type : "LINKS", datas : datas }) })()

action/js/view.js

export class View{ constructor(options){ this.options = options || {} this.init() } get datas(){ return this.options.datas } get parent(){ return document.getElementById("links") } item = ` <div class="item" data-num="{{num}}"> <a class="name">{{text}}</a> <p class="state"></p> <iframe src="{{url}}"></iframe> </div> ` init(){ if(!this.datas){return} let num=0 for(const data of this.datas){ if(!data.url || !data.url.match(/^http(.+?)/)){continue} data.num = num const html = this.get_html(data) this.parent.insertAdjacentHTML("beforeend", html) const item = this.parent.querySelector(`.item[data-num="${num}"]`) const iframe = item.querySelector("iframe") iframe.addEventListener("readystatechange", this.change_readystate.bind(this)) iframe.addEventListener("load", this.loaded.bind(this)) num++ } } get_html(data){ let html = this.item html = html.replace(/\{\{text\}\}/g, data.text) html = html.replace(/\{\{url\}\}/g, data.url) html = html.replace(/\{\{num\}\}/g, data.num) return html } change_readystate(e){ console.log(e.state) e.target.querySelector(".state").innerText = "state: "+e.state } loaded(e){ e.target.parentNode.querySelector(".state").innerText = e.target.src console.log(e.target.src,e.target.contentWindow) } }

action/index.html

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>URL Checker</title> <meta name="description" content=""> <meta name="author" content=""> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <meta http-equiv="Expires" content="0"> <link rel="apple-touch-icon" href="page/common/img/favicon.png" /> <meta name="apple-mobile-web-app-title" content="ExtensionTemplate"> <link rel="mask-icon" href="img/icon.svg" type="image/svg+xml" color="white" /> <link rel='stylesheet' href='css/style.css'/> <script type='module' src='js/main.js'></script> </head> <body> <h1>URL Checker</h1> <main> <div id="links"></div> </main> </body> </html>

manifest.json

{ "name": "Url Checker", "short_name" : "URLCHK", "version": "0.0.1", "manifest_version": 3, "description": "ホームページのリンク切れなどを目視チェックする。", "icons": { "32" : "icon/icon_16.png", "48" : "icon/icon_48.png", "128": "icon/icon_128.png" }, "permissions" : ["tabs", "activeTab", "scripting"], "action": { "default_popup": "action/index.html", "default_icon" : "icon/icon_32.png" } }

アイコン画像

アイコンは好きなものを使ってもらってもいいし、この画像をサイズ変更して使ってもいいです。 なんなら無くても問題ないです。

GoogleChromeの拡張機能登録

上記モジュールと画像などの素材が用意できたら、GoogleChromeの拡張機能登録をしてみましょう。

1. ブラウザ右上の縦三点リーダーの中の「拡張機能の管理」を選択

2. ディベロッパモードをONにして、パッケージ化されていない拡張機能を読み込むボタンを押す

表示されたダイアログで、上記モジュールが置かれているフォルダを選択します。

3. ブラウザ右上の拡張機能パネルの箇所のパズルのようなアイコンをクリックして、UrlCheckerのPINをONにする

上記の操作で、拡張機能ボタンが表示されているハズです。

iframe一覧を取得

URLを確認したいページで、UrlCheckerのボタンをクリックすると、次のようにiframe一覧が表示されます。
※リンクが多いページでクリックすると、たくさんのリスト表示がされるので、メモリオーバーに注意してください。 実際にリンクを表示してみると、iframeにページが表示されないページがたくさんありますが、 この表示されないページはほとんどが、same domainの設定をサーバーで行っていると、iframeやjavascriptでのアクセス拒否がされてしまう事象です。
回避するには、CGI側で行ったり、Chromiumのようなサーバーブラウザでアクセスして内容をレンダリングするしかないかもですね。

404エラー

アクセス拒否と同じ見た目ですが、「IPアドレスが見つかりません」というエラー内容は、要するにそのURLが存在しないということです。

あとがき

今回、思ったとおりの仕様でiframeを表示するURLチェッカーを作ってみましたが、 これを便利に使ってくれる人もいれば、おそらく機能が足りていない人もいるでしょう。 実際にエラーのあるページがページ内のどの項目なのか?とか、HTMLのどの部分なのかを、もう少し表示させて、運用作業を効率化できるようにする必要があるかもですね。 とりあえず、拡張機能の登録までは行わない予定なので、このツール使いたい人はデバッグモードでお使いくださいませ。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ