在前面两篇《聚BT浏览器扩展自定义网站从入门到精通1-HTTP请求类型GET、GET_CUSTOM》、《聚BT浏览器扩展自定义网站从入门到精通2-HTTP请求类型NEWTAB、NEWTAB_IFRAME》讲解了聚BT浏览器扩展 HTTP请求类的GET、GET_CUSTOM以及NEWTAB、NEWTAB_IFRAME。这篇继续讲解POST。
POST类型分为两大类:普通POST请求、NEWTAB/NEWTAB_IFRAME的请求。
GET/GET_CUSTOM和NEWTAB/NEWTAB_IFRAME (实际上前面讲的NEWTAB是GET类型的新开标签页),系统都有缺省的searcher或parser,但对于POST类型,searcher和parser都需要自定义。
普通POST请求
普通POST请求,不需要新开标签页,也是最常用的POST类型。
普通POST的典型例子:好恐怖 https://www.hkb123.com 。值得推荐一下,好恐怖电影站质量不错,尤其是很多冷门篇此站都有收集。
POST类型的请求,在查询时候,浏览器地址栏不会带查询关键词信息,因此在自定义站点页面,网站搜索地址可以只填写官网首页:https://www.hkb123.com ,不需要带searchkeyword关键词。
在好恐怖首页:https://www.hkb123.com,输入“爱与怪物”查询,大致的请求交互流程为:
1、实际请求URL(Request URL)为:https://s.haokongbu.net/e/search,请求类型(Request Method)为:POST
POST的Form表单参数为:show=title%2Cftitle%2Cactor&keyboard=%E7%88%B1%E4%B8%8E%E6%80%AA%E7%89%A9
2、服务器返回302重定向请求,重定向地址为 https://s.haokongbu.net/e/search/result/?searchid=582944 ,请求类型为GET
地址栏变为为:https://s.haokongbu.net/e/search/result/?searchid=582944 ,搜索结果返回并展示。
对于POST类型的请求,每一个网站的searcher都不相同,只能一个一个网站自定义,例如好恐怖的searcher为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | async function hkb123Searcher(url, keyword) { try { //函数输入参数 url为: https://s.hkb123.com/e/search,由系统带入,当然也可以直接在自定义函数中写死 let url1 = url.replace( "www" , "s" ) + "/e/search/" ; keyword = encodeURIComponent(keyword); let body = "show=title%2Cftitle%2Cactor&keyboard=" + keyword; //console.debug("searcher.js hkb123Searcher body :" + body + ",keyword is:" + keyword); let response1 = await httpPost(url1, "application/x-www-form-urlencoded" , body); //console.debug("searcher.js hkb123Searcher response1 :" + JSON.stringify(response1)); //console.debug("searcher.js hkb123Searcher response1 keys is :" + Object.keys(response1)); if (response1 && Object.keys(response1).length == 2) { return response1.body; } return null ; } catch (err) { console.info( "searcher.js err: " + JSON.stringify(err, Object.getOwnPropertyNames(err), 2)); return null ; } } |
再次强调:这是系统内置函数,在自定义界面的”网站搜索代码“字段,不需要输入函数名,只需要输入函数体部分。
对应的系统内置parser 为hkb123Parser
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function hkb123Parser(content, url, source, keyword) { let myDocument = documentFactory(content); const elements = myDocument.querySelectorAll( "div.channel-content ul li p 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; //console.debug("parser.js hkb123Parser href is: " + href + ", text is:" + text); if (href && text) { hrefs.push({ link: href, linkText: text, desc: desc, source: source, keyword: keyword, url: url, type: "movie" }); } } } return hrefs; } |
再次强调:这是系统内置函数,在自定义界面的”网站解析代码“字段,不需要输入函数名,只需要输入函数体部分。
NEWTAB/NEWTAB_IFRAME 的POST
以上举的好恐怖是普通的POST,但假如页面请求涉及复杂的交互逻辑,例如有ajax请求或请求报文有加密请求,此时,为降低抓包分析难度,可以直接使用NEWTAB/NEWTAB_IFRAME 配合自定义searcher的方案。
典型例子:知网 https://www.cnki.net
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function cnkiSearcher(url, keyword) { //console.debug("parserNewTab.js cnkiSearcher keyword is: " + keyword); if (document.getElementById( "txt_search" )) { let element = document.getElementById( "txt_search" ); element.value = keyword; var handler = setInterval( function () { element = document.getElementById( "txt_search" ); //console.debug("parserNewTab.js cnkiSearcher value1 is: " + element.value); if (element.value == keyword) { //console.debug("parserNewTab.js cnkiSearcher value2 is: " + keyword); clearInterval(handler); document.querySelector( "input.search-btn" ).click(); setTimeout( function () {}, 1000); } else { cnkiSearcher(keyword); } }, 1000); } else { total++; if (total < 7) { cnkiSearcher(url, keyword); } } } |
代码看起来貌似有点复杂,核心思路如下:
1、在采用 NEWTAB_IFRAME 模式打开标签页
2、等待页面装载完成
通过document.getElementById(“txt_search”) 轮询页面txt_search元素
如果未获取到,则递归调用cnkiSearcher自己。
重复7次未获取到,则退出
3、将搜索框txt_search的值设置为搜索关键词
4、模拟点击 input.search-btn完成搜索。
NEWTAB类型的POST极少使用,如果不喜欢新开标签页,也可以通过分析请求报文和相关的JavaScript函数,用自定义普通POST实现。
系统缺省内置的parser为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | function cnkiParser(url, source, keyword) { const elements = document.querySelectorAll( "td.name a" ); let hrefs = []; for (let element of elements) { let href = element.getAttribute( "href" ); let match = href.match(/FileName=(.*)&DbName=(.*)&DbCode=(.*)&/); if (match) { let filename = match[1]; let dbname = match[2]; let dbcode = match[3]; href = "https://kns.cnki.net/kcms/detail/detail.aspx?filename=" + filename + "&dbname=" + dbname + "&dbcode=" + dbcode; let text = element.innerText; let desc = keyword; console.debug( "parser.js mikuclubParser href is: " + href + ", text is:" + text); if (href && text) { hrefs.push({ link: href, linkText: text, desc: desc, source: source, keyword: keyword, url: url, type: "scholar" }); } } } return hrefs; } |
以上为系统缺省内置的parser,如果在自定义界面,输入如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | let myDocument = documentFactory(content); const elements = myDocument.querySelectorAll( "td.name a" ); let hrefs = []; for (let element of elements) { let href = element.getAttribute( "href" ); let match = href.match(/FileName=(.*)&DbName=(.*)&DbCode=(.*)&/); if (match) { let filename = match[1]; let dbname = match[2]; let dbcode = match[3]; href = "https://kns.cnki.net/kcms/detail/detail.aspx?filename=" + filename + "&dbname=" + dbname + "&dbcode=" + dbcode; let text = element.innerText; let desc = keyword; console.debug( "parser.js mikuclubParser href is: " + href + ", text is:" + text); if (href && text) { hrefs.push({ link: href, linkText: text, desc: desc, source: source, keyword: keyword, url: url, type: "scholar" }); } } } return hrefs; |
主要差异:
1、在自定义界面需要对搜索结果使用documentFactory构建document
1 2 | let myDocument = documentFactory(content); const elements = myDocument.querySelectorAll( "td.name a" ); |
2、正如反复强调的:不需要输入函数名,只需要输入函数体部分
由此总算介绍完了聚BT浏览器扩展的几种请求类型,下一篇针对系统内置的几个函数重点介绍,包括documentFactory, httpGet,httpPost等,以更好理解自定义searcher和parser的逻辑。