先做一下小测试,看看人人网首页是哪个form提交数据,提交数据的域有哪些
<span style="font-size:18px;">import mechanize br=mechanize.Browser() br.open('http://www.renren.com') for form in br.forms(): print form</span>打印结果为:
<span style="font-size:18px;"><POST http://www.renren.com/PLogin.do application/x-www-form-urlencoded <TextControl(email=)> <PasswordControl(password=)> <CheckboxControl(autoLogin=[true])> <TextControl(icode=)> <HiddenControl(origURL=http://www.renren.com/home) (readonly)> <HiddenControl(domain=renren.com) (readonly)> <HiddenControl(key_id=1) (readonly)> <HiddenControl(captcha_type=web_login) (readonly)> <SubmitControl(<None>=登录) (readonly)>></span>看起来是第一个form在提交数据,数据域为email和password
<span style="font-size:18px;">import mechanize br=mechanize.Browser() br.open('http://www.renren.com') br.select_form(nr=0) br['email']='email'#登陆账号,通常为邮箱地址 br['password']='password'#登陆密码 r=br.submit() print br.title()</span>
可以看到打印出来的title为“人人网-XXX“,XXX为你在人人网的注册名,从而证明登录成功。
当然如果熟悉基础包,使用如下方法也可以达到登陆人人网的目的
<span style="font-size:18px;">#encoding:utf-8 import cookielib import urllib2 import urllib cj=cookielib.LWPCookieJar() opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) url='http://www.renren.com/PLogin.do' parms={'email':'xxx','password':'xxx'} parm=urllib.urlencode(parms) req=urllib2.Request(url,parm) response=opener.open(req) print response.geturl()#查看登陆信息,验证登陆成功 print response.info()</span>
正式动工,利用mechanize实现自动化登陆与网页内容下载,re或BeautifulSoup实现数据提取,源代码:
<span style="font-size:18px;">#encoding:utf-8 ''' Created on 2015年1月21日 @author: ''' import mechanize import re import time from bs4 import BeautifulSoup #初始化一个浏览器对象 def initBrowser(): #Browser br = mechanize.Browser() #options br.set_handle_equiv(True) br.set_handle_gzip(True) br.set_handle_redirect(True) br.set_handle_referer(True) br.set_handle_robots(False) #Follows refresh 0 but not hangs on refresh > 0 br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) #debugging #br.set_debug_http(True) #br.set_debug_redirects(True) #br.set_debug_responses(True) #User-Agent br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')] return br #登陆人人网 def renrenLogin(email,password): br=initBrowser() r=br.open('http://www.renren.com') br.select_form(nr=0) br['email']=email#登陆账号,通常为邮箱地址 br['password']=password#登陆密码 r=br.submit() print br.title() print br.geturl() return br #获取好友列表页的好友id和姓名 def getFriends(page,uid): friendUrl='http://friend.renren.com/GetFriendList.do?curpage=' friendsUrl=friendUrl+str(page)+'&id='+uid print 'page-',page,': ',friendsUrl friendsPage=br.open(friendsUrl).read().decode('utf-8') soup=BeautifulSoup(friendsPage,from_encoding='utf-8') friendsCon=soup.find('ol',{'id':'friendListCon'}) friends=friendsCon.find_all('div',{'class':'info'}) #接下来你可以使用正则表达式提取信息 pattern=re.compile('<a href="http://www.renren.com/profile.do\?id=(\d{9})">(.*?)</a>') for friend in friends: info=friend.encode('utf-8') match=pattern.search(info) if match: userID=match.group(1) print 'id:',userID name=match.group(2) print 'name:',name #也可以使用BeautifulSoup来提取信息 for friend in friends: info=friend.find('a') href=info['href'] userID=href[-9:len(href)] print 'id:',userID name=info.string print 'name:',name #如果有下一页,递归处理,循环进行下一页处理 nextPage=soup.find('a',{'title':'下一页'}) if nextPage!=None: page=page+1 time.sleep(1)#先休息一下 getFriends(page, uid) email='XXXXX' password='XXXXX' br=renrenLogin(email,password) print br.title() iniUrl=br.geturl() uid=iniUrl[-9:len(iniUrl)] getFriends(0,uid) </span>
就不截取结果图了,自己跑一遍就可以得到自己的所有好友数据。这样就可以将所有好友ID,NAME取到,下一步是通过好友id获取好友的好友,但数据会呈指数级上升,如果我有100个好友,每个好友平均有100个好友,则好友的好友就会有100*100=10000条数据。按照六度分割理论,你和任何一个陌生人之间所间隔的人不会超过五个,100^6=10^12数量级达到百亿级,足以覆盖所有地球人,因此,倘若所有地球人都注册了人人网,最多通过五个中间人你就能够认识任何一个陌生人,如图
以上只抓取到我的好友,为了获取好友的好友,添加一个列表用于记录好友id,然后根据好友id依次抓取好友的好友,并将结果保存到文件,主函数改为:
#encoding:utf-8 ''' Created on 2015年1月21日 @author: ''' import mechanize import re import time from bs4 import BeautifulSoup import csv #初始化一个浏览器对象 def initBrowser(): #Browser br = mechanize.Browser() #options br.set_handle_equiv(True) br.set_handle_gzip(True) br.set_handle_redirect(True) br.set_handle_referer(True) br.set_handle_robots(False) #Follows refresh 0 but not hangs on refresh > 0 br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) #debugging #br.set_debug_http(True) #br.set_debug_redirects(True) #br.set_debug_responses(True) #User-Agent br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')] return br #登陆人人网 def renrenLogin(email,password): br=initBrowser() r=br.open('http://www.renren.com') br.select_form(nr=0) br['email']=email#登陆账号,通常为邮箱地址 br['password']=password#登陆密码 r=br.submit() print br.title() print br.geturl() return br #获取好友列表页的好友id和姓名 def getFriends(page,uid): friendUrl='http://friend.renren.com/GetFriendList.do?curpage=' friendsUrl=friendUrl+str(page)+'&id='+uid print 'page-',page,': ',friendsUrl print br.title() if page==0: uname=br.title()[12:]#截取“人人网 - XXX”中的用户名 else: uname=br.title()[12:-9]#截取“人人网 - XXX的好友”中的用户名 friendsPage=br.open(friendsUrl).read().decode('utf-8') soup=BeautifulSoup(friendsPage,from_encoding='utf-8') friendsCon=soup.find('ol',{'id':'friendListCon'}) friends=friendsCon.find_all('div',{'class':'info'}) #接下来你可以使用正则表达式提取信息 pattern=re.compile('<a href="http://www.renren.com/profile.do\?id=(\d{9})">(.*?)</a>') for friend in friends: info=friend.encode('utf-8') match=pattern.search(info) if match: userID=match.group(1) name=match.group(2) f.write(uid+","+uname+','+userID+','+name+'\n') #如果有下一页,递归处理,循环进行下一页处理 nextPage=soup.find('a',{'title':'下一页'}) if nextPage!=None: page=page+1 time.sleep(1)#先休息一下 getFriends(page, uid) email='XXX' password='XXX' br=renrenLogin(email,password) print br.title() iniUrl=br.geturl() iniId=iniUrl[-9:len(iniUrl)] f=open('e:/test/renren.csv','a')#追加模式打开 f.write('fromid,fromname,toid,toname\n') getFriends(0,iniId) #获取朋友 f.flush() f.close() friendsList=[] f=open('e:/test/renren.csv') reader=csv.reader(f) reader.next()#跳过第一行标题行 for line in reader: friendsList.append(line[2])#取第三列toid f=open('e:/test/renren.csv','a') for fid in friendsList:#id为内置变量,避免使用,否则会带来意想不到的意外与麻烦 getFriends(0,fid) #获取朋友的朋友 f.flush() f.close()
大功告成,如此就可以循环往复,得到好友的好友数据了。
仍然使用R来进行数据分析和可视化,先看看得到了多少条数据
<span style="font-size:18px;">renren<-read.csv('e:/test/renrendata.csv',sep=',',stringsAsFactors=F,encoding='utf-8',header=F) names(renren)<-c('fromid','fromname','toid','toname') nrow(renren) [1] 43911</span>
接下来对数据进行清洗
<span style="font-size:18px;">renren[,1]<-as.character(renren[,1]) renren[,3]<-as.character(renren[,3]) renren[,1]=sub('的好友','',renren[,1])#数据中仍然出现少量XXX的好友的情况 <span style="font-family:SimSun;">renren[,4]=sub('的好友','',renren[,4]) myid=renren[1,1] renren<-renren[renren$fromid!=myid,]#去掉from中的自己 renren<-renren[renren$toid!=myid,]#去掉to中的自己 length(unique(renren$fromname))#看看我有多少个好友 [1] 163</span>看看朋友的朋友
<span style="font-size:18px;">friends<-table(renren$fromid) frame<-data.frame(friends) nmaes(frame)<-c('id','fnum') head(frame) id fnum 1 151717544 224 2 194087284 266 3 200161949 413 4 221056707 935 5 221284131 195 6 221348577 195 summary(frame$fnum) Min. 1st Qu. Median Mean 3rd Qu. Max. 8.0 150.8 217.5 265.7 330.0 1248.0 </span></span>平均每个朋友有250多个朋友,最多的有1200多个朋友,画个图看看分布情况
<span style="font-size:18px;">frame<-frame[order(frame$fnum,decreasing=T),] qplot(1:nrow(frame),fnum,data=frame,geom='line')+xlab('好友数排名')+ylab('好友数') </span>
graph<-graph.data.frame(d=fnet,directed=T,vertices=fnode) graph<-simplify(graph)#去掉重复链接 degree<-degree(graph) summary(degree) Min. 1st Qu. Median Mean 3rd Qu. Max. 1.000 1.000 1.000 2.951 1.000 1248.000 graph<-subgraph(graph,which(degree>3)) print(graph) IGRAPH UN-- 1291 12548 -- + attr: name (v/c) plot(graph, layout = layout.fruchterman.reingold, vertex.size = 5, vertex.label = NA, + edge.color = grey(0.5), edge.arrow.mode = "-")