聚BT浏览器扩展提供了强大的二次开发功能,用户只需要懂简单的CSS、Javascript基础就可以增加自定义网站,轻松打造自己的个性化搜索引擎。
此系列文章目的是帮助有CSS、Javascript基础的同学熟悉聚BT浏览器扩展的开发接口。对没有CSS、Javascript经验的同学也不用担心,可以在聚BT论坛的二次开发板块提出需求,社区伙伴会帮助你。
searcher vs. parser
在开始学习前,请先看一下《聚BT浏览器扩展技术架构》,大致了解一下聚BT浏览器扩展的系统架构。
对自定义网站,只需要记住:要自定义一个网站,主要涉及两部分:searcher、parser。
searcher的作用是调用对应网站的搜索功能,以得到搜索结果。
parser的作用是对搜索结果进行解析,将结果放入聚BT浏览器扩展搜索结果页。
这篇文章中,HTTP请求类型,指的就是searcher的请求类型。
searcher的HTTP请求类型
根据HTTP标准,HTTP请求共有8种请求类型,其中:
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
大部分网站请求,都属于GET、POST两类。其他HTTP请求类型在RESTFUL API中使用较多,在日常网页浏览很少使用。
因此聚BT的HTTP请求主要使用了GET、POST两大类,在聚BT目前支持的200多个网站中,90%的网站确实也能用GET请求搞定,10%网站为POST。但在实际应用中,很多网站的GET/POST请求相对于标准请求,有一些特殊的地方。
例如:
1、网站使用了AJAX请求,实际的搜索结果是异步加载,例如腾讯音乐、虾米等。
2、网站对HTTP 请求做了加密、特殊编码处理,例如music.163.com。
3、网站涉及包含了iframe,搜索结果在iframe中装载
这几种情况理论上都可以通过GET、POST方式搞定,但涉及抓包、加密协议分析等等工作,很难标准化,后期维护也极为麻烦。
因此在聚BT浏览器扩展在用户自定义界面中,HTTP请求类型细分分为:GET,GET_CUSTOM,POST,NEWTAB,NEWTAB_IFRAME 5类。
GET-缺省(GET):标准的GET请求,采用系统缺省seacher。
GET-自定义(GET_CUSTOM):用户自定义GET请求代码。主要应用在用户自定义网站时候适用。
新标签页(NEWTAB):以指定的搜索请求URL为地址,打开新标签页进行搜索。
新标签页-iframe(NEWTAB_IFRAME):以指定的搜索请求URL为地址,打开新标签页搜索。与“新标签页(NEWTAB)”相比,主要适用于网站有iframe的情况。
POST:适用于搜索请求以POST进行的网站。
备注:以上类似“GET-缺省(GET)“形式的写法,”GET-缺省”指用户在自定义界面中所见到的文字,而”(GET)”中的”GET”是系统内部代码,以下文章沿用此种说法,或者直接用系统内部代码指代。
GET-缺省(GET)
GET类型请求,适用于大部分网站。
此类网站,URL地址中包含了搜索关键词,请求URL地址后,网站同步返回完整的搜索结果,也即网站不是AJAX异步装载的。
以动漫花园为例,搜索“海贼王”,对应的搜索请求url为:https://share.dmhy.org/topics/list?keyword=%E6%B5%B7%E8%B4%BC%E7%8E%8B
在自定义网站的新增/修改界面,网站搜索地址填写为:https://share.dmhy.org/topics/list?keyword=searchkeyword
这里searchkeyword为搜索关键词的占位符,指代用户输入的搜索关键词。
对GET类型的网站,网站搜索地址 中必须包含searchkeyword关键词。
采用GET类型,对应网站的searcher采用系统缺省内置函数:
1 2 3 4 5 6 7 8 9 | async function defaultSearcher(url, keyword) { try { let response = await httpGet(url); return response.body; } catch (err) { console.info( "searcher.js err: " + JSON.stringify(err, Object.getOwnPropertyNames(err), 2)); return null ; } } |
需要强调一下,如果在自定义界面的”网站搜索代码“字段,不需要输入函数名,只需要输入函数体部分,也即:
1 2 3 4 5 6 7 | try { let response = await httpGet(url); return response.body; } catch (err) { console.info( "searcher.js err: " + JSON.stringify(err, Object.getOwnPropertyNames(err), 2)); return null ; } |
采用GET类型的网站,只需要自定义parser部分。
以动漫花园为例,一个标准的Parser函数示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function dmhyParser(content, url, source, keyword) { let myDocument = documentFactory(content); const elements = myDocument.querySelectorAll( "tr td.title a" ); let hrefs = []; for (let element of elements) { let href = element.getAttribute( "href" ); if (href) { href = relativeUrlToAbsolute(href, url); let text = element.innerText; let desc = keyword; if (href && text) { hrefs.push({ link: href, linkText: text, desc: desc, source: source, keyword: keyword, url: url, type: "acg" }); } } } return hrefs; } |
再次强调一下:这是系统缺省内置函数定义,如果在自定义界面的”网站搜索代码“字段,不需要输入函数名,只需要输入函数体部分,也即:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | let myDocument = documentFactory(content); const elements = myDocument.querySelectorAll( "tr td.title a" ); let hrefs = []; for (let element of elements) { let href = element.getAttribute( "href" ); if (href) { href = relativeUrlToAbsolute(href, url); let text = element.innerText; let desc = keyword; if (href && text) { hrefs.push({ link: href, linkText: text, desc: desc, source: source, keyword: keyword, url: url, type: "acg" }); } } } return hrefs; |
GET-自定义(GET_CUSTOM)
对一些网站,网站请求类型为GET类型,但系统缺省的GET类型满足不了需要,此时可以使用GET-自定义(GET_CUSTOM)类型。
GET_CUSTOM类型与GET类型的唯一差异在于,searcher不采用系统缺省内置的defaultSearcher,而采用自定义。
实际上,GET类型是GET_CUSTOM的一种特殊情况。对所有的GET请求类型的网站,都可以指定为GET_CUSTOM类型,对应的searcher为系统缺省,也即在新增网站的”网站搜索代码“部分输入:
1 2 3 4 5 6 7 | try { let response = await httpGet(url); return response.body; } catch (err) { console.info( "searcher.js err: " + JSON.stringify(err, Object.getOwnPropertyNames(err), 2)); return null ; } |
使用GET_CUSTOM的典型例子:对URL的关键词编码不是UTF-8,而是GBK的编码。
例如 阳光影视 的请求类型是GET,系统缺省的httpGet的编码为UTF-8,此时用系统缺省内置的defaultSearcher会编码错误,导致无搜索结果。此时,采用GET_CUSTOM对应的输入代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | try { let utf8Keyword = encodeURIComponent(keyword); let gbkKeyword = GBK.URI.encodeURI(keyword); url = url.replace(utf8Keyword, gbkKeyword); //console.debug("searcher.js ygdy8Searcher url :" + url + ",keyword is:" + keyword + ",gbkKeyword is:" + gbkKeyword + ",utf8Keyword is:" + utf8Keyword); let response = await httpGet(url, "arraybuffer" ); let dataView = new DataView(response.body); let decoder = new TextDecoder( "GBK" ); let gbkResponse = decoder.decode(dataView); //console.debug("searcher.js er httpGet response :" + gbkResponse); return gbkResponse; } catch (err) { console.info( "searcher.js err: " + JSON.stringify(err, Object.getOwnPropertyNames(err), 2)); return null ; } |
这一讲先到这儿,下一讲继续讲解网站请求类型POST、NEWTAB、NEWTAB_IFRAME。