Total Pageviews

Monday 21 January 2013

用一段Python代码自动下载“人人网”上好友的相册



爬虫是神马?
根据百度百科有: “网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取 万维网信息的程序或者脚本。…….传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的 URL放入队列,直到满足系统的一定停止条件。”
偶针对人人做了一些特化(换句话说拿到其他网站就没用了),人人网要访问首先得有个帐号,也就是说要先登录,然后服务器就可以根据session或 cookie来判断你在其他页面的登录情况,而对人人cookie就好了。当然,我们在一个浏览器登录,在另一个浏览器也可能还得要再登录一下,因为一般 情况下他们不共享cookie,除非专门去读某个浏览器的cookie。于是爬虫要爬人人,首先要登录…..然后保存cookie。
浏览器与服务器之间通讯主要都是Http协议,方法主要有GET和POST,(据《深入理解计算机系统》说,GET方法占了99%的HTTP请 求。),GET方法主要向服务器发送比较短的数据,主要将参数写到URL里面,而POST方法则可以发送比较长的数据,例如发这篇文章的话,则是用了 POST。想我们可以用”Telnet www.google.com 80”,然后键入”Get /”就可以可以收到和我们在浏览器打上”http://www.google.com/”同样的东西。爬虫也一样,就是不断地GET,POST……
要抓取所有好友的所有可见的相册有两种方法,一种是人工一个好友一个好友一个相册一个相册地下,另一种就是就给计算机让它自己去爬….因为我比较懒,所以选择第二种方法。
又到了“要怎么怎么样,首先怎么怎么样”的句式了~
要获取所有好友,可以在登录的情况下访问http://friend.renren.com/myfriendlistx.do,如果有用浏览器登 录的话,好友会被javascript分成很多页显示。在网页的某段javascript中有个变量叫friends,保存所有好友的信息,里面都是 {“id”:254905709,”vip”:false,”selected”:true,”mo”:true,”name”:”\u5b89 \u8feaAndy”,”head”:”http:\/\/hdn.xnimg.cn\/photos\/hdn321\/20110612 \/1600\/h_tiny_zFLc_715e000281932f76.jpg”,”groups”:[“\u534e\u5357\u7406 \u5de5\u5927\u5b66”]}这种元组,从这里,我们可以获取所有好友的id。
要获取某个人的所有相册,可以访问http://www.renren.com/profile.do?id=(某人的id)& v=photo_ajax&undefined,这个是怎么找出来的呢?我们登录一个人的主页时,然后点击相册,这个页面并没有刷新,只是由 AJAX替换了页面的一部分,它就是去Get那个路径,就返回了网页的一部分代码过来,替换掉现在的。所以我们也可以去Get那个路径,就可以获得包含所 有相册id的页面。
要获取一个相册里面的所有照片,这个要靠人人的一个Bug了,很无意发现的,你可以打开别人相册的排序照片的页面。在排序的页面,一个相册所有的照 片都列出来了,通过正则表达式,我们就可以拿到每张照片的id。排序的页面为http://photo.renren.com/photo/(某人的 id)/album-(相册id)/reorder。
经过了三句“要怎么怎么样,首先怎么怎么样”,我们拿到了所有好友的id,所有好友的所有相册的id,和所有好友的所有相册的所有照片的id。为什 么都是id呢?这个个人觉得用一个整数作为数据库元组的主码,性能会高些,而且对于一个32位整数,只占4字节,就可以标识4294967296个东西 了。加上在客户与服务器之间传送id也方便。
拥有这些id我们可以做什么,目前什么都做不了,我们访问http://photo.renren.com/photo/(某人的id) /photo-(相片id)就可以在网页中代码中发现AJAX返回的一段代码代码中有一句”largeurl”:”http:\ /\/fmn.rrimg.com\/fmn049\/20110621\/1520 \/p_large_S5jA_37eb000165dc5c3f.jpg”,这就是一张照片的真正地址了,然后我们把里面的””给删掉就可以下载了。
好,于是我们就可以这样写出一个残缺不全的爬虫了……….对于人人的新鲜事,可以把一个页面的url抓出来筛选后放到一个优先队列里,再从优先队列里选一个最优的进入,重复上一步,直到队列为空或者其他情况….

源码地址:  https://github.com/cedricporter/renren