いろんなサイトから ISBN を抽出するグリモンのテスト
2008/05/22 追記
via id:hetappiさんのISBNのグリモンを少し弄った。 - tyoro.exe
tyoro さんに指摘してもらって wedata から json 形式で取得したときの Content-Type を text/javascript から application/json に修正しました。ありがとです。
このまえ少し止まってた時に変わったのかな…。
wedata にとりあえず作って1か月ほど放置していた Item - データベース: ISBN Scraper - wedata 。CrossBookSearch のソース中にだーっと書いてあった ISBN を抽出する XPath を Wiki で管理することで、編集を容易にし他のスクリプトなどでも使えるようになります。きっと。
とりあえずテストグリモンでは Document もしくは http な URL 文字列から ISBN をゲットできるようにした。
var sc = new ISBNScraper; sc.scrape(document, function(isbn) { if (isbn) console.dir(isbn); }); sc.scrape('http://www.oreilly.co.jp/books/9784873113654/', function(isbn) { if (isbn) console.dir(isbn); });
isbn10 "4873113636" isbn13 "9784873113630" isbn10 "" isbn13 "9784873113654"
まだ wedata には Amazon とオライリーしかないけど、http://coderepos.org/share/browser/lang/javascript/userscripts/crossbooksearch.user.js? にいっぱいあるので誰か(ry。
// ==UserScript== // @name TestISBNScraper // @namespace http://d.hatena.ne.jp/hetappi // @include * // ==/UserScript== var sc = new ISBNScraper; sc.scrape(document, function(isbn) { if (isbn) console.dir(isbn); }); sc.scrape('http://www.oreilly.co.jp/books/9784873113654/', function(isbn) { if (isbn) console.dir(isbn); }); function ISBNScraper() { return { _getSiteInfo: function(callback) { var cache = eval(GM_getValue('cache')); if (cache && cache.expire > new Date().getTime()) { callback(cache.siteinfo); } else { new GMUtil().get('http://wedata.net/databases/isbn%20scraper/items.json', function(resp) { if (resp && resp.response.body.type == 'json') { var items = resp.response.body.json; var cacheNew = { siteinfo: items, expire: new Date(new Date().getTime() + 24 * 60 * 60 * 1000) }; GM_setValue('cache', uneval(cacheNew)); callback(items); } else { callback(cache ? cache.siteinfo : null); } }); } }, _getIsbn: function(doc, url, items) { for (var i = 0, m = items.length; i < m; ++i) { if (!new RegExp(items[i].data.url).test(url)) continue; var isbn = {}; if (items[i].data.isbn10) isbn.isbn10 = doc.evaluate( items[i].data.isbn10, doc, null, XPathResult.STRING_TYPE, null).stringValue; if (items[i].data.isbn13) isbn.isbn13 = doc.evaluate( items[i].data.isbn13, doc, null, XPathResult.STRING_TYPE, null).stringValue; return isbn; } return null; }, scrape: function(src, callback) { if (!src) { callback(null); return; } var self = this; self._getSiteInfo(function(items) { if (!items) { callback(null); } else if (typeof src == 'string' && new RegExp('^https?://').test(src)) { new GMUtil().get(src, function(resp) { callback( resp ? self._getIsbn(resp.response.body.document, src, items) : null); }); } else if (typeof src == 'object' && new GMUtil().instanceof(src, Document)) { callback(self._getIsbn(src, src.location.href, items)); } else { callback(null); } }); } }; }
function GMUtil() { return arguments.callee._self || (arguments.callee._self = { instanceof: function(obj, type) { // todo: return obj.wrappedJSObject instanceof type.wrappedJSObject; }, get: function(url, callback) { var self = this; var opts = { method: 'get', url: url, onerror: function(resp) { callback(null); }, onload: function(resp) { callback(self.parseXmlHttpResponse(resp)); } }; GM_xmlhttpRequest(opts); }, parseXmlHttpResponse: function(resp) { if (!resp) return null; var obj = { readyState: resp.readyState, status: resp.status, statusText: resp.statusText, response: { body: { text: resp.responseText } } }; obj.response.headers = (function(headers) { var obj = {}; headers.split('\n').forEach(function(header) { var pair = header.split(': '); if (pair.length != 2) return; console.log(pair[0]); console.log(pair[1]); obj[pair[0]] = pair[1]; }); return obj; })(resp.responseHeaders); if (!obj.response.headers['Content-Type']) return obj; var contentType = obj.response.headers['Content-Type'].split('; '); if (contentType[0] == 'application/json') { obj.response.body.json = eval(resp.responseText); obj.response.body.type = 'json'; } else if (contentType[0] == 'text/html') { // todo: var r = document.createRange(); r.selectNode(document.documentElement); var d = document.implementation.createDocument(null, 'html', null); d.documentElement.appendChild(r.createContextualFragment(resp.responseText)); obj.response.body.document = d; obj.response.body.type = 'html'; } else if (contentType[0] == 'text/xml' || contentType[0] == 'application/xml') { obj.response.body.document = new DOMParser().parseFromString(resp.responseText, contentType[0]); obj.response.body.type = 'xml'; } else { obj.response.body.type = 'unknown'; } return obj; } }); }