remove the jump link in BAIDU

去除百度搜索跳转链接

当前为 2015-10-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name remove the jump link in BAIDU
  3. // @author burningall
  4. // @description 去除百度搜索跳转链接
  5. // @version 2015.10.23
  6. // @include *www.baidu.com*
  7. // @grant GM_xmlhttpRequest
  8. // @run-at document-start
  9. // @compatible chrome 完美运行
  10. // @compatible firefox 完美运行
  11. // @license The MIT License (MIT); http://opensource.org/licenses/MIT
  12. // @supportURL http://www.burningall.com
  13. // @contributionURL troy450409405@gmail.com|alipay.com
  14. // @namespace https://greasyfork.org/zh-CN/users/3400-axetroy
  15. // ==/UserScript==
  16. (function(win,doc,undefined) {
  17. //=====配置参数======
  18. var config = {
  19. // 需要跳转的链接
  20. macthRules: 'a[href*="www.baidu.com/link?url"]:not([transcoding]):not([transcoded]):not([transcodedAll]):not(.m)',
  21. // 请求失败,需要再次请求的链接
  22. reloadRules: 'a[transcoded*="false"]',
  23. // 是否正在请求全部,不要修改
  24. transcodingAll:false,
  25. };
  26. //======事件对象=======
  27. function handler(obj) {
  28. return new Event(obj);
  29. }
  30. function Event(obj) {
  31. this.element = obj;
  32. return this;
  33. }
  34. Event.prototype.addEvent = function(type, fn) {
  35. var obj = this.element,ev;
  36. return obj.addEventListener ?
  37. obj.addEventListener(type, function(e) {
  38. ev = win.event ? win.event : (e ? e : null);
  39. ev.target = ev.target || ev.srcElement;
  40. if (fn.call(obj, ev) === false) {
  41. ev.cancelBubble = true;
  42. ev.preventDefault();
  43. }
  44. }, false) :
  45. obj.attachEvent('on' + type, function(e) {
  46. ev = win.event ? win.event : (e ? e : null);
  47. ev.target = ev.target || ev.srcElement;
  48. if (fn.call(obj, ev) === false) {
  49. ev.cancelBubble = true;
  50. return false;
  51. }
  52. });
  53. };
  54. // 事件绑定
  55. Event.prototype.bind = function(type, fn) {
  56. var obj = this.element;
  57. // 传入json
  58. if (arguments.length == 1) {
  59. for (var attr in type) {
  60. this.addEvent(attr, type[attr]);
  61. }
  62. }
  63. // 传入2个参数
  64. else if (arguments.length == 2) {
  65. var events = type.split(' '),j = 0;
  66. while (j < events.length) {
  67. this.addEvent(events[j], fn);
  68. j++;
  69. }
  70. }
  71. return this;
  72. };
  73. // 监听
  74. Event.prototype.ob = function(config, fn) {
  75. var target = this.element,
  76. MutationObserver = win.MutationObserver || win.WebKitMutationObserver || win.MozMutationObserver,
  77. observer = new MutationObserver(function(mutations) {
  78. mutations.forEach(function(mutation) {
  79. fn.call(target);
  80. });
  81. });
  82. observer.observe(target, config);
  83. return this;
  84. };
  85. //======公共函数=======
  86. // 获取DOM节点的文本
  87. function getText(obj){
  88. return obj.innerText ? obj.innerText : obj.textContent;
  89. }
  90. // AJAX
  91. function ajax(url,json,a){
  92. // this>>>a
  93. a = a ? a : win;
  94. if( json.beforeFn ){
  95. // 如果返回值为false,则不请求
  96. if( json.beforeFn.call(a,url)===false ) return;//this>>>a
  97. }
  98. GM_xmlhttpRequest({
  99. method: "GET",
  100. url: url,
  101. onreadystatechange: function(response) {
  102. if (response.readyState == 4) {
  103. var status = response.status + '';
  104. if (status.charAt(0) == "4" || status.charAt(0) == "5") { //4XX,5XX错误
  105. if( json.failFn ) json.failFn.call(a,status,url);//this>>>a
  106. } else {
  107. if( json.successFn ) json.successFn.call(a,response.responseText,url);//this>>>a
  108. }
  109. }
  110. }
  111. });
  112. }
  113. //======主体对象=======
  114. function init(agm) {
  115. return new Init(agm);
  116. }
  117. // 初始化
  118. function Init(agm) {
  119. // 不传参数则返回
  120. if (!agm) return this;
  121. // 获取到要跳转的A链接
  122. var jumpLinks = doc.querySelectorAll(agm);
  123. // 在可视区域内的跳转链接
  124. this.inViewPort = [];
  125. for (var j = 0,leng = jumpLinks.length; j < leng; j++) {
  126. this.a = jumpLinks[j];
  127. // 在可视区域内
  128. if ( this.visible() ) this.inViewPort.push(jumpLinks[j]);
  129. }
  130. // 删除百度搜索追踪
  131. var trackDiv = doc.querySelectorAll('#content_left *[data-click]');
  132. for( var i=0,len=trackDiv.length;i<len;i++ ){
  133. trackDiv[i].removeAttribute('data-click');
  134. }
  135. return this;
  136. }
  137. // 全局请求
  138. Init.prototype.all = function(callBack){
  139. // 搜索框的关键字
  140. var searchWord = doc.getElementById('kw').value,
  141. // 构建新的请求url,把tn=baidulocal替换成tn=baidulocal
  142. url = win.top.location.href.replace('https', 'http').replace(/(\&)(tn=\w+)(\&)/img, '$1' + 'tn=baidulocal' + '$3').replace(/(\&)(wd=\w+)(\&)/img, '$1' + 'wd='+ searchWord + '$3');
  143. ajax(url,{
  144. // 请求发出前
  145. "beforeFn":function(url){
  146. config.transcodingAll=true;
  147. },
  148. // 请求失败
  149. "failFn":function(status,url){
  150. this.setAttribute("transcoded","false");
  151. console.log( '请求' + url + '结果:' + status );
  152. },
  153. // 请求成功
  154. "successFn":function(response,url){
  155. var html = doc.createElement('html');
  156. // 讨厌的http百度图片
  157. html.innerHTML = response.replace(/http\:\/\/(.*)\.gif/img, "http://wwwbaidu.com");
  158. // 请求得到的所有A标签
  159. var requireAtag = html.querySelectorAll('.f>a'),
  160. // 存放信息的哈希表
  161. info = {};//href:innerText
  162. // 存放href和innerText到info中
  163. for (var i = 0,length = requireAtag.length; i < length; i++) {
  164. if ( info[requireAtag[i].href] === undefined) info[ requireAtag[i].href ] = getText( requireAtag[i] );
  165. }
  166. // 当前页的需要跳转的A标签
  167. var currentAtag = doc.querySelectorAll('.t>a:not(.OP_LOG_LINK):not([transcoded]):not([transcodedAll])');
  168. // 循环匹配,替换url
  169. for (var trueLink in info) {
  170. for (var j = 0,len = currentAtag.length; j < len; j++) {
  171. // 如果符合条件
  172. if ( info[trueLink].replace(/\s*/img, '') == getText( currentAtag[j] ).replace(/\s*/img,'') ) {
  173. currentAtag[j].href = trueLink;
  174. currentAtag[j].setAttribute('transcodedAll','true');
  175. currentAtag[j].setAttribute('transcoded','true');
  176. // currentAtag[j].style.background = 'red';
  177. }
  178. }
  179. }
  180. config.transcodingAll=false;
  181. // 回调函数
  182. if(callBack) callBack();
  183. }
  184. });
  185. };
  186. // 逐一请求
  187. Init.prototype.onebyone = function(){
  188. var leng = this.inViewPort.length;
  189. // 如果可视区域内不存在跳转链接
  190. if (leng <= 0) return;
  191. // 对在可视区域内的跳转链接,进行循环逐一请求
  192. for (var i = 0; i < leng; i++) {
  193. this.a = this.inViewPort[i];
  194. // 如果已经全局请求过了
  195. if( this.a.getAttribute("transcodedAll") ) continue;
  196. // url构建:url必须要加上"&wd=&eqid=0",否则出错
  197. ajax(this.a.href.replace("http", "https") + "&wd=&eqid=0",{
  198. // 请求前
  199. "beforeFn":function(url){
  200. this.setAttribute("transcoding", "true");
  201. },
  202. // 请求失败
  203. "failFn":function(status,url){
  204. this.setAttribute("transcoded", "false");
  205. console.log( '请求' + url + '结果:' + status );
  206. },
  207. // 请求成功
  208. "successFn":function(responseStr,url){
  209. var trueLink = responseStr.match(/\(\"\S+\"\)/img)[0].replace(/^[\(\"]*|[\)\"]*$/img,"");
  210. this.href = trueLink;
  211. this.removeAttribute("transcoding");
  212. this.setAttribute("transcoded", "true");
  213. }
  214. },this.a);
  215. }
  216. return this;
  217. };
  218. // 检查是否在可视区域内
  219. Init.prototype.visible = function() {
  220. var obj = this.a,pos = obj.getBoundingClientRect(),w,h,inViewPort;
  221. if (doc.documentElement.getBoundingClientRect) {
  222. w = doc.documentElement.clientWidth || doc.body.clientWidth;
  223. h = doc.documentElement.clientHeight || doc.body.clientHeight;
  224. inViewPort = pos.top > h || pos.bottom < 0 || pos.left > w || pos.right < 0;
  225. return inViewPort ? false : true;
  226. }
  227. };
  228. //======执行=======
  229. handler(doc).bind({
  230. // 页面加载完毕则开始执行
  231. "DOMContentLoaded": function() {
  232. if( config.transcodingAll===false ){
  233. // 全局请求
  234. init().all(function() {
  235. // 逐一请求
  236. init(config.macthRules).onebyone();
  237. // 翻页监听
  238. handler(doc).ob({
  239. "childList":true,
  240. "subtree":true
  241. },function(){
  242. if( !config.transcodingAll ){
  243. init().all(function() {
  244. init(config.macthRules).onebyone();
  245. });
  246. }
  247. });
  248. });
  249. }
  250. },
  251. // 鼠标移入跳转链接则请求
  252. "mouseover": function(e) {
  253. var a = e.target;
  254. if (a.tagName == "A" && /www.baidu.com\/link\?url=/img.test(a.href) && a.getAttribute('transcoded') !== "true") {
  255. var href = a.href.replace("http", "https") + "&wd=&eqid=0";
  256. ajax(href,{
  257. "beforeFn":function(url){
  258. this.setAttribute("transcoding", "true");
  259. },
  260. "successFn":function(responseStr,url){
  261. var trueLink = responseStr.match(/\(\"\S+\"\)/img)[0].replace(/^[\(\"]*|[\)\"]*$/img,"");
  262. this.href = trueLink;
  263. this.removeAttribute("transcoding");
  264. this.setAttribute("transcoded", "true");
  265. }
  266. },a);
  267. }
  268. }
  269. });
  270. // 页面滚动则LazyLoad
  271. handler(win).bind('scroll',function(){
  272. // 逐一请求
  273. init(config.macthRules).onebyone();
  274. // 再次请求失败的url
  275. init(config.reloadRules).onebyone();
  276. });
  277. })(window,document,undefined);