公司辦了一個活動,吸引了大批網友來留言,因為合作廠商說只能幫忙分析 (parse) 公開留言,所以得手動把 facebook 誤判為廣告 (spam) 而隱藏的留言 (comments) 打開。

想要人工檢閱,但是點一次只展開其中的 50 筆,所以上網 Google "facebook expand all comments",找到這篇:"Expand All Facebook Comments"

 

做法很簡單,就是把下面這行超連結搬到 Chrome 或 Firefox 的我的最愛書籤列就可以了:

 

 

展開所有fb留言 

 

這個的原理是把一長串 JavaScript 放到書籤裡,開好要展開留言的 facebook 討論串網頁後,再去點一下書籤列上的這顆按鈕,就可以展開所有留言。

 

作者 Jens-ingo Farley 說他不打算在網誌中美化程式碼,請有興趣的人自己到 jsbeautifier.org 之類的網站處理。我因為怕這段程式裡有放什麼有的沒的,所以就把內容撿出來看一下,看起來就是代替人工去遞迴地點選「查看更多的留言 (View more comments)」。

var todo=7;
var EXPAND_POST=1;
var EXPAND_COMMENTS=2;
var EXPAND_REPLIES=4;
var WAIT_TIME=100;
var MAX_WAIT=20;
var END_DELAY=2;
var CSS_COMMENT_AREA="UFIList";
var ATTR_SHOW_COMMENT_AREA="data-comment-prelude-ref";
var CSS_SHOW_COMMENT_AREA="UFIBlingBox";
var CSS_SHOW_COMMENT_AREA_2="uiBlingBox";
var _NONE="no-value";
var _COMMENTS="-comments";
var _REPLIES="-replies";
var CSS_CONTINUE_READING="text_exposed_link";
var CSS_PAGER="UFIPagerLink";
var CSS_VERIFIED="UFIReplySocialSentenceVerified";
var CSS_LINK_TEXT="UFIReplySocialSentenceLinkText";
var CSS_SEE_MORE="fss";
var CSS_COMMENT="UFIComment";
var CSS_REPLY_LIST="UFIReplyList";

function escapeClauseOn(){window.abortNow=false;
    document.addEventListener("keyup",docKeyUp);
}

function escapeClauseOff(){window.abortNow=true;
    document.removeEventListener("keyup",docKeyUp);
}

function docKeyUp(e){
    if(e.keyCode==27){
        myLog("Aborting...");
        window.abortNow=true;
    }
}

function showStatusWindow(){
    var WANT_W=300;
    var WANT_H=200;
    var sizer=document.getElementsByTagName("html")[0];
    var w=sizer.clientWidth;
    var h=sizer.clientHeight;
    var x=0;
    if(w>WANT_W){
        x=(w-WANT_W)/2;
    }
    var y=0;
    if(h>WANT_H){
        y=(h-WANT_H)/3;
    }
    var div=document.createElement("div");
    div.id="status-window";
    div.style.position="fixed";
    div.style.zIndex="999999";
    div.style.left=x+"px";
    div.style.width=WANT_W+"px";
    div.style.top=y+"px";
    div.style.height=WANT_H+"px";
    var container=document.body;
    container.insertBefore(div,container.firstChild);
    var edit=document.createElement("textarea");
    edit.style.width="100%";
    edit.style.height="100%";
    edit.style.color="#fff";
    edit.style.backgroundColor="#425f9c";
    div.appendChild(edit);
    window.g_logger=edit;
    escapeClauseOn();
}

function hideStatusWindow(){
    var div=document.getElementById("status-window");
    document.body.removeChild(div);
    g_logger=null;
    escapeClauseOff();
}

function myLog(s){
    console.log(s);
    window.g_logger.value=s+"\n"+window.g_logger.value;
}

function endSession(){
    var n=document.getElementsByClassName(CSS_COMMENT).length;
    myLog("Number of comments and replies = "+n);
    window.setTimeout(hideStatusWindow,END_DELAY*1000);
}

function getDomSize(){
    return document.getElementsByTagName("*").length;
}

function getStyle(node){
    return node.ownerDocument.defaultView.getComputedStyle(node,null);
}

function isHidden(node){
    return getStyle(node)["display"]=="none";
}

function getAncestorByType(node,type,deflt){while(node){
    node=node.parentNode;
    if(node&&node.nodeName==type){return node;
    }}return deflt;
}

function getAncestorByClass(node,className){
    while(node){
        node=node.parentNode;
        if(node&&node.className&&node.className.indexOf(className)!=-1){
            return node;
        }
    }
    return null;
}

function ensureCommentsShowing(value,onDone){
    var byClass=(value!=null);
    var showers=byClass?document.getElementsByClassName(value):document.getElementsByTagName("A");
    var filter=[];
    for(var i=0;i<showers.length;i++){
        if(byClass||showers[i].getAttribute(ATTR_SHOW_COMMENT_AREA)){
            var root=getAncestorByType(showers[i],"FORM",document);
            var area=root.getElementsByClassName(CSS_COMMENT_AREA);
            if(area.length==0){
                filter.push(showers[i]);
            }
        }
    }
    if(filter.length>0){
        myLog("Showing comments for "+filter.length+" post(s)");
            clickAndWait(_NONE,onDone,filter,0);
        }
    else{
        if(onDone)onDone();
    }
}

function isHideReplies(value,link){
    if(value===CSS_LINK_TEXT&&link.children.length==0){
        return true;
    }
    if(value===CSS_VERIFIED&&isNaN(window.parseInt(link.textContent,10))){
        return true;
    }
    return false;
}

function newWindow(link){
    var anchors=link.getElementsByTagName("A");
    if(anchors.length>0){
        var target=anchors[0].getAttribute("target");
        if(target){
            myLog("New window: "+anchors[0].textContent);        
            var w=window.open(anchors[0].getAttribute("href"),target);
            if(!w){
                myLog("New window was blocked!");
            }
            return true;
        }
    }
    return false;
}

function clickClass(value,onDone){
    if(window.abortNow){
        if(onDone)onDone();
        return;
    }
    var links=document.getElementsByClassName(value);
    var filter=[];
    for(var i=0;i<links.length;i++){
        if(value==CSS_CONTINUE_READING){
            if(isHidden(links[i])){
                continue;
            }
            if(links[i].children.length>0){
                filter.push(links[i].children[0]);
                continue;
            }
        }
        if(isHideReplies(value,links[i])){
            myLog("skipping: "+links[i].textContent);
        }
        else if(value===CSS_SEE_MORE&&links[i].nodeName==="SPAN"){
            continue;
        }
        else{
            if(!newWindow(links[i])){
                filter.push(links[i]);
            }
        }
    }
    if(filter.length>0){
        clickAndWait(value,onDone,filter,0);
    }
    else{
        if(onDone)onDone();
    }
}

function commentsOrReplies(comments,onDone){
    if(window.abortNow){
        if(onDone)onDone();
        return;
    }
    var links=document.getElementsByClassName(CSS_PAGER);
    var filter=[];
    for(var i=0;i<links.length;i++){
        var isReply=getAncestorByClass(links[i],CSS_REPLY_LIST)!=null;
        if(comments&&!isReply){
            filter.push(links[i]);
        }
        else if(!comments&&isReply){
            filter.push(links[i]);
        }
    }
    if(filter.length>0){
        clickAndWait(comments?_COMMENTS:_REPLIES,onDone,filter,0);
    }
    else{
        if(onDone)onDone();
    }
}

function clickAndWait(value,onDone,links,i){
    if(window.abortNow){
        if(onDone)onDone();
        return;
    }
    var label=links[i].getAttribute("aria-label");
    if(!label){
        label=links[i].textContent;
    }
    myLog("click: "+label);
    links[i].click();
    var n=getDomSize()+(value===_NONE?20:0);
    var wait=value===CSS_SEE_MORE?0:MAX_WAIT;
    window.setTimeout(function(){waitHelper(value,onDone,links,i,n,wait);},WAIT_TIME);
}

function waitHelper(value,onDone,links,i,n,wait){
    if(wait===0||getDomSize()>n){
        if(++i<links.length){
            clickAndWait(value,onDone,links,i);
        }
        else{
            if(wait>0){
                if(value==_COMMENTS||value==_REPLIES){
                    commentsOrReplies(value==_COMMENTS,onDone);
                }
                else{
                    clickClass(value,onDone);
                }
            }
            else{
                if(onDone)onDone();
            }
        }
        return;
    }
    if(wait!=MAX_WAIT){}
    window.setTimeout(function(){waitHelper(value,onDone,links,i,n,--wait);},WAIT_TIME);
}

function setUpActions(){
    var actions=window.actions=[];
    actions.push(function(onDone){ensureCommentsShowing(null,onDone);});
    actions.push(function(onDone){ensureCommentsShowing(CSS_SHOW_COMMENT_AREA,onDone);});
    actions.push(function(onDone){ensureCommentsShowing(CSS_SHOW_COMMENT_AREA_2,onDone);});
    if((todo&EXPAND_POST)!=0){
        actions.push(function(onDone){clickClass(CSS_CONTINUE_READING,onDone);});
    }
    if((todo&EXPAND_COMMENTS)!=0){
        actions.push(function(onDone){commentsOrReplies(true,onDone);});
    }
    if((todo&EXPAND_REPLIES)!=0){
        actions.push(function(onDone){commentsOrReplies(false,onDone);});
        actions.push(function(onDone){clickClass(CSS_VERIFIED,onDone);});
        actions.push(function(onDone){clickClass(CSS_LINK_TEXT,onDone);});
    }
    actions.push(function(onDone){clickClass(CSS_SEE_MORE,onDone);});
    actions.push(endSession);
    actions.push(null);
}

function doActions(i){
    if(window.actions[i]!=null){
        window.actions[i](function(){doActions(i+1);});
    }
}

if(window.g_logger){
    return;
}

showStatusWindow();
setUpActions();
doActions(0);

 

 

第一個 todo 是作者設計來作為參數的,把它改成 0, 1, 2, 3, 4, 5, 6, 7 各有不同效果。

  • 1: 展開貼文 (post) 本身
  • 2: 展開留言 (comments)
  • 3: 展開貼文與留言 (comments),但不展開留言 (comments) 之下的回覆 (replies)
  • 4: 展開回覆 (replies)
  • 5: 作者沒說這個參數設計來幹嘛的XD
  • 6: 展開留言 (comments) 與回覆 (replies),但不展開貼文本身
  • 7: 預設值,展開貼文 (post)、留言 (comments) 與回覆 (replies)

 

 

arrow
arrow
    文章標籤
    facebook comments 留言
    全站熱搜
    創作者介紹
    創作者 小攻城師 的頭像
    小攻城師

    小攻城師的戰場筆記

    小攻城師 發表在 痞客邦 留言(5) 人氣()