ポク太郎です。
本ページの話題は「JavaScriptで別ページ内のHTML情報を取得する。」『JavaScriptで3択クイズを作ろう』中の一機能。
ソース丸ごと閲覧者のデバイスにダウンロードするJavaScriptなので、閲覧者に答えがバレないようクイズの問題と答えを別ページに準備し、それをJavaScriptで読みに行く仕様とするために。
JavaScriptで作るクイズの仕様と呼び名の定義
1 別ページB | クイズの問題と答えを書いた別ページ。 通常、クイズページAをリファラーとするアクセス以外をブロックする閲覧制限付。 |
2 別ページB読み取り機能 | 別ページB内の情報を読み取る機能。クイズページA内に設置するJavaScriptで実現。 |
3 クイズページA | 別ページBを読み取るためのJavaScriptと、それを表示するための表示枠設置。例では表示枠を<div id=”debug”></div>としました。 |
以下から上記を作っていきます。
1. 別ページBのHTMLと閲覧制限
ブログのタイムラインに出現しないよう“固定ページ”に作成した別ページBのURLは、
上記は見本なので閲覧制限は付けてありません。
ドメインが異なる別のサイト上でもOK。
別ページBのHTML
以下がHTML内容。
<html> <head> <meta name="robots" content="noindex,noarchive,nofollow"> </head> <body> <!-- ここに貼る --> <div style="visibility:hidden;"> <div class="qdt">9000,足し算,r,3+5=?,8○,9,10,正解は「8」です。</div> <div class="qdt">9001,足し算,r,4+5=?,8,9○,10,正解は「9」です。</div> <div class="qdt">9002,足し算,r,3+9=?,12○,15,10,正解は「12」です。</div> <div class="qdt">9003,足し算,r,2+8=?,8,9,10○,正解は「10」です。</div> <div class="qdt">9004,引き算,r,2-5=?,-3○,-5,7,正解は「-3」です。</div> <div class="qdt">9005,引き算,r,11-4=?,7○,9,10,正解は「7」です。</div> <div class="qdt">9006,引き算,r,9-2=?,7○,6,11,正解は「7」です。</div> <div class="qdt">9007,引き算,r,8-5=?,3○,2,13,正解は「3」です。</div> <div class="qdt">9008,掛け算,r,2x5=?,10○,12,7,正解は「10」です。</div> <div class="qdt">9009,掛け算,r,11x4=?,44○,42,7,正解は「44」です。</div> <div class="qdt">9010,掛け算,r,4x4=?,16○,20,8,正解は「16」です。</div> <div class="qdt">9011,掛け算,r,3x4=?,12○,10,7,正解は「12」です。</div> <div class="qdt">9012,割り算,r,10/5=?,2○,3,4,正解は「2」です。</div> <div class="qdt">9013,割り算,r,9/3=?,3○,4,5,正解は「3」です。</div> <div class="qdt">9014,割り算,r,3/2=?,1.5○,2,1,正解は「1.5」です。</div> <div class="qdt">9015,割り算,r,4/2=?,2○,1,4,正解は「2」です。</div> <div class="qdt">9016,慣用句,r,○○を漢字で埋めなさい。豚に○○。,真珠○,念仏,小判,正解は「真珠」です。</div> <div class="qdt">9017,慣用句,r,○○を漢字で埋めなさい。人生万事塞翁が○,馬○,豚,猿,正解は「馬」です。</div> <div class="qdt">9018,慣用句,r,○○を漢字で埋めなさい。猿吉は○でも踏んどれ。,麦○,米,肉,正解は「麦」です。</div> <div class="qdt">9019,慣用句,r,○○を漢字で埋めなさい。パンツトラナイデネ!○○トコナイデネ!,二度○,再度,既,正解は「二度」です。</div> </div> </body></html>
まず最初に、用途から考えて別ページBは検索エンジンに登録されてはいけないのでNOINDEX属性必須。やり方はHTMLの<head></head>タグ内に以下記述。
<meta name="robots" content="noindex,noarchive,nofollow">
次に内部。<div class=”qdt”></div>とある20行がクイズのデータ。
データのフォーマットを、
としました。シャッフルフラグとは選択肢の順番を並び替えて出題するかどうか、また選択肢中の正解には文末に○を付けておく仕様とします。
クイズページAに実装されるJavaScriptは<div class=”qdt”></div>を頼りにこれらHTMLテキストをデータとして読み込みます。
別ページBに必要なのは閲覧制限
別ページBはクイズの問題と答え・解説が書いてあるページなので、閲覧制限しておかないと意味がありません。つまり、クイズページA以外からのアクセスをブロックする必要があります。
方法はいくつかありますが、完璧なブロックを行うには.htaccessファイルを使える環境である必要があります。
1 | .htaccessファイルでリファラー指定。 | 通常無料ブログは.htaccessファイルを置けないので、レンタルサーバなどのみで使える方法。ただし100%ブロック可能。 |
2 | JavaScriptでリファラーをチェックし条件判定。 | 無料ブログでも使える方法。ただし、JavaScriptオフにしてアクセスされると閲覧できてしまう。CSSで非表示にすることはできるがソースは見れてしまう状態。 |
実装例1 .htaccessによる別ページBの閲覧制限
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / SetEnvIf Referer "クイズページAのURL" ref=qpage SetEnvIf REQUEST_URI "別ページBのURL" req=qkotae RewriteCond %{ENV:req} qkotae RewriteCond %{ENV:ref} !qpage RewriteRule .* https://www.google.com/ [R=301,END] </IfModule>
上記の意味は、REQUEST_URIが別ページBである場合、そのリファラーがクイズページAでなかったらgoogleへ転送しろ、というもの。
今の場合、”別ページBのURL“部分は”/js-test”と書き、”クイズページAのURL“部分は設置する本ページのURL”/pc/code/js-quiz.html”と記述。URLのドメイン以下の部分を先頭に/付で記述。
実装例2 JavaScriptによる別ページBの閲覧制限
var ref = document.referrer; if( ref == 'クイズページAのURL' ){ } else { window.top.location.href = "//www.google.com/"; }
完璧なブロックはできないが、無料ブログでも使えるJavaScriptを使った方法。
document.referrerプロパティを使ってリファラーを調べ、それがクイズページAのURLでない場合、googleへ転送します。
2&3. 別ページの内容を読み取るJavaScript関数
クイズページA内の、結果を表示したい表示領域に、idを“debug”とした<div>タグを設置しておく必要があります。
クイズページAのHTMLがこちら。先の表中3番の機能。
<div id="debug"></div>
クイズページAに設置するJavaScriptソースがこちら。先の表中2番の機能。
document.getElementById("debug").innerHTML = ''; var obj = new XMLHttpRequest(); obj.open('GET','https://poku.blog/js-test',true);//true:非同期通信 obj.onreadystatechange = function(){ if (obj.readyState === 4 && obj.status === 200){ var str = obj.responseText; //読み込んだHTMLを変数に代入 //----処理 var qdt = str.match(/<div class="qdt">.+?<\/div>/g); document.getElementById("debug").style.display = ''; //id="debug"タグにテキストを記述する。 for (var i=0;i<qdt.length;i++){ document.getElementById("debug").innerHTML += qdt[i]; } //----処理 } }; obj.send(null); //リクエストの送信
外部参照用の箱obj | 外部参照用の箱として変数objを準備し、new XMLHttpRequest()を代入。 |
実際に別ページBへアクセス。 | obj.open(‘GET’,’と、別ページ ‘,true);BのURLを指定。 |
obj.onreadystatechange = function() | 状態変化が認められた時に走るfunction()関数内に条件指示。上記例のif文では、obj.readyStateが“転送完了”かつレスポンスコードが代入されるobj.statusが“200”であることを条件にしています。 |
変数strに全データ | obj.responseTextに読み込んだHTMLが代入されてるので変数strに代入。 |
正規表現で該当部位を変数qdtに代入 | 変数strの内、別ページBの仕様とした<div class=”qdt”>を含む部分のみを変数qdtに代入。正規表現を満足するものを選び出す機能.matchを使用しています。 その配列qdt全部を次のfor文で表示領域に全表示。 |
1 | obj.open(‘GET’,’ ‘,true); | 実際に外部ページを読みに行けと命令する部分。オプションパラメータは非同期通信の指定。例では非同期を指定するtrue。 |
2 | obj.onreadystatechange | XMLHttpRequest()に何らかの状態変化が起きたフラグ。 |
3 | obj.readyState | XMLHttpRequest()の接続状態を表す値が入るプロパティ。“4”は転送完了を表す。XMLHttpRequest.readyStateの結果と表す状態。 |
4 | obj.status | XMLHttpRequest()接続のエラーコードが入るプロパティ。“200”…正常終了、“404”…存在せずなど。HTTP レスポンスステータスコード。 |
5 | obj.responseText | XMLHttpRequest()接続先の全HTMLテキストが代入される変数。 |
表示領域~
~
表示領域。別ページBから情報を読み取ってしまえば、後は配列変数などに格納し好きなように値として扱えます。
本ページでは別ページの内容をJavaScriptで読み取るまでを実施してみました。
Step1 仕様・必要機能 | Step2 別ページのHTML取得 | Step3 出題用2次元配列へ | Step4 閲覧者の回答検出・判定 |
コメント