2007/01/05

JSON 應用(2):最新迴響的標題


自從 blogger.com 的新版發佈以來,最另人詬病的就是若是有加入一個新網頁元素(Page Elements),選擇資訊提供(Feed)的時候,加入是最新迴響的 Feed(http://xxxxx.blogspot.com/feeds/comments/summary) 更新的速度很慢,甚至要到幾個小時之譜,這對來部落格留言的人不是很能接受的。

因為 blogger.com 之前的舊版是利用轉成靜態網頁的方式,但新版就不是這樣的模式,增加了很大的彈性,但是這對於資料的同步與 Cache 是很大的考驗,所以其實也不能責怪他們。

若改成用 Javascript 的模式去抓 JSON 格式的 Feed 來顯示,可以解決上述的問題,因為資料是在客戶端電腦去抓取 Feed 回來顯示。可是問題又來了,這個 Feed 的格式居然沒有原文章的標題,這個對寫很多文章的人來說是個很大的困擾,往往要點入後才知道這些人是在哪篇文章留言的!所以,我想了幾個辦法如下:

  1. 先抓取 comments 的 feed,內有標題的網址,然後利用搜尋的方法去 blogsearch.google.com 取回標題
  2. 先抓取 comments 的 feed,內有標題的網址,然後再抓取 posts 的 feed 兩個去比對
  3. 先抓取 comments 的 feed,內有標題的網址,再抓取藉由 comments 發佈到 gmail 信箱然後轉發到另一個部落格的 posts feed 去比對網址,取回標題。


分析以上作法的風險,我決定採用最麻煩的第三種作法。

  1. blogsearch 的效能不可預知,新文章可能搜尋不到,舊文章可能搜不到,或者標題更改也不一定會更新。
  2. 看起來是完美的作法,但是萬一有人在很舊很舊的文章留言, posts 的 feed 一次最多只能抓取 99 則,若比對不到的話,可能還要抓第二次第三次,很浪費連線的資訊傳送。
  3. 去比對最新 comments 的 feed 雖然可行,可是中間經過兩個SMTP(gmail)的轉寄,未來格式轉變,或是被誤認為 SPAM 也是很容易出問題。


我很懶的剪圖做說明,就簡單的把第三種方法的設定方式描述如下,有問題的人麻煩在詢問就好。

  1. 在原部落格A的控制主頁(Dashboard) → 設定(Settings) → 意見(Comments) → 意見通知地址 (Comment Notification Address) 打入一個為了最新迴響而開設的gmail 信箱(C@gmail.com)
  2. 開一個新的部落格B,然後在控制主頁(Dashboard) → 設定(Settings) → 電子郵件(Email) → Mail-to-Blogger 地址 Mail-to-Blogger Address 自行設定一組地址(account.D@blogger.com) 然後下方的 發佈(Publish) 要打勾勾
  3. 進入 (C@gmail.com) 的信箱收信匣(Web版) → 設定(Settings) → 轉寄和 POP 轉寄內收郵件的副本至輸入上個步驟的 account.D@blogger.com
  4. 在部落格A隨便留個言,然後打開部落格B看看是否留言有變成一篇新的文章,若有的話再進行下一個步驟。
  5. 在部落格A的控制主頁(Dashboard) → 範本(Template) → 網頁元素(Page Elements) → 新增網頁元素(Add a New Page Elements) → HTML/Javascript 然後把下面的原始碼貼上,就大功告成了,不過寄得把紅字的網址要打對。

<div id="divrc">下載中...</div>
<script>
var g_szAuthorsLink=new Array();
var g_szTitle= new Array();
var g_szOrgLink = new Array();
var g_iIndex=0;
var g_iShowCount=5;

function a_comprc(a,b){
order= Date.parse(a.published.$t.replace(/^(\d{4})-(\d{2})-(\d{2})T([0-9:]*)([.0-9]*)(.)(.*)$/,
'$1/$2/$3 $4 GMT')) - Date.parse(b.published.$t.replace(/^(\d{4})-(\d{2})-(\d{2})T([0-9:]*)([.0-9]*)(.)(.*)$/,
'$1/$2/$3 $4 GMT'));
return 0-order;
}
function a_rc(json)
{
g_entry = json.feed.entry.sort(a_comprc);
}
function a_FindTitle(json,orgLink)
{
var ret= orgLink;
for (var ii=0,rc; rc= json.feed.entry[ii]; ii++)
{
var content=rc.content.$t;
var index=content.indexOf(orgLink);
if (index>0)
{
var iBegin=index+orgLink.length+2;
var content2= content.substring(iBegin,content.length);
var iEnd = content2.indexOf('</a>');
if (iEnd >0)
ret=content2.substring(0,iEnd);
break;
}
}
return ret;
}
function a_FindIndex(json,orgLink)
{
var ij=0;
for (ij=0; ij < g_iIndex; ij++)
{
if (orgLink==g_szOrgLink[ij])
return ij;
}
g_szOrgLink[ij]=orgLink;
g_szTitle[ij]= a_FindTitle(json,orgLink);
g_szAuthorsLink[ij]='◎';
g_iIndex ++;
return ij;
}
function b_rc(json)
{
for (var i=0,post; post = g_entry[i]; i++)
{
var content = post.title.$t;
var link = post.link[0].href;
var iFind = link.indexOf('#');
var orgLink= link;
if (iFind>0)
orgLink = link.substring(0,iFind);
var index = a_FindIndex(json,orgLink);
if (index>= g_iShowCount)
{
g_iIndex--;
break;
}
var auther= post.author[0].name.$t;
var timestamp=post.published.$t.substr(0,10) + ' ' +post.published.$t.substr(11,5);
g_szAuthorsLink[index] += '<a href="' + link + '" title="' + timestamp + ':' + content + '">' + auther + '</a>«';
}
var temp = '<ul id="feedItemListDisplay">';
for (var j=0; j< g_iIndex; j++)
{
temp += '<li><a href="' + g_szOrgLink[j] + '">' + g_szTitle[j] + '</a><br/>' + g_szAuthorsLink[j] + '</li>';
}
temp+="</ul>";
document.getElementById("divrc").innerHTML = temp;
}
</script>
<script src="http://部落格A網址/feeds/comments/summary?alt=json-in-script&callback=a_rc" type="text/javascript"></script>
<script src="http://部落格B網址/feeds/posts/full?alt=json-in-script&callback=b_rc" type="text/javascript"></script>


至於實際的效果,就看左邊的《最新迴響》就是了。

2007.1.11 更新
上面這個方法,email 轉發文章到部落格B 被 blogger.com 擋掉了,他們認為是 spam。所以我改用了方法2. 其實程式碼是差不多,也做成一個元件送給大家使用,使用方法如下:

<script>g_szBlogDomain='xxxxx.blogspot.com'; </script>
<script src="http://js.writers.idv.tw/rc.js"></script>

2008.9.23 更新
今天不知道怎樣,json 輸出的格式改了,我把程式更新在 rc3.js

<script>g_szBlogDomain='xxxxx.blogspot.com'; </script>
<script src="http://js.writers.idv.tw/rc3.js"></script>

2008.9.24 更新
我把原來程式加入 rel 這個值的判斷,所以用原來的 rc.js 也可以了!

總共有35個迴響

  1. pjhuang 1/11/2007 8:58 上午

    Cool

    很棒的解決方式,找時間要來裝裝看。

  2. 水瓶子 1/11/2007 1:28 下午

    上面這個方法,email 轉發文章到部落格B 被 blogger.com 擋掉了,他們認為是 spam。所以我改用了方法2. 其實程式碼是差不多,也做成一個元件送給大家使用,使用方法如下:

    <script>g_szBlogDomain='xxxxx.blogspot.com'; </script>
    <script src="http://js.writers.idv.tw/rc.js"></script>

  3. 柏強 1/15/2007 3:58 上午

    天啊,我找了半個月的程式出現了... 第三個想法真妙哪。

    前兩天想自己動手寫,我本來想的是用 xmlhttprequest 抓網頁下來解出 title,不過你的想法速度應該快上 n 倍。

    大感謝

  4. 柏強 1/15/2007 4:33 上午

    Hi,
    因為想讓顯示版面更符需求一點,希望你不介意我把程式抓回去修改,改完正式上線後會貼篇文章註明出處的 :)

  5. 水瓶子 1/15/2007 12:17 下午

    柏強,歡迎拿回去修改。

  6. 柏強 1/16/2007 8:40 下午

    找到一個以 postid 取得單篇文章 json 的方法:http://www2.blogger.com/feeds/{blogId}/posts/summary/{postId}?alt=json-in-script

    例如 http://www2.blogger.com/feeds/5918579739413557982/posts/summary/5099559220264953311

    不過我還沒有實際去做相應的程式,這好像應該用 httprequest 動態取回比較好?.. mmm

    總之先提供您這項資訊 :)

  7. 水瓶子 1/17/2007 1:33 上午

    柏強

    1. postid 的網址用下面這個可能好一點

    http://部落格網址/feeds/posts/summary/{postid}?alt=json-in-script

    若是用這種方法也不錯,只是有個缺點,若要顯示10個最新迴響,而且分別在不同文章回應,就要去抓10次的標題,有點耗費資源!

    2. 我個人覺得 json 比較好用,因為是瀏覽器透過 http 的協定去取回資料,而 httprequest 是利用瀏覽器內建的元件去取用,不知道有無最佳化過,這部份非同步的程式碼需要跑 javascript 才會去取資料,而 json 雖然也是 javascript 的語法,可是取資料的時候並沒有經過語言的解譯就去取資料了。

    3. 至於你問為什麼要排序,是因為blogger 的原始排序方式是依據更新的時間,而不是文章的時間,這個例子是以最新迴響的時間,應該並不需要排序,就是正確的。若是顯示最新文章,一定要排序才是對的。

  8. 柏強 1/18/2007 9:30 上午

    喔喔排序我了解了。

    我也覺得 JSON 比較好用,不過不了解除了 xmlhttprequest 之外怎麼動態取回某網址的資料。(每次都硬塞個 document.write([script]...[/script]) 進去?)

    多謝說明~

  9. 水瓶子 1/19/2007 2:01 下午

    柏強,對的,就是用 document.write......

    不過,這樣就跟用 XMLHttpRequest 的效果一樣了,呵呵!

  10. tate 1/26/2007 4:56 下午

    抱歉,請問所以方法3是不能用了嗎?我自己試結果是失敗的。

    沒想到要弄個最新的回應也這麼花工夫啊……

  11. Lynn 2/03/2007 3:56 上午

    感謝水瓶子啊
    原來的迴響佔了好多邊欄位置
    現在變的好清爽
    謝謝 ^^

  12. King @ 2/14/2007 12:27 下午

    請問水瓶子:
    您所說的改使用方法二
    那兩行程式碼,我要放在我的blog哪邊呢?謝謝

  13. King @ 2/14/2007 12:32 下午

    真是不好意思,我已經嘗試出來了

  14. King 4/26/2007 6:11 下午

    您好:
    不知道什麼原因
    今天看blog的時候,《最新迴響》那邊始終show不出來

  15. 水瓶子 5/02/2007 9:48 上午

    的確有幾天有問題,但我沒時間查,現在已經正常。

  16. 匿名 @ 5/03/2007 1:05 上午

    你好
    謝謝提供好用的功能
    但我使用了方法二的程式碼
    最新迴響的地方卻一直是"下載中"
    重新整理了好幾次都沒用
    請問可能是出了什麼問題?
    謝謝解答

  17. 水瓶子 5/03/2007 9:51 上午

    麻煩您把使用的部落格網址給我,我來查看看。

  18. tinyfox 5/05/2007 1:17 下午

    你好我是16樓
    今天最新回應還是一直"下載中"
    很頭痛啊...
    http://8020rule.blogspot.com/

    順便問一下
    因為想用自己的欄位名稱
    所以想要把《最新迴響》隱藏
    請問要如何修改
    非常謝謝

  19. 水瓶子 5/06/2007 12:48 上午

    給樓上的 fox,我想下面這段貼上去就可以了。

    <script>g_szBlogDomain='8020rule.blogspot.com'; var g_szHead='';</script><script src="http://js.writers.idv.tw/rc.js"></script>

  20. tinyfox 5/06/2007 5:50 下午

    謝謝水瓶子^^
    現在回應終於出來了
    非常完美XD

  21. hidelensman @ 5/07/2007 3:54 下午

    我好像也有跟fox一樣的問題耶
    都是出現下載中...
    可以請瓶子幫我?
    謝謝^^

  22. 水瓶子 5/07/2007 8:25 下午

    to hidelensman 以及其他留言的朋友:

    要協助的請留下您的部落格網址(測試站台也可以),我可以去看看幫你 debug,我不是神,馬上可以判讀您的問題。

  23. hidelensman @ 5/07/2007 10:31 下午

    http://hidelensman.blogspot.com
    謝謝水瓶子^^
    我發現水瓶子真的好厲害耶...
    很多文章對我這blogger初學者都很有幫助
    有空會多來跟水瓶子請教的^^

    再次謝謝:)

  24. 水瓶子 5/08/2007 1:39 下午

    樓上這位 hidelensman 大哥,您的 feed設定開關沒有打開,請到主控台(Dashboard)→設定(Setting)→網站提供(Site Feed)→進階模式(Advanced Mode) 把前兩個 Feed 打開

  25. hidelensman @ 5/08/2007 11:39 下午

    謝謝水瓶子>///<

  26. LVCHEN 6/21/2007 1:01 上午

    我在修改您的 code 時有幾個問題。

    Blogger 的comment RSS or JSON feed 好像並沒有留言者的網站連結或是 e-mail 資訊,在留言者暱稱加的連結好像怪怪的,Anyway 會連到文章的網頁,那不是多此一舉嗎?

    希望您有看懂我在說什麼><...

    還有用 JSON-in-script 的方式處理 JSON 是相當方便的,還可以避掉本地端無法開啟外部資源的問題,但是似乎在送到 function 處理 JOSN 的同時,並沒有辦法向外傳出參數,即使是利用全域變數(global),也沒有辦法,但是,不同的 JSON-in-script 呼叫卻可以直接使用 function 裡的變數,即使他們是在不同的 function 與不同的 callback。

    請問您對這有什麼看法,如果我要從 JSON-in-script 的呼叫中傳參數到其他的function (與json-in-script callback 用的function 沒關係),有什麼好辦法嗎?

    您可以 e-mail 給我,我的e-mail 是 lvchen.blog@m2k.com.tw

    謝謝您的回答。

  27. LVCHEN 6/21/2007 7:28 上午

    花了一個下午,勉強解決了問題。

    成果就在我的站上。

    雖然還沒有得到您的解答,但總之還是要謝謝您的 CODE 給我的靈感。

  28. 水瓶子 6/21/2007 7:47 下午

    LVCHEN,你已經克服了,恭喜!有關大於99篇的文章,其實還是有解決方法,只是很耗IE的效能及頻寬,再去讀下一個99篇文章的標題來比對就可以了,只是很懶得再寫程式了。

    還有一個解決的方式,若你到那篇文章去重新發佈一下文章,有機會會在 RSS 上出現,這樣就可以抓到標題了,不過並不太適用很久很久以前的文章,我也不知道為什麼,我想應該是 blogger.com 資料庫的儲存方式問題吧!這個就不深究了

    有關你對於為何作者要連結到網頁的這個問題,應該可以發現連結後面有個 #123456789 的號碼,而留言的地方多了 <a name=#123456789> 的這個 HTML tag 就是可以快速的指到留言者的地方,只是這樣,沒有別的作用。你可能要改一下 template 才能配合的天衣無縫

  29. LVCHEN 6/23/2007 2:42 上午

    謝謝你的回答

    我還想試試能不能讓這個看似普通的功能得到更大的擴充。

    但我的確遇到一些困難...

    不知道您對 jQuery 熟不熟,如果有這方面的問題可以請教你嗎?

  30. LVCHEN 8/04/2007 12:37 上午

    您好,我從您的最新迴響得到很多 IDEA,也寫了一個屬於自己的最新迴響 widget,這幾天我想要發表出來,先給您通知ㄧ聲,希望您有空能看一看,順便給我ㄧ些意見。

    我的 blog 有範例,porject 的 Homepagey 在 http://code.google.com/p/lvchen-recentcomments/

    在此再對您說聲謝謝。

  31. cyber runner 8/30/2007 5:48 下午

    謝謝大大
    已用您的方案
    謝謝

  32. DONKEY EGG 5/04/2008 8:30 下午

    大大,想請問妳一下,因為我本身不會任何網路語言,
    但是又很想把樣板更換,http://www.fresheezy.com/請問這網站的樣板,該怎麼套用呢??能幫幫我嗎?

  33. uperkids @ 9/21/2008 6:03 下午

    我跟32樓的大大有同樣的困擾>"<
    我是用wordperss,然後想用fresheezy的樣板更換,可是下載下來以後不知道要怎麼弄到wordpress上
    只是想問問看
    如果水瓶子不方便也沒關係
    先謝過囉
    附上我的e-mail:
    uperkids@hotmail.com
    ^^

  34. gitiswoods @ 9/23/2008 8:15 下午

    感謝你的更新解決了我的問題!

  35. Felicia 4/29/2009 10:52 下午

    無意間得知這個地方
    感覺真棒,謝謝大大的研究
    讓我這個對程式語言不懂的人
    可以如願地加入訪客的回應
    感謝^_^