Showing posts with label BloggerHack. Show all posts
Showing posts with label BloggerHack. Show all posts

Monday, September 21, 2009

用 Feed 实现 Blogger 分页

使用 Blogger 建博客,一个很不爽的问题是在首页下方没有分页功能,这会直接导致有兴趣的读者没有办法方便的翻阅以前的旧帖子;而 Blogger 提供的模板,无论是老的 Template,还是新的 Layout,都没有相关的标签来实现这个功能,因此要加上这个功能,就只能继续 hack 了。

这两天利用 Blogger 的完整帖子的 Feed,配合 PHP 实现了这个功能。思路为:
  • 读取原始的 index.html,把帖子的部分去掉,也就是 <Blogger>...</Blogger> 这段内容
  • 读取以下 Feed 地址,解析出文章的日期、时间、标题、正文、标签等,按照原来模板的格式,用 PHP 输出到原来 index.html 放文章的地方
    http://www.blogger.com/feeds/[blogId]/posts/full?max-results=[step]&start-index=[startIndex]&orderby=published
  • 根据当前页码以及总帖数计算分页,在页面底部添加分页链接
  • 如果有条件,可以利用 .htaccess 文件,将分页的 URL 由原来的
    xxx.php?page=x
    形式替换成对搜索引擎更友好的
    /index/x
    形式

如此一来,就可以在自己不存储任何文章数据的情况下,实现分页功能。当然,直到目前,以上的 Feed 地址仍然是被墙的,需要翻墙或者使用 HTTP 代理才能成功地获取内容。

Friday, June 19, 2009

GFW 开始识别 WEB 代理

之前提到用 HTTP 中转的办法解决了评论的问题,今天发现 Blog 上所有的评论又失效了…… 开始以为是因为页面直接引用了 www.blogger.com 域名的某些内容而导致撞墙,但仔细分析后发现,我的 HTTP 中转直接不能访问了,而且之后我的 HTTP 中转程序所在的域名也会在一小段时间内无法访问…… 但同时,用该中转能够访问原本没有被封的内容,比如 Flickr……

考虑到传入的目标 URL 参数是用 Base64 和 URL Encode 方式处理的,不存在任何加密,而且这和大多数的 WEB 代理相同,所以推测是现在 GFW 能够识别用 Base64 编码的内容,如果该内容刚好是被屏蔽的网址,则阻拦该 HTTP 请求,并且屏蔽该请求所在的域…… 从而让公众无法通过 WEB 代理访问屏蔽内容。

当然,解决的办法也简单,如果不能简单通过 Base64 decode 得到一个 URL,那么它也就无从判断是不是被屏蔽的网址了……

我起先想直接把原网址按位取反再 Base64 就行了,结果同事说我作为一个 IT 人士这么干太低级了…… 他们说用 RSA 吧,但是也犯不着这么兴师动众吧……

还是 Liuming 小弟比较聪明,提供了一个比按位取反高级,又比 RSA 简单的办法,那就是……

两次 Base64…… >.<"e;

Friday, October 17, 2008

Blogger 的相关文章和热门文章

看到很多别人的 Blog 在文章页面下方都有“相关文章”和“热门文章”的列表,无疑能够增加访问者继续阅读文章的兴趣。可是 Google 的 Blogger 没有这样的功能,于是自己想办法也添加了一个。

由于 Blogger 并没有提供相关的模板标签(Tags)来支持这样的功能,因此自己只好用 PHP 和 MySQL 建立了一个简单的数据维护和查询系统,然后用 AJAX 的方式在页面上显示出来。具体来讲有以下内容:
  • 利用 Google Blogger 的 Feed 接口将文章的 ID、标题、标签、URL、发布及修改时间等内容用程序导入到数据库。
  • Google Analytics 的页面浏览数统计(统计报告 » 内容 » 最常见内容)数据导出成文本文件,再通过程序导入到数据库。
  • 用 PHP 建立一个“相关文章”的查询接口。输入参数为文章的 ID,输出为指定数量的相关文章列表。具体算法上,先用 ID 查出基准文章的标签,然后在数据库中文章中比对标签匹配的数量,按照标签匹配数量从多到少找出相关的文章。
  • 对于热门文章,有两种计算方法。一种是按有史以来所有文章的浏览量来排序,但是用这种方法得到的结果,基本上都是 2005 年很老的文章,而很多有意义的新文章却很难出现。于是我采用了另一种算法,即按照每日平均浏览量来排序,这样比较新的浏览量比较大的文章也能出现了。

修改好模板以后,将整个 Blog 重新发布,现在这些功能已经调试好并上线了。顺便抱怨一下,对于用 FTP 发布的 Blogger 来讲,帖子多了以后,整站重新发布,真是一个漫长的过程啊。

在修改模板的同时,也顺便改了一下首页上提示阅读全文的方式,将原来的“点击这里阅读全文”的文字链接改成了图标,希望这样看起来更醒目一些,在我另一个非技术的 Blog 上可以看到效果。

另外,最初做的模板的 PSD 文件找不到了,也忘了当时在标题部分用的哪种字体。这给后面添加新的标题带来很多麻烦。于是趁这次修改模板,一并将标题的图片都修改了。找了很多字体,也研究了很久,挑了 10 种非衬线(Sans Serif)字体出来,最后选中的竟然是 Windows XP 自带的 Lucida Sans Unicode。

Thursday, May 29, 2008

用 AJAX 实现 Blogger 页内评论

之前服务器上有 Java 环境时,一直用一个自己写的 Servlet 作为中间代理来向 Blogger 的评论页面 POST 表单数据,实现页面内的评论操作,后来转挂在朋友的 IIS 服务器下,由于对 ASP 不熟,这一功能就一度取消了。现在购买了新的 Linux PHP 服务器,因此用 PHP 重新写了一个同样功能的中间代理来实现这一功能,并且实现成了 AJAX 的模式。评论内容的读取也一样通过 Blogger Feed 的 JSON 模式读取,因此提交评论后可以立即显示出来,而不用再等待 Blogger 重新生成 HTML 页面并通过 FTP 上传这一漫长的过程。(虽然实际上后台它还是不可避免的执行了这个过程。)

经过多次测试,应该可以用了。关于 Spam 的问题,以前的验证码是直接读取的 Blogger 页面的 Captcha 图片,现在 Google 改变了表单结构以至于程序已经无法自动做这个动作。所以我取消了 Blogger 自己的 Captcha 验证,自己写了个简单的加减法验证,虽然仍然不能完全杜绝 Spam,但已经比几天前测试时裸奔的情况好多了。当时夸张到一个下午一张帖子被贴了 50 多条 Spam 评论。毕竟传说 Google 的 Captcha 也已经被破解了么,同样不能完全杜绝 Spam。 ;-)

另外,Backlink 不显示的问题也修正了。不过,经过前端时间页面恶意代码事件的影响,目前似乎已经没什么 Backlink 了…… :-(

Friday, January 05, 2007

用 JSON 实现侧边栏的最新评论列表

上个月 21 号 Google 发出消息,声称 GData API 开始支持以 JSON (JavaScript Object Notation,中文介绍) 的形式提供数据,并且给出了对应的 API 文档,同时 Blogger Buzz 网站也告知广大用户,JSON 支持的 GData API 中同样也包括 Blogger。

在这之前,由于 JavaScript 先天的限制,我们不能通过 JavaScript 代码打开当前域以外的远程文件,这也就限制了我们通过传统的 AJAX 技术利用 GData API 的 Atom Feed 来实现 Blogger 页面上最新帖子、评论列表的即使更新,因为我们无法在某个 *.blogspot.com 域名下打开 www.blogger.com 下的 XML 文档。当然,新的 Blogger 支持在自己的域名下,也就是以 yourname.blogspot.com/feeds/ 的形式访问 Atom Feed 解决了这个问题,但是对于通过 FTP/sFTP 发布的非 blogspot 用户,还是无法绕过这个问题。

现在,Google GData API 除了可以在原来的地址后面加 alt=json 参数来以 JSON 的格式组织数据以外,还可以用 alt=json-in-script&callback=myFunction (其中 myFunction 是自己用来处理 JSON 数据的函数) 的方式使得 Feed 返回的 JS 代码内容直接是对 myFunction 函数的调用,这样就绕过了以上 JavaScript 不能远程调用本域以外资源的限制。

通过这个办法,我修改了自己 Blogger 侧边栏的最新评论列表。虽然原来有一个,不过只是根据 Blogger Help 上的这篇介绍开启的,原理还是利用 <Blogger> 标签的循环,只输出评论的部分,也就是说,原来的方法输出的只是当前页面最新评论列表,没有在首页列出的文章,其评论是不会出现的。而且,在默认情况下,评论的排序方式是先按帖子先后顺序,再按时间顺序。我自己另外写了一个 JavaScript 函数来对它们重新排序,并只保留最新的 10 条。

现在,通过 GData API 的 JSON 回调支持,我写了一个真正意义上的最新评论列表。看到这位网友提供了一个 blogspot 用户适用的办法,对于非 blogspot 发布,特别是 FTP/sFTP 发布的用户,可以用我的办法:

<div id="sidebar-recent-comments">
<p id="comment-loading">Loading Data...</p>
<dl id="comments-block">
<dt class="comment-data" name="comment-data">
<a href=""></a><span>, </span>
<span class="comment-poster">
<a href="" rel="nofollow"></a></span>
<span> said...</span></dt>
<dd class="comment-body" name="comment-body"><p></p></dd>
</dl></div>

<script type="text/javascript">

// Fetch the recent comments from Blogger Feed with JSON code and
// the callback func is "dispComments".
function getComments(blogId, counts) {

// Temporarily hide it
var dl = document.getElementById("comments-block");
dl.style.display = "none";

// Retrieve the JSON feed.
var script = document.createElement('script');
script.setAttribute('src', 'http://www2.blogger.com/feeds/' + blogId +
'/comments/default?alt=json-in-script&callback=' +
'dispComments&start-index=1&max-results=' + counts);
script.setAttribute('id', 'jsonScript-recent-comments');
script.setAttribute('type', 'text/javascript');
document.documentElement.firstChild.appendChild(script);
}

// Translate the date
function transDate(dateStr) {
dateStr = dateStr.substring(0, dateStr.indexOf("."));
dateStr = dateStr.replace("T", " ");
dateStr = dateStr.replace(/\-/g, "/");
return dateStr;
}

// Display the comment entries onto the web page.
function dispComments(json) {
var dl = document.getElementById("comments-block");

// get entry template
var dt = dl.getElementsByTagName("dt")[0];
var dd = dl.getElementsByTagName("dd")[0];

dl.removeChild(dt);
dl.removeChild(dd);

for (var i = 0; i < json.feed.entry.length; i++) {
var entry = json.feed.entry[i];
var curDt = dt.cloneNode(true);
var curDd = dd.cloneNode(true);

// Time
curDt.childNodes[0].href = entry.link[0].href;
curDt.childNodes[0].appendChild(
document.createTextNode(transDate(entry.published.$t)));

// Author
curDt.childNodes[2].childNodes[0].appendChild(
document.createTextNode(entry.author[0].name.$t));
if (entry.author[0].uri) {
curDt.childNodes[2].childNodes[0].href = entry.author[0].uri.$t;
}
else {
curDt.childNodes[2].childNodes[0].removeAttribute("href");
}
dl.appendChild(curDt);
dl.appendChild(curDd);

//Content
curDd.childNodes[0].appendChild(
document.createTextNode(entry.title.$t));
}

dl.style.display = "block";
var commentLoading = document.getElementById("comment-loading");
commentLoading.style.display = "none";
}

getComments('yourBlogId', entryCount);
</script>

注意最后一行调用的 getComments 函数的两个参数,yourBlogId 是你当前这个 Blog 的 blogId,每个 Blog 都是不同的。打开自己帖子的评论页面,从 URL 上就可以找到自己的 blogId。第二个参数 entryCount 是要显示的评论条数,例如 10。

另外,为了保持页面整洁,我只使用了评论的第一行,也就是 title 部分的内容。如果需要显示完整,将以上代码中蓝色的 title 改成 content 即可。

为了简洁起见,也可以把 getComments 和 dispComments 两个函数放到外部的 .js 文件中去定义,页面只用引入这个 .js 文件,然后调用 getComments 即可。

Saturday, November 18, 2006

通过 GData API 提交评论

前两天有提到升级到 Blogger Beta 后发布评论的问题。今天从 Google Groups 上的 Google Data API 讨论组上看到一个新的发布评论的办法,就是用 GData API 通过单贴评论的 Feed 地址
http://beta.blogger.com/feeds/blogID/postID/comments/default

发布。

这个方法与向 http://beta.blogger.com/comment.do 直接 POST 数据的方法比起来,要科学得多。经过测试,这个方法确实可行,评论发布后,页面会被正常地重建。然而,仍然有问题:评论对应的发布者被设置成了 Blogger 的主人,也就是在向 feed POST 数据之前提供给 Google 的身份验证信息对应的用户。

据讨论组上 Blogger 的研发人员回复说,官方并不支持这种方法提交评论,尽管它确实是可行的。我想之所以会有上面的问题,大概是因为这个方法原本是用来发布帖子用的,在这种情况下,作者信息自然就应该从通过身份验证的 Blogger 账户中取得。

已经在这个有关 GData API 提交评论的讨论串中提出建议修正这个问题,不过不知道 Blogger 会不会理我。在这个问题被修正之前,这个方法实际仍然无法投入实用,毕竟不会有人会让所有评论的作者信息丢失掉。

Monday, November 13, 2006

升级后如何才能方便的发布评论?

升级到 Blogger Beta后,由于大家无法访问 beta.blogger.com 域名,因此出现了无法发布评论的问题,在上次的帖子中有所讨论。

为了解决这个问题,我自己写了个简单的 Servlet,来接受来自页面上的评论发布,并将这个请求转到 Blogger Beta 上处理评论发布的地址 https://beta.blogger.com/comment.do,因为我可以修改服务器上的 host 文件使其可以访问 beta.blogger.com,这样可以起到一个类似代理的作用,代替需要发布评论的朋友们访问这个不能直接访问的域名。

理论上是没有问题的,实践上我也几乎取得了成功。出现的问题是:评论被正常发布后,和评论相关的帖子页面没有重建!

我们知道,用 FTP 的方式发布 Blogger,任何对帖子的更改,都会导致 Blogger 自动重建页面并自动发布到 FTP 相关的目录下,以使得 blog 网站上的页面能够反应出最近的信息,这些操作包括新增/修改/删除帖子,以及添加/删除评论。正常情况下,一旦有评论发布,这个重建的过程就会发生,这样评论能够在最多几分钟的时间内出现在页面上。

可是现在,评论的内容都出现在 Blogger Beta 自己的评论页面上了,但是却没有触发页面重建。不过,如果直接把页面上评论表单的内容提交到 https://beta.blogger.com/comment.do,则一切正确;但是当然这样做没有意义,因为这要求发布评论的朋友能够直接访问 beta.blogger.com 域名。

现在出现的现象会是,大家发布的评论不会立即显示在帖子页面上,但是实际上是已经被正确的保存了。我看到电子邮件的提示后,就会尽快重建页面使得这些评论能够被显示出来。相信这个问题只是暂时的,总归是应该得到解决的。

这个问题琢磨了一晚上也没有得到结果,Google 上也搜不出什么有用的东西来。已经把这个问题发布到了 Google 上的 Blogger Data API 讨论组求助,希望有人遇到过类似的问题从而给我一些提示。

Updated on 2006/11/17:
有一个更科学的方法来提交评论,那就是用 GData API 向单贴评论的 Feed 地址提交,不过仍然有些问题。详见“通过 GData API 提交评论”。

Updated on 2006/12/21:
Blogger 的某次更新似乎已经解决了评论提交后页面不会重建的问题。现在在页内的评论表单中提交评论,页面会被立即重建,只是由于需要重建的页面和以往的老 Blogger 比起来要多一些,因此会慢一点。一般 5 分钟之内评论就会出现在页面上了。

Thursday, October 26, 2006

Blogger 网页显示空白的问题

之前一直有朋友声称我的 Blog 访问不了,打开来是空白。这个问题我自己也经常遇到,原因是网页编码被误判成 GB2312,而不是正确的 UTF-8,于是 IE 无法识别,所以显示成空白。这个问题据说在 Firefox 上并不存在,但是为什么会被误判我也一直不清楚。

现在原因应该清楚了,因为在文件头中,声明网页内容编码的那一行标记
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

被放到了 <title> ... </title> 之后,而刚好 title 中有中文,所以 IE 在没有获得指定的编码类型时,用了默认的 GB2312。

解决这个问题还是比较容易:编辑 Blogger 的模版,把“<$BlogMetaData$>”放到“<title><$BlogPageTitle$></title>”的前面,然后重建一下,就不会出现这个问题了。

Friday, August 18, 2006

模版更新

看了 Blogger Beta 新的 Archive 树状的列表方式,非常喜欢,于是花了点时间,把自己现在的模版也改成了这个样子。刚好做 Calender 的时候,已经有一份完整的时间、帖子标题和地址的对应数据,所以做这个树状的 Archive 列表,只是表现的问题而已。不过,尽管如此,还是花了我好几个小时的时间。

另外,打开了 Blogger 的 Backlink 功能。由于要改模版,Blogger 提供这个功能以后一直没有动,嫌麻烦。不过,把这个功能打开容易,要把样式调整的和整体一致,还是花了不少功夫。

弄好后,把自己比较得意的帖子都看了一下,除了 Throwing Tables Out the Window 那篇以外,别的帖子几乎没什么 backlinks,可能还是因为我写的东西都比较私人吧。

Tuesday, October 18, 2005

SSI 和 document.write()

这两天一直在考虑怎么给 Blogger 加上 Calendar 和分类的功能。原来是这么打算的:

首先,要让生成的 HTML 代码尽量符合 XHTML 规范,以便可以写程序用 XML 解析器来分析并从中提取数据。只要是合法的 XML,应该问题就不大,不一定要完全遵循 XHTML 的 DTD,反正 Dom4J 没有 DTD 照样能分析 XML,不过,这个还有待试验证实。

Blogger 的帖子数据里面,link 这个字段似乎没有什么用,可以利用它来存储分类。通过程序分析提取以后,套用 Blogger 的模板生成 HTML,并把出现过的分类列表写到一个单独的 HTML 中,由需要的页面通过 SSI include 进来。

同样利用分析出来的数据,生成日历的 HTML,每个月一个文件,供需要的页面调用。

不过,要让 Resin 支持 SSI 功能,可能性不太大,必须另外想办法。

昨天给 BlogBus 做模板,发现这个 Blog 的默认模板里头,所有侧边栏(日历,最近贴,存档,Tags 等)全部都是由 JavaScript 来 document.write() 的,而 JavaScript 代码本身,也貌似是发布的时候根据数据动态产生的,估计这个是为了达到这些数据块可以在需要的地方重复调用的目的。

于是,我想,是不是我也可以将 Blogger 里头需要的 Calendar 和分类数据也在发布时用 Servlet 写成 JavaScript,然后再在需要的地方用这些 JavaScript 来 document.write()

嗯,有空试验一下就知道了…… 理论上应该是可行的……

Updated on 11/13/2005:

经过试验,用 document.write() 方式输出是可行的,现在此 blog sidebar 上的日历就是用 document.write() 打印出来的,而数据是由 Servlet 分析生成的 HTML 文件后自动写的 JavaScript 代码。问题有两个,一是用 Dom4j 解析的时候,对实体 (entities) 的解析有点问题,要把除 &amp; 以外的所有实体全部清楚掉才能解析正确,应该有正确的识别方法,尚在研究中。另一个问题是,documents.write() 写出来的内容,无法被搜索引擎识别,但对网站本身功能影响不大。

Sunday, October 09, 2005

So We've Got A New Face Here!

上次翻译了那篇倡导 tableless layout 的文章后,心里头就一直想着尝试一下。所以今天响应这个号召,在坚决不用 table 的原则下,把面孔改成了这个样子。实际没有什么设计的成分,主要是尝试对 CSS 的利用。结果是完全实现了原来必须要用 table 才能完成的版面,还是有点成就感。另外,今天还大概看了一下 CSS 2.0 的参考,突然发现了 CSS 很多以前不知道的却很实用的功能,尤其是,居然可以让溢出容器的文字串自动省略并以“...”结尾;以前这个功能需要用服务端程序来实现,而且还挺麻烦的……