18143453325 在线咨询 在线咨询
18143453325 在线咨询
所在位置: 首页 > 营销资讯 > 电子商务 > 爬虫爬取人人网社交数据(一)

爬虫爬取人人网社交数据(一)

时间:2023-03-13 22:54:01 | 来源:电子商务

时间:2023-03-13 22:54:01 来源:电子商务

今天突然看到人人网的一个链接,想起前几年可是很火的大学生社交网站,登录自己的账号进去看后,发现这网站居然开始搞直播,不是之前那么单纯的社交功能网站了,不过发现人人网的数据还挺有意思的,可以爬取到不认识的人的社交资料,比如性别生日,所读学校,好友列表的,这个数据可以拿来做一个社交关系网状图,甚至拿来检验六度分隔理论,想想还有点小兴奋,于是就开始研究怎么爬取人人网的数据。

首先看某个用户的人人网主页面 http://www.renren.com/494871890/profile , url中的494871890 很像是人人网用户的id,后尝试修改访问其它页面后得以证实,也就是说我们只要能拿到一批用户的id,然后去遍历这些网页,就能拿到这个用户的一些社交信息。那么我们只要考虑两个问题:

  1. 根绝某个用户id可以拿到哪些用户社交信息
  2. 如果获取大量的用户id
首先看第一个问题,我们能拿到用户哪些信息

看上图大红色方框选定的地方,可以拿到用户的 昵称,就读学校,性别,生日,居住地,主页访问次数,好友列表 等信息,还有用户的logo也是可以爬取下来的,这些信息应该足以支撑我们做社交网络的研究了。

再看第二个问题,如果和获取大量的用户id,看上图红色小红色方框部分,每个用户页面都会展示用户好友,那么这就很好办了,根据一个用户id获取他的好友id,再根据他的好友id获取更多的好友,也就是说我们只需要一个用户的id(比如就是你的id),可以获取到非常多的用户id,假定平均每个人有100个好友,那么我们爬取你的好友数量是 100,你好友的好友是 100*100 = 10000 ,你好友的好友的好友 100*100*100 = 100w,这个数字就已经非常大了。

大概的计划有了,我们就可以开始找网站的接口了

打开 http://www.renren.com/494871890/profile ,使用控制台选中我们要爬取的元素,就能看到实际上我们要爬取的数据都在一个id为 operate_area 的 div元素中,这就很好办了,我们只要爬取到这个页面的html然后再使用正则或者是 xpath将我们需要的元素爬取出来就可以了,但是这里得注意到,社交网站一般都会验证登录的,尝试了一下不加cookie果然是爬取不到用户页面的,果断去找到登录的Cookie,随便找个请求报文找到Header中的Cookie,就是下图红框部分,隐私信息太多了,码都打不过来。

然后我们就可以编写http类了

首先写个HttpUtil类用于访问网页代码,post和get方法都需要

package http;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;import org.apache.http.client.HttpClient;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.HttpClients;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;import util.RegexUtil;import java.util.*;/** * Created by on 2017/12/23. */public class HttpUtil { public String doGet(String url, Map<String, String> headers) { HttpClient httpClient; HttpGet httpGet; String result = null; try { httpClient = HttpClients.createDefault(); httpGet = new HttpGet(url); Iterator<Map.Entry<String, String>> it = headers.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); String key = entry.getKey(); String val = entry.getValue(); httpGet.addHeader(key, val); } HttpResponse response = httpClient.execute(httpGet); if (response != null) { HttpEntity resEntity = response.getEntity(); if (resEntity != null) { result = EntityUtils.toString(resEntity, "utf8"); } } } catch (Exception ex) { System.out.println("http get失败"); } return result; } public String doPost(String url, Map<String, String> params, Map<String, String> headers) { HttpClient httpClient; HttpPost httpPost; String result = null; try { httpClient = HttpClients.createDefault(); httpPost = new HttpPost(url); Iterator<Map.Entry<String, String>> it = headers.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); String key = entry.getKey(); String val = entry.getValue(); httpPost.addHeader(key, val); } Iterator iterator = params.entrySet().iterator(); List<NameValuePair> list = new ArrayList<NameValuePair>(); while (iterator.hasNext()) { Map.Entry<String, String> elem = (Map.Entry<String, String>) iterator.next(); list.add(new BasicNameValuePair(elem.getKey(), elem.getValue())); } if (list.size() > 0) { UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "utf8"); httpPost.setEntity(entity); } HttpResponse response = httpClient.execute(httpPost); if (response != null) { HttpEntity resEntity = response.getEntity(); if (resEntity != null) { result = EntityUtils.toString(resEntity, "utf8"); } } } catch (Exception ex) { System.out.println("http post失败"); } return result; } public static void main(String[] args) { HttpUtil util = new HttpUtil(); Map<String, String> headers = new HashMap<String, String>(); headers.put("Cookie", "你的cookie串"); String htmlStr = util.doGet("http://www.renren.com/494871890/profile", headers); Map<String,String> userInfo = RegexUtil.groupUserInfo(htmlStr); System.out.println(userInfo); }}

同时拉取到的是整个网页的代码,所以我们要使用正则或者xpath选择到我们需要的元素,这里使用正则,编写了一个正则的工具类RegexUtil

package util;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * Created by on 2017/12/24. */public class RegexUtil { public static List<String> getValByReg(String str, String reg, int valueNum) { List<String> rets = null; Pattern p = Pattern.compile(reg); Matcher m = p.matcher(str); if (m.find()) { if (m.groupCount() == valueNum) { rets = new ArrayList<String>(); for (int i = 1; i <= valueNum; i++) rets.add(m.group(i)); } } return rets; } /* * 获取用户标题栏消息工具 * **/ public static Map<String, String> groupUserInfo(String htmlStr) { Map<String, String> retMap = new HashMap<String, String>(); try { String infoReg = "(<div class=/"tl-information/"[//s//S]+</div>)"; //获取到存储用户信息的div List<String> rets = RegexUtil.getValByReg(htmlStr, infoReg, 1); if (rets == null || rets.size() < 1) { return retMap; } // 将div中的信息匹配出来 String div = rets.get(0).replace("/n", ""); Pattern p = Pattern.compile("<li class=/"(.*?)/">(.*?)</li>"); Matcher m = p.matcher(div); while (m.find()) { String attr = m.group(1); String value = m.group(2).replaceAll("(<span>|</span>| )", ""); retMap.put(attr, value); } } catch (Exception e) { return retMap; } return retMap; }}于是运行上面httpUtil中的主类方法我们可以输出的结果就是

{birthday=女生,二月十二日, hometown=来自河南商丘市, address=现居重庆, school=就读于重庆邮电大学}这就是说我们已经有了一个可以根据id拿到用户主页标题栏信息的工具了

为了之后存储数据库方便,我们预先把用户的bean类建好

package renren;import java.util.Set;/** * Created by on 2017/12/24. */public class User { private Stringd renrenId; // 人人id private String renrenName; // 人人昵称 private String renrenInfo; //人人标题栏信息 private int visitTime; //该人主页被访问次数 private Set<String> allFriendsId; // 该人的所有好友人人id public User() { } public User(String renrenId, String renrenName, String renrenInfo, int visitTime, Set<String> allFriendsId) { this.renrenId = renrenId; this.renrenName = renrenName; this.renrenInfo = renrenInfo; this.visitTime = visitTime; this.allFriendsId = allFriendsId; } public String getRenrenId() { return renrenId; } public void setRenrenId(String renrenId) { this.renrenId = renrenId; } public String getRenrenInfo() { return renrenInfo; } public void setRenrenInfo(String renrenInfo) { this.renrenInfo = renrenInfo; } public int getVisitTime() { return visitTime; } public void setVisitTime(int visitTime) { this.visitTime = visitTime; } public String getRenrenName() { return renrenName; } public void setRenrenName(String renrenName) { this.renrenName = renrenName; } public Set<String> getAllFriendsId() { return allFriendsId; } public void setAllFriendsId(Set<String> allFriendsId) { this.allFriendsId = allFriendsId; } @Override public String toString() { return String.format("%s---%s---%s---%d", renrenId, renrenName, renrenInfo, visitTime); }}可以看到我们再bean中还定义了 用户昵称,用户主页面访问次数,好友id集合的字段,好友id集合获取方式会在后面介绍,有点小复杂

先看看获取用户昵称 用户主页面访问次数 的获取,都在 之前的 RegexUtil中

package util;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * Created by on 2017/12/24. */public class RegexUtil { /* * 获取用户昵称信息 * **/ public static String groupUsername(String htmlStr) { String nameReg = "<title>人人网 - (.*)</title>"; List<String> rets = RegexUtil.getValByReg(htmlStr, nameReg, 1); if (rets != null && rets.size() > 0) return rets.get(0); return null; } //获取用户主页面访问次数 public static int groupVisitTime(String htmlStr){ htmlStr.replace("/n",""); String visitTimeReg = "(<div id=/"footprint-box/"[//s//S]*/h5>)"; List<String> rets = RegexUtil.getValByReg(htmlStr, visitTimeReg, 1); if(rets!=null && rets.size()>0){ String div = rets.get(0).replace("/n",""); String visitTime = div.replaceAll(".*最近来访.*?(//d+).*","$1"); if(visitTime.matches("//d+")) return Integer.parseInt(visitTime); } return 0; }}现在我们能拿到的信息有 用户id,用户昵称,用户标题栏信息(地址,大学等),主页访问次数 , 编写一个主类来试一下

package http;import net.sf.json.JSONObject;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;import org.apache.http.client.HttpClient;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.HttpClients;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;import renren.User;import util.RegexUtil;import java.util.*;/** * Created by on 2017/12/23. */public class Test { public static void main(String[] args) { HttpUtil util = new HttpUtil(); Map<String, String> headers = new HashMap<String, String>(); // Cookie headers.put("Cookie","你的cookie"); String renrenId ="494871890"; String htmlStr = util.doGet("http://www.renren.com/"+renrenId+"/profile", headers); //获取用户信息 Map<String,String> userInfo = RegexUtil.groupUserInfo(htmlStr); JSONObject jsonObj = JSONObject.fromObject(userInfo); String renrenInfo = jsonObj.toString(); //获取用户姓名 String userName = RegexUtil.groupUsername(htmlStr); //获取用户主页面访问次数 int visitTime= RegexUtil.groupVisitTime(htmlStr); User user = new User(renrenId,userName,renrenInfo,visitTime,null); System.out.println(user); }}输出结果为

494871890---李瑶玉---{"birthday":"女生,二月十二日","hometown":"来自河南商丘市","address":"现居重庆","school":"就读于重庆邮电大学"}---62那么我们根据一个id获取到用户信息并且填入bean已经可以成功了,后续会讲到

如何获取好友id列表,源源不断的获取到用户id,并且爬取信息入库,最后库中的数据基本如下所示

包含 用户id ,昵称,概括信息,主页访问次数,好友列表,以及存储每个用户的头像图片

当爬取到一定的数据之后(大概7000条),使用 gephi进行图像绘制,gephi可以绘制网络关系图,我们只要提供 点,边的关系即可,我们这里的点就是 各个用户的renren昵称(如果没有昵称可以用id替代) , 我们这里的边是 具有好友关系的两个人的id , 对我们库中的数据进行简单的处理后,可以得到点的信息

id 为renren_id,Label 为人名,对于没有爬取到的人名用佚名代替

得到边的信息如下

source 为边起始人人 id

target 为结束的人人 id

Itype为连线类型,为无向边

id是该边的id

weight为权重,即边的粗细

导入点数据到gephi

导入边数据到gephi

最后生成一个关系图

可以到看很多聚集的点就是一个人的所有好友,这个人同时连接了很多点

这个图只是用了几千个点和边,即几千个人的联系,因爬取的数据量相比gephi的计算而言过多,无法将图形绘制图来,过多cpu会发烫,目前只能达到这个量级的绘制了。

关键词:数据,社交,爬虫

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭