昨天上知乎一看,發現本身關注的問題接近1000個了,不能忍,但願控制在500個以之內最好是100個之內。因而打開我關注的問題列表。發現這個列表已經由滾動加載變成了分頁,而且不能在問題列表頁面直接點取消關注,須要進入問題詳情頁面去取消關注。這樣一來工做量就太大了。
以前滾動加載的時候只要寫個小腳本在控制檯運行一下就能夠把全部的問題加載出來,如今想把全部的問題加載出來就不行了。html
可是做爲一個前端,對頁面上的東西,老是能夠想一想辦法的。那就寫個小小的chrome插件吧。前端
要實現的功能點:git
思路:github
實現的時候要注意的是何時去點擊下一頁,在什麼時機觸發。由於咱們要肯定下一頁的數據加載過來了,才能進行下一次點擊,否則就可能出現漏頁的狀況。 觀察頁面發現每一頁的數據加載好,知乎就會把滾動條移動到頂部去。因此咱們能夠經過監測scroll事件來判斷當前頁面的數據是否已經加載完畢。監測到scroll事件的時候就是咱們發起下一次點擊的時候。而且當下一頁加載好以後咱們要再把滾動條移動到底部去。這樣加載新一頁的時候滾動條纔會再次往上移,從而觸發咱們綁定的scroll事件。
另外,就是scroll事件通常會一次性觸發好多個。咱們要保證咱們綁定的事件的邏輯代碼只執行一次。因此我加了一個timeout定時器,稍微延遲一下。等滾動條停下來的時候才真正執行事件邏輯。在這個timeout運行以前的再次觸發的scroll事件都會直接return掉。而且設置一個適當延遲,也減少了被誤認爲是爬蟲的機率。ajax
思路:chrome
爲了方便,我就直接寫成chrome插件使用了。就不用每次手動到控制檯去運行了。
直接拿以前寫的一個chrome插件的架子過來開幹。
chrome插件的入門寫法以及使用我以前有篇文章寫過。一個簡單的chrome拓展程序開發
而且以前的chrome插件架子裏集成了jQuery,代碼寫起來就更歡快了。api
/* * 功能說明: * 1.把全部關注的問題列出來。 * 2.給全部的問題添加取消關注按鈕並完成取消關注。 * * author: liusaint@gmail.com * date: 20180120 */ var ZhiHu = { htmlArr: [], //保存每一頁的問題的html數據。 pageItems: {}, //保存每一頁的數量。 INTEVAL: 2000, //翻頁的時間間隔。請求下一頁的間隔。能夠調小一些。 timer: '', //定時器 //初始化。 init: function() { var that = this; //綁定滾動事件。當頁面滾動了就能夠開始請求下一頁的數據了。 $(window).on('scroll', this.scrollFn.bind(this)); //初始調用。 this.scrollFn(); //給咱們添加的按鈕綁定事件。 $("body").on("click", '.del-q', function(event) { that.delQ($(this)); }); }, //取消關注。拼裝url,發送delete請求。 //須要拼裝的url接口格式:https://www.zhihu.com/api/v4/questions/20008370/followers delQ: function(jqObj) { var questionUrl, matchArr, delUrl, questionId; //問題頁面連接 questionUrl = jqObj.siblings('.QuestionItem-title').find('a').attr('href'); if (!questionUrl) { return; } //正則匹配問題id matchArr = questionUrl.match(/\d+/); if (matchArr) { questionId = matchArr[0]; } delUrl = 'https://www.zhihu.com/api/v4/questions/' + questionId + '/followers'; $.ajax({ url: delUrl, type: 'delete', success: function(data) { //成功的話刪除該列。 jqObj.closest('.List-item').remove(); } }) }, //頁面滾動時觸發的事件。 scrollFn: function(event) { var that = this; //滾動條滾動時會屢次調用此方法,攔截掉。 if (this.timer) { return; } this.timer = setTimeout(function() { //頁面內容提取 that.saveData(); //若是有下一頁,模擬點擊。 if ($(".PaginationButton-next").length > 0) { $(".PaginationButton-next")[0].click(); //移動到底部。 that.scrollBottom(); } else { //到了最後一頁了。最後的數據處理。 that.mergeList(); //解綁事件 $(window).off('scroll'); } clearTimeout(that.timer); that.timer = ''; }, this.INTEVAL) }, //從頁面中提取問題html數據與每頁的數量。 saveData: function() { var html = $(".List-header+div").prop('outerHTML'); this.htmlArr.push(html); //當前頁面的問題數量 this.pageItems[$('.PaginationButton--current').text()] = $('.List-item').length; }, //數據收集完成後對列表的處理。 mergeList: function() { var html = this.htmlArr.join(''); //組裝全部頁的數據到一頁。 $(".List-header+div").html(html); //移除分頁 $(".Pagination").remove(); //給每一個問題添加取消關注按鈕 $(".ContentItem-title").append('<button class="del-q" style="float:right;color:#1388ff;">取消關注</button>'); //把每頁的數量打出來看一下,發現並非每頁都是20條數據。 top.console.log(this.pageItems); }, //滾動到底部 scrollBottom: function() { var h = $(document).height() - $(window).height(); $(document).scrollTop(h); }, } /* chrome插件部分。核心代碼是上面的內容 */ chrome.extension.onRequest.addListener( function(request, sender, sendResponse) { if (request.greeting == "hello") { //執行上面的內容 ZhiHu.init(); } } );
插件完成,加載到chrome瀏覽器,點擊運行。功能正常。大功告成。數組
不過當全部問題都加載出來以後發現了比較奇怪的事情,就是一共加載出來911個問題。而實際上知乎顯示我關注的問題有950個。因此我一度懷疑是否是哪一個邏輯有錯誤少加載了一兩頁的數據。就在代碼里加入了一個對象保存每個問題頁面的問題數據。
得出的結果是並非每一頁都有20個問題的。有些頁面只有19個,最少的甚至只有16個。因而我點開某一頁最少的,挨個數一下,發現真是隻有16個。而後把這些數據加起來,確實是911個。
另外39個問題真是消失在搜索結果中了。瀏覽器
本代碼具備時效性,僅供參考。知乎的列表的dom結構和接口均可能會修改。若是發現代碼不能運行,能夠酌情修改代碼再運行。app
效果圖: