JavaScriptで外部ページを取得して解析するwebアプリをつくります。
まずHTMLソースを取得しなければなりません。C#であれば以下のようにすれば取得できます。
1 2 3 4 5 6 7 |
// フィールド変数として宣言する(アプリケーションが終了するまでDisposeしないこと) System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient(); void GetHtml(){ string html = await httpClient.GetStringAsync("https://www.yahoo.co.jp/"); // やりたいことをする } |
自分のサイト内であればfetch()メソッドで
JavaScriptであればfetch関数を使います。従来はjQueryによるAjaxやaxiosというライブラリを使わなければならなかったのですが、いまではfetchAPIという機能があるので以下の処理で外部ページを取得することができます。
1 2 |
let responce = await fetch('https://lets-csharp.com/'); let html = await responce.text(); |
もしそのページから貼られているリンクをすべて取得するのであれば以下のようにします。ただしこれができるのは自分のサイト内だけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let links = []; // リンク先urlを格納する配列 let texts = []; // アンカーテキストを格納する配列 let responce = await fetch('https://lets-csharp.com/'); let html = await responce.text(); const dom = new DOMParser().parseFromString(html, 'text/html'); const anchors = dom.querySelectorAll('a'); for(a of anchors) { links.push(a.getAttribute('href')); texts.push(a.innerText); } |
自分のサイト内でない場合
自分のサイト内ではないページで同じようなことをしようとするとエラーが発生します。コンソールをみると以下のようなメッセージが表示されます。以下はYahoo! JAPANのリンクを取得しようとした場合のエラーメッセージです。
1 |
クロスオリジン要求をブロックしました: 同一生成元ポリシーにより、https://www.yahoo.co.jp/ にあるリモートリソースの読み込みは拒否されます (理由: CORS ヘッダー ‘Access-Control-Allow-Origin’ が足りない)。ステータスコード: 200 |
ではどうするか? phpを使って回避するのはどうでしょうか? get-data.phpというファイルを自分のサイト内にアップロードしておきます。これが実行されるとHTMLソースが表示されます。get-data.phpは自分のサイト内にあるので、クロスオリジン要求をブロックされることはないというわけです。
get-data.php
1 2 |
<?php echo file_get_contents($_GET["path"]); |
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
let links = []; let texts = []; // エンコードしておく let responce = await fetch('./get-data.php?path=' + encodeURI('https://www.yahoo.co.jp/')); let html = await responce.text(); const dom = new DOMParser().parseFromString(html, 'text/html'); const anchors = dom.querySelectorAll('a'); for(a of anchors) { links.push(a.getAttribute('href')); texts.push(a.innerText); } |
応用例
以下はテキストボックスに入力されたページからでているリンクの一覧を表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>リンクを取得し表示する</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> #target-url { width: 300px; } </style> </head> <body> <p><input type="text" id = "target-url"></p> <p><button onclick="showLink()">リンクを表示する</button></p> <p><button onclick="clearText()">クリア</button></p> <div id = "result"></div> <script src='./index.js'></script> </body> </html> |
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
let $targetUrl = document.getElementById('target-url'); let $result = document.getElementById('result'); function clearText(){ $targetUrl.value = ''; $result.innerHTML = ''; } async function showLink(){ let links = []; let texts = []; await getLinks($targetUrl.value, links, texts); let ret = ''; for(let i=0; i < links.length; i++) ret += `<p><a href="${links[i]}" target="_blank" rel="noopener">${texts[i]}</a></p>`; $result.innerHTML = ret; } async function getLinks(targetUrl, links, texts){ targetUrl = encodeURI(targetUrl); // エンコードしておく let responce = await fetch('./get-data.php?path=' + targetUrl); let html = await responce.text(); const dom = new DOMParser().parseFromString(html, 'text/html'); const anchors = dom.querySelectorAll('a'); for(a of anchors) { links.push(a.getAttribute('href')); texts.push(a.innerText); } return links; } |
get-data.php
1 2 3 4 5 |
<?php if (isset($_GET["path"])) echo file_get_contents($_GET["path"]); else echo ''; |