WSH(JScript)用HTTPライブラリ:HTTPUtility.js
WSH(JScript)用HTTPライブラリです。
機能概要は、以下の通りです。
- HTTP/HTTPSのファイル取得
- TEXT/HTML/XMLの解析
サンプル
http.wsf<?xml version="1.0" encoding="UTF-16" standalone="yes" ?>
<package>
<job>
<?job error="false" debug="true" ?>
<script language="JavaScript" src="../common/HTTPUtility.js"/>
<script language="JavaScript">
//<![CDATA[
(function() {
"use strict";
var stdout = [];
function println(msg) {
stdout.push(msg);
}
function main() {
// DuckDuckGoで検索
var keyword = 'a';
var url = 'https://duckduckgo.com/html/?q='+keyword+'&kl=jp-jp';
println(url);
// HTMLドキュメント取得 + 解析
var doc = HTTPUtility.httpHTML(url);
var titles = doc.querySelectorAll('#links h2.result__title');
println(titles.length);
for (var i=0; i<titles.length;i++) {
println(titles[i].innerText);
}
// 結果出力
WScript.Echo(stdout.join('\n'));
}
main();
})();
//]]>
</script>
</job>
</package>
出力結果
出力結果>cscript test.wsf
https://duckduckgo.com/html/?q=a&kl=jp-jp
30
Amazon.co.jp | A [DVD] DVD ...
('A`)とは (ドクオとは ...
A-tech
株式会社エーアイ (A,I ...
藤子不二雄aデジタル ...
A-ROUND|個室mitsubachi ...
A.d.s.r.
a-ha fansite for Japanese a-ha fans ...
A M a T A
A-PDF.com - PDFソフトウェア
A-cute | 全年齢 トップ
A-asterisk / 阿司拓设计
HUMOR SHOP | A-net Inc.[株式会社 ...
A-tec 中部国際自動車大学校
Q&Aカード(クエスチョン ...
『Vector』「Q&A」 - Vector ...
アステラス製薬オープン ...
Ju適正販売店|中古車販売 ...
エーチームグループ エー ...
赤バスホームページR
Welcome to Fountain of Rainbow
アルルカン Official Website
Architanz(アーキタンツ ...
アルケマ吉富株式会社 ...
CROCORE
不動産運用 ...
「あねせん」ゲーム ...
A-shape トップページ
株式会社ア・ネット ...
A-cue Records
参考リンク
HTTPUtility.js
GitHubで公開しました。最新版は、k08045kk/WSHLibraryから取得してください。
HTTPUtility.js/*!
* HTTPUtility.js v2
*
* Copyright (c) 2018 toshi - https://www.bugbugnow.net/p/profile.html
* Released under the MIT license.
* see https://opensource.org/licenses/MIT
*
* The querySelectorAllPolyfill function is:
* Copyright (c) 2014 Michael Tsyganov (https://github.com/mtsyganov)
* Released under the MIT license.
* see https://opensource.org/licenses/MIT
*/
/**
* WSH(JScript)用HTTPライブラリ
* @requires module:ActiveXObject('MSXML2.XMLHTTP')
* @requires module:ActiveXObject('MSXML.DOMDocument')
* @requires module:ActiveXObject('htmlfile')
* @requires module:WScript
* @requires ErrorUtility.js
* @auther toshi(https://www.bugbugnow.net/p/profile.html)
* @license MIT License
* @version 2
* @see 1 - add - 初版
* @see 2 - update - テキスト編集処理を追加
*/
(function(root, factory) {
if (!root.HTTPUtility) {
root.HTTPUtility = factory(root.ErrorUtility);
}
})(this, function(ErrorUtility) {
"use strict";
var _this = void 0;
/**
* PrivateUnderscore.Process.js
* @version 1
*/
{
// see https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
function _Array_indexOf(array, searchElement, fromIndex) {
if (array == null) throw new TypeError('"array" is null or not defined');
var o = Object(array);
var len = o.length >>> 0;
if (len === 0) return -1;
var n = fromIndex | 0;
if (n >= len) return -1;
var k = n >= 0 ? n : Math.max(len + n, 0);
for (; k < len; k++) if (k in o && o[k] === searchElement) return k;
return -1;
};
function _getCallee() {
var args = arguments;
var func = args.callee;
return func.caller;
};
function _getFunctionName(func) {
var name = 'anonymous';
if (func === Function || func === Function.prototype.constructor) {
name = 'Function';
} else if (func !== Function.prototype) {
var match = ('' + func).match(/^(?:\s|[^\w])*function\s+([^\(\s]*)\s*/);
if (match != null && match[1] !== '') {
name = match[1];
}
}
return name;
};
function _errormessage(error) {
return ''
+ (error.name? error.name: 'UnknownError')
+ '('
+ (error.number? ((error.number>>16)&0xFFFF)+'.'+(error.number&0xFFFF): '')
+ ')'
+ (error.message? ': '+error.message: '');
};
function _stack(callee, message, prefix) {
callee = callee || _getCallee();
var stack = [message];
var funcs = [];
for (var func=callee.caller; func; func=func.caller) {
if (_Array_indexOf(funcs, func) !== -1) {
stack.push(prefix+_getFunctionName(func)+'()...');
break;
}
funcs.push(func);
stack.push(prefix+_getFunctionName(func)+'()');
}
return stack.join('\n');
};
function _Process_createActiveXObjects(progIDs) {
for (var i=0; i<progIDs.length; ++i) {
try {
return new ActiveXObject(progIDs[i]);
} catch (e) {
if (i == progIDs.length - 1) { throw e; }
}
}
return null;
};
function _Process_createDOMDocument() {
return _Process_createActiveXObjects([
'MSXML2.DOMDocument.6.0',
'MSXML2.DOMDocument.3.0',
'Msxml2.DOMDocument',
'Msxml.DOMDocument',
'Microsoft.XMLDOM']);
};
function _getParentElement(element, tag) {
var callee = _getParentElement;
if (element === null) {
} else if (element.tagName === null) {
} else if (element.tagName.toLowerCase() === tag.toLowerCase()) {
return element;
} else {
return callee(element.parentElement, tag);
}
return null;
}
}
/**
* コンストラクタ
* @constructor
*/
_this = function HTTPUtility_constructor() {};
// 定数
_this.GET = 'GET';
_this.POST= 'POST';
_this.READYSTATE_UNINITIALIZED= 0;
_this.READYSTATE_LOADING = 1; // open呼び出し完了
_this.READYSTATE_LOADED = 2; // send呼び出し完了、ヘッダ受信完了
_this.READYSTATE_INTERACTIVE = 3; // ボディ受信中
_this.READYSTATE_COMPLETE = 4; // 通信完了(成功失敗問わず)
/**
* UserAgent
* Desktop: IE11(Windows)
* Mobile: Firefox(Android)
* TODO:随時更新が必要
* https://developer.mozilla.org/ja/docs/Web/HTTP/Gecko_user_agent_string_reference
*/
_this.Desktop = 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko';
_this.Mobile = 'Mozilla/5.0 (Android 4.4; Mobile; rv:41.0) Gecko/41.0 Firefox/41.0';
_this.UserAgent = _this.Desktop;
function HTTPUtility_createXMLHttpRequest() {
return _Process_createActiveXObjects([
'Msxml2.ServerXMLHTTP.6.0',
'Msxml2.ServerXMLHTTP.5.0',
'Msxml2.ServerXMLHTTP.4.0',
'Msxml2.ServerXMLHTTP.3.0',
'Msxml2.ServerXMLHTTP',
'Microsoft.ServerXMLHTTP',
'Msxml2.XMLHTTP.6.0',
'Msxml2.XMLHTTP.5.0',
'Msxml2.XMLHTTP.4.0',
'Msxml2.XMLHTTP.3.0',
'Msxml2.XMLHTTP',
'Microsoft.XMLHTTP']);
};
/**
* 簡易パーサー
* 開始文字列と終了文字列に挟まれた文字列を返す。
* @param {string} html - 入力文字列
* @param {string} start - 開始文字列
* @param {string} end - 終了文字列
* @return {string[]} 検索文字列の配列
*/
_this.finds = function HTTPUtility_finds(html, start, end) {
var results = [];
var index = 0;
while (true) {
var s = html.indexOf(start, index);
if (s != -1) {
var e = html.indexOf(end, s + start.length);
if (e != -1) {
results.push(html.substring(s + start.length, e));
index = e + end.length;
continue;
}
}
break;
}
return results;
};
/**
* html文字列からHTMLタグを削除
* @param {string} html - 入力文字列
* @return {string} タグ削除済み文字列
*/
_this.innerText = function HTTPUtility_innerText(html) {
return html.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g,'');
};
/**
* 親要素のタグを探す
* @param {Element} element - 要素
* @param {string} tag - 探すタグ
* @return {Element} 親要素
*/
_this.getParentElement = function HTTPUtility_getParentElement(element, tag) {
return _getParentElement(element, tag);
};
/**
* パラメータ作成
* @param {Element} form - 要素
* @param {Element} submit - 要素
* @return {Object} パラメータ
*/
_this.createParams = function HTTPUtility_createParams(form, submit) {
var params = {};
var inputs = form.getElementsByTagName('input');
for (var i=0; i<inputs.length; i++) {
if ((submit !== void 0) && (inputs[i].type == 'submit') && (inputs[i].name != submit)) {
continue;
}
params[inputs[i].name] = inputs[i].value;
}
return params;
// 補足:クリックしたsubmitボタンの値のみ送付する。
// 複数submitボタンがある場合、クリックしたボタンのみ送付すべき。
};
/**
* パラメータ文字列作成
* @param {Object} params - パラメータ
* @return {string} パラメータ文字列
*/
_this.escapeParams = function HTTPUtility_escapeParams(params) {
var param = null;
if (params) {
param = '';
for (var key in params) {
if (params.hasOwnProperty(key)) {
if (param.length > 0) { param += '&'; }
param += encodeURIComponent(key).replace(/%20/g, '+')
+ '=' + encodeURIComponent(params[key]).replace(/%20/g, '+');
}
}
}
return param;
};
function HTTPUtility__standbyUnsync(xhr, state, opt) {
var timeout = (state === _this.READYSTATE_COMPLETE)? opt.receiveTimeout: opt.sendTimeout;
var interval = (state === _this.READYSTATE_COMPLETE)? opt.receiveInterval: opt.sendInterval;
var count = Math.floor(timeout / interval);
var delay = timeout - (count * interval);
WScript.Sleep(delay);
for (var c=0; (timeout==0) || (c<count); c++) {
if (xhr.readyState >= state) { break; }
WScript.Sleep(interval);
}
return (xhr.readyState >= state);
}
function HTTPUtility__standbySync(xhr, state, opt) {
return (xhr.readyState >= state);
}
/**
* HTTP要求
* 注意: option.unsync=trueを指定しても、本関数としては、同期処理を行う。
* @param {string} method - メソッド
* @param {string} url - URL
* @param {Object} option - オプション
* @return {Object} 結果
*/
_this.httpMethod = function HTTPUtility_httpMethod(method, url, option) {
// オプションの初期値
if (!option)
option = {};
if (!option.headers)
option.headers = {};
if (option.sendTimeout === void 0)
option.sendTimeout = 30*1000;
if (option.sendInterval === void 0)
option.sendInterval = 50;
if (option.receiveTimeout === void 0)
option.receiveTimeout = 30*1000;
if (option.receiveInterval === void 0)
option.receiveInterval = 100;
// キャッシュ無効 304対策
if (option.headers['Pragma'] === void 0)
option.headers['Pragma'] = 'no-cache';
if (option.headers['Cache-Control'] === void 0)
option.headers['Cache-Control'] = 'no-cache';
if (option.headers['If-Modified-Since'] === void 0)
option.headers['If-Modified-Since'] = 'Thu, 01 Jun 1970 00:00:00 GMT';
// GET/POST用処理
if (option.content === void 0)
option.content = null;
else if (option.headers['Content-Type'] === void 0)
option.headers['Content-Type'] = 'application/x-www-form-urlencoded';
// 待機(既定状態まで待つ)
if (option.unsync === void 0)
option.unsync = false;
if (option.standby === void 0)
option.standby = (option.unsync)? HTTPUtility__standbyUnsync: HTTPUtility__standbySync;
// 処理本体
var ret = null,
xhr;
try {
xhr = HTTPUtility_createXMLHttpRequest();
xhr.open(method, url, option.unsync);
// ヘッダを設定
for (var key in option.headers) {
if (option.headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, option.headers[key]);
}
}
// 送信
xhr.send(option.content);
// 受信待ち
if (option.standby(xhr, _this.READYSTATE_INTERACTIVE, option) === false) {
} else if (option.standby(xhr, _this.READYSTATE_COMPLETE, option) === false) {
} else if (option.unsync) {
// 追加待機(完了直後に処理すると、エラーとなることがある)
WScript.Sleep(500);
}
// 戻り値作成
// ヘッダ作成
ret = {'status':xhr.status,'statusText':xhr.statusText,headers:{}};
var headers = xhr.getAllResponseHeaders().replace(/\r\n?/g,'\n').split('\n');
for (var h=0; h<headers.length; h++) {
var m = headers[h].split(': ');
if (m.length == 2) {
ret.headers[m[0]] = m[1];
}
}
// 受信データ作成
if (ret.headers['Content-Type'] && ret.headers['Content-Type'].indexOf('text') == 0) {
ret.responseText = xhr.responseText;
} else {
ret.responseBody = xhr.responseBody;
}
} catch (e) {
// 要求キャンセル
try {
xhr.abort();
} catch (e2) {}
// エラー処理
ret = {'status':-1};
if (ErrorUtility != null) {
if (!e.stackframes) {
ErrorUtility.captureStackTrace(e);
}
ret.error = ErrorUtility.stack(e);
} else {
ret.error = _stack(null, _errormessage(e), ' at ');
}
}
xhr = null; // 開放(10000個のハンドラの取り尽くしを回避)
return ret;
// {status: number, statusText, string, headers: {header: string, ..},
// responseText, string, responseBody: Blob[], error: string}
};
/**
* GET通信用
* @param {string} url - URL
* @param {Object} params - パラメータ
* @param {Object} option - オプション
* @return {Object} データ
*/
_this.httpGET = function HTTPUtility_httpGET(url, params, option) {
if (option == null)
option = {};
if (option['User-Agent'] === void 0)
option['User-Agent'] = _this.UserAgent;
if (params)
url += '?' + _this.escapeParams(params);
return _this.httpMethod(_this.GET, url, option);
};
/**
* POST通信用
* @param {string} url - URL
* @param {Object} params - パラメータ
* @param {Object} option - オプション
* @return {Object} 結果
*/
_this.httpPOST = function HTTPUtility_httpPOST(url, params, option) {
if (option == null)
option = {};
if (option['User-Agent'] === void 0)
option['User-Agent'] = _this.UserAgent;
if (option['content'] === void 0)
option['content'] = _this.escapeParams(params);
return _this.httpMethod(_this.POST, url, option);
};
/**
* HTMLドキュメントを取得する
* 補足:IE7程度のjsで動作するため、querySelectorが使えない。
* Google検索するとCookieのダイアログがでるため、注意。
* @param {string} text - HTMLデータ
* @return {ActiveXObject('htmlfile')} html
*/
_this.html = function HTTPUtility_html(text) {
// IE11互換
//text = text.replace(/(<head.*>)/i, '$1<meta http-equiv="x-ua-compatible" content="IE=11"/>');
var doc = new ActiveXObject('htmlfile');
doc.write(text);
if (!doc.querySelectorAll) {
// see https://github.com/mtsyganov/queryselector-polyfill/blob/master/index.js
doc.querySelectorAll =
function querySelectorAllPolyfill(r, c, i, j, a) {
var d=doc,
s=d.createStyleSheet();
a = d.all;
c = [];
r = r.replace(/\[for\b/gi, '[htmlFor').split(',');
for (i = r.length; i--;) {
s.addRule(r[i], 'k:v');
for (j = a.length; j--;) {
a[j].currentStyle.k && c.push(a[j]);
}
s.removeRule(0);
}
return c.reverse(); // 逆順で取得するため、リバース
};
}
if (!doc.querySelector) {
doc.querySelector =
function querySelectorPolyfill(selectors) {
var elements = this.querySelectorAll(selectors);
return (elements.length) ? elements[0]: null;
};
}
if (!doc.getElementsByClassName) {
doc.getElementsByClassName =
function getElementsByClassNamePolyfill(classNames) {
classNames = String(classNames).replace(/^|\s+/g, '.');
return this.querySelectorAll(classNames);
};
}
return doc;
};
/**
* XMLドキュメントを取得する
* @param {string} text - HTMLデータ
* @return {ActiveXObject('DOMDocument')} xml
*/
_this.xml = function HTTPUtility_xml(text) {
var xml = _Process_createDOMDocument();
xml.loadXML(text);
return xml;
};
// ファイル取得
function HTTPUtility_httpDocument(type, url, method, params, option) {
method = (method === void 0)? _this.GET: method;
var ret = null;
if (method === _this.GET) { ret = _this.httpGET(url, params, option); }
else if (method === _this.POST) { ret = _this.httpPOST(url, params, option); }
var doc = null;
if (ret && ret.responseText) {
switch (type) {
case 'TEXT': doc = ret.responseText; break;
case 'HTML': doc = _this.html(ret.responseText); break;
case 'XML': doc = _this.xml(ret.responseText); break;
default: break;
}
}
ret = null;
return doc;
};
/**
* TEXTファイルの取得
* @param {string} url - URL
* @param {string} method - メソッド
* @param {Object} params - パラメータ
* @param {Object} option - オプション
* @return {ActiveXObject('htmlfile')} 結果
*/
_this.httpTEXT = function HTTPUtility_httpTEXT(url, method, params, option) {
return HTTPUtility_httpDocument('TEXT', url, method, params, option);
};
/**
* HTMLファイルの取得
* @param {string} url - URL
* @param {string} method - メソッド
* @param {Object} params - パラメータ
* @param {Object} option - オプション
* @return {ActiveXObject('htmlfile')} 結果
*/
_this.httpHTML = function HTTPUtility_httpHTML(url, method, params, option) {
return HTTPUtility_httpDocument('HTML', url, method, params, option);
};
/**
* XMLファイルの取得
* @param {string} url - URL
* @param {string} method - メソッド
* @param {Object} params - パラメータ
* @param {Object} option - オプション
* @return {ActiveXObject('DOMDocument')} xml
*/
_this.httpXML = function HTTPUtility_httpXML(url, method, params, option) {
return HTTPUtility_httpDocument('XML', url, method, params, option);
};
return _this;
});
変更履歴
更新日 | 内容 |
---|---|
2018/05/27 | v1 - add - 初版 |
2019/05/14 | v2 - update - テキスト編集処理を追加 |