JavaScriptで別ページのHTMLテキストをデータとして取得する機能

勘違いしながらドはまりしながら作り上げていく『JavaScript奮闘記』。事始めのJavaScript常識をまとめたページや現在作ろうとしてるクイズの仕様説明はこちら。

ポク太郎です。

本ページの話題は「JavaScriptで別ページ内のHTML情報を取得する。」『JavaScript3択クイズを作ろう』中の一機能。

ソース丸ごと閲覧者のデバイスにダウンロードするJavaScriptなので、閲覧者に答えがバレないようクイズの問題と答えを別ページに準備し、それをJavaScriptで読みに行く仕様とするために。


JavaScriptで作るクイズの仕様と呼び名の定義

準備するもの
1
別ページB
クイズの問題と答えを書いた別ページ。
通常、クイズページAをリファラーとするアクセス以外をブロックする閲覧制限付。
2
別ページB読み取り機能
別ページB内の情報を読み取る機能。クイズページA内に設置するJavaScriptで実現。
3
クイズページA
別ページBを読み取るためのJavaScriptと、それを表示するための表示枠設置。例では表示枠を<div id=”debug”></div>としました。

以下から上記を作っていきます。

1. 別ページBのHTMLと閲覧制限

ブログのタイムラインに出現しないよう“固定ページ”に作成した別ページBのURLは、

poku.blog/js-test

上記は見本なので閲覧制限は付けてありません。

アクセスする場合は先頭にhttps://を付けて下さい。style=”visibility:hidden;”としてあるので中身は見えませんが。

ドメインが異なる別のサイト上でもOK

訂正)ドメインが異なる他サイトはHTTPステータスコードに0が返ってきてしまいアクセスできません。“クロスドメイン通信”と呼ばれ認証が必要になります。

別ページ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行がクイズのデータ。

データのフォーマットを、

クイズNo,カテゴリ,シャッフルフラグ,問題文,選択肢1,選択肢2,選択肢3,正解の解説文

としました。シャッフルフラグとは選択肢の順番を並び替えて出題するかどうか、また選択肢中の正解には文末に○を付けておく仕様とします。

クイズページAに実装されるJavaScript<div class=”qdt”></div>を頼りにこれらHTMLテキストをデータとして読み込みます。

別ページBに必要なのは閲覧制限

別ページBはクイズの問題と答え・解説が書いてあるページなので、閲覧制限しておかないと意味がありません。つまり、クイズページA以外からのアクセスをブロックする必要があります。

方法はいくつかありますが、完璧なブロックを行うには.htaccessファイルを使える環境である必要があります。

閲覧制限の実現方法と条件
1.htaccessファイルでリファラー指定。通常無料ブログは.htaccessファイルを置けないので、レンタルサーバなどのみで使える方法。ただし100%ブロック可能。
2JavaScriptでリファラーをチェックし条件判定。無料ブログでも使える方法。ただし、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に実装するJavaScriptJavaScriptが走った後、別ページB内のテキストを変数に納めるまでの機能です。

クイズページ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); //リクエストの送信

XMLHttpRequest()に関する説明
外部参照用の箱obj外部参照用の箱として変数objを準備し、new XMLHttpRequest()を代入。
実際に別ページBへアクセス。obj.open(‘GET’,’https://poku.blog/js-test‘,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文で表示領域に全表示。

判定や値を利用するXMLHttpRequest()関連パラメータ
1obj.open(‘GET’,’URL‘,true);実際に外部ページを読みに行けと命令する部分。オプションパラメータは非同期通信の指定。例では非同期を指定するtrue
2obj.onreadystatechangeXMLHttpRequest()に何らかの状態変化が起きたフラグ。
3obj.readyStateXMLHttpRequest()の接続状態を表す値が入るプロパティ。“4”は転送完了を表す。XMLHttpRequest.readyStateの結果と表す状態
4obj.statusXMLHttpRequest()接続のエラーコードが入るプロパティ。“200”…正常終了、“404”…存在せずなど。HTTP レスポンスステータスコード
5obj.responseTextXMLHttpRequest()接続先の全HTMLテキストが代入される変数。

ここから表示領域~

ここまで表示領域。

別ページBから情報を読み取ってしまえば、後は配列変数などに格納し好きなように値として扱えます。

本ページでは別ページの内容をJavaScriptで読み取るまでを実施してみました。

JavaScript3択クイズを作ろう
Step1
仕様・必要機能
Step2
別ページのHTML取得
Step3
出題用2次元配列へ
Step4
閲覧者の回答検出・判定

コメント

タイトルとURLをコピーしました