公司辦了一個活動,吸引了大批網友來留言,因為合作廠商說只能幫忙分析 (parse) 公開留言,所以得手動把 facebook 誤判為廣告 (spam) 而隱藏的留言 (comments) 打開。
想要人工檢閱,但是點一次只展開其中的 50 筆,所以上網 Google "facebook expand all comments",找到這篇:"Expand All Facebook Comments"。
做法很簡單,就是把下面這行超連結搬到 Chrome 或 Firefox 的我的最愛書籤列就可以了:
這個的原理是把一長串 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)
文章標籤
全站熱搜
留言列表