标签

2015年2月16日星期一

在Heroku为墙外博客搭建墙内可访的爬虫代理

计算机网络课程在讲HTTP协议的时候介绍了Web Proxy(代理)的原理,可以用这幅图解释
这里要讲的代理工作原理和Proxy是一样的,不同之处在于不涉及任何的缓存。Client访问我们所搭建的Proxy服务器的时候,Proxy通过爬虫到我们的墙外博客爬下HTML页面直接返回。

Django域名转换
Django是一个很好的Python后台框架。在MVC框架下,Django通过定义视图模块(通用命名是views.py)来为网页指定view部分,可以结合模块使用。
Django通过根目录下的manage.py文件来与服务器进行交互,例如我们在本地启动一个Django服务器,使用的是命令
python manage.py runserver
我们可以修改manage.py内定义的默认模块来指定初始的模块,例如我们将项目主体的文件都放到了gettingstarted的目录,修改manage.py的设置:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gettingstarted.settings")
向其指定设置文件为gettingstarted目录下的settings模块。
Django的url配置用于定义项目中url模式与其对应视图,定义在urls.py中
默认的urls.py是这样的:
from django.conf.urls.defaults import *

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Example:
    # (r'^mysite/', include('mysite.foo.urls')),

    # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
    # to INSTALLED_APPS to enable admin documentation:
    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # (r'^admin/', include(admin.site.urls)),
)
urls.py文件中的urlpatterns是一个元组,通过正则表达式匹配url,然后指定其映射到的视图模块。这个代理的urls.py很简单。
urlpatterns = patterns('',
    url(r'^(.*)$', 'gettingstarted.views.getPageContent', name='getPageContent'),
)
我在这里定义一个会捕捉整个url后缀的正则表达式,在映射时,Django会将正则内捕捉到的组作为参数传给你定义的模块,例如我在views.py内定义的getPageContent函数:
def getPageContent(request, postfix="/"):
 url = 'https://zhengsuizhan.blogspot.com/' + postfix + "?m=1"
 content = urllib2.urlopen(url).read()
 content = content.replace("http://zhengsuizhan.blogspot.com/", "http://zhengsuizhan-blogspot.herokuapp.com/")
 content = content.replace("?m=1", "")
 return HttpResponse(content)

这个函数将后缀拼接成url后通过urllib2模块进行访问,因为我没有做特别处理,直接通过Django的HttpResponse函数转换为Http响应信息返回。这样以来,访问云平台上的一个形如
http://zhengsuizhan-blogspot.herokuapp.com/xxxx的url,代理服务器先通过url映射规则,将正则捕捉到的组内容"xxxx"传参给getPageContent函数,getPageContent访问blogspot上对应页面http://zhengsuizhan.blogspot.com/xxxx,处理成响应报文返回。这样便能实现访问代理时url的格式和原网站上的格式一致。(我在这里让代理访问手机版页面)
urls.py的作用很像PHP项目中的.httaccess,不过感觉写起来更顺手。
关于Django的更多,请参考Django Book或官方文档。

选择云平台

现在人们能够申请的云平台很多。但因为我是为自己的Google Blog搭,Blogspot自从零八零九后的互联网寒冬后就一直被GFW封禁,所以我并没有考虑国内企业的云平台BAE或是SAE,一来怕我的应用受到审查,二来不了解新浪或是百度的服务器能不能翻墙。这使得选择空间变小。
最早用过的云平台是新浪的Sina App Engine(SAE)。SAE限制流量,当你注册初始的云豆用尽后就不能被访问,需要通过金钱购买,百度的BAE相比之下功能更好。
从Instagram在上年九月阵亡开始,我意识到墙选择目标的逻辑其实很简单:“不听我话的就是目标”。我在红帽子(Red Hat)的云平台Openshift上给这个博客搭建了代理站,才发现Openshift上搭建应用对应的域名rhcloud早就进了黑名单。同理的还有Sourceforge旗下对应的用户自建站域名。GAE更不用说了。有境外网站选择使用亚马逊的云服务为自己的网站搭建镜像。他们认为寄生在外企的基础服务上,GFW要墙掉整个站点的成本太大(亚马逊的云服务有一定的国内用户量)。但既然GFW能做到墙掉维基百科的某条词条,或是阮一峰博客的某篇博文,他们就能在不影响AWS整体业务的情况下卡掉某个不和谐的应用,因此我仍认为这种依附的自由是伪命题。
回到GFW逻辑的话题,为什么sourceforge和github这类看似人畜无害的程序猿社群网站都会被盯上(Github在2013年曾被下手,后因受到IT业人士广泛关注而解除,sourceforge早在2002始就被多次下手)?很直接的一个原因就是因为这类网站里没有直接听命的审查员,因此就有可能被用于发布他们Undesired的内容(巨火一直通过Github公布他们设置的最新镜像地址)。这个逻辑实际上能解释很大部分境外网站进入黑名单的原因(Instagram,Flickr,Wordpress等等)
我最后选择了墙内尚能访问的Heroku云平台,这家创业公司已被Salesforce收购。据说名字来源于Hero和Haiku(俳句,一种日本诗)的拼接。有趣的是Ruby的发明者松本行弘也加入了这个公司。

源代码
这个小程序的源代码在我的Github上可以看到。

题外话,一些墙外网站的用户,在他们使用的网站阵亡后认为在这些网站上发布不和谐内容的人要负责任,有时甚至是骂。不知道大家怎么看。记得以前中学玩一款被封禁的游戏《命令与征服:将军》,贴吧上一些用户会骂发布不和谐内容的用户怕他们导致封吧,当然吧主会很快删帖。

没有评论 :

发表评论