即将迎来国庆+中秋小长假,部分同事已经请假提前回家,工作氛围感觉渐淡下来,于是开始整理最近以来的工作的总结,以及开始准备节后一个技术沙龙的议题,还有节后的工作计划,闲暇之余聊到了二哥(gainover)之前的“安全圈有多大?”于是又重温了一遍,二哥作为生物学博士,使用生物学中分子的分析方法分析了安全圈的关系。二哥通过爬取腾讯微博的数据,以自己为起始点爬取用户的关注了哪些人,通过这种可视化方法能得到很多有意思的信息,下面记录一下实践过程吧~
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.javaweb.core.net.HttpRequest;
import org.javaweb.core.net.HttpResponse;
import utils.MysqlConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by jeary on 2017/9/28.
*/
public class WeiboSpider {
public static void main(String[] args) {
Map<String[], Boolean> urls = new HashMap<String[], Boolean>();
urls.put(new String[]{"16525***", "**"}, false);
crawllWeibo(urls);
}
public static void crawllWeibo(Map<String[], Boolean> urlMap) {
Map<String[], Boolean> weibos = new HashMap<String[], Boolean>();
String id = "";
String name = "";
for (Map.Entry<String[], Boolean> url : urlMap.entrySet()) {
id = url.getKey()[0];
name = url.getKey()[1];
System.out.println(id + ":" + name);
long siteid = findID(id);
if (siteid == 0) {
add(new Object[]{id, name});
siteid = findID(id);
}
System.out.println("新的父节点ID:" + siteid + "\t");
Map<String, String> links = getTwoWeiboLinks(id);
for (Map.Entry<String, String> linkMap : links.entrySet()) {
String weibo_id = linkMap.getKey();
String weibo_name = linkMap.getValue();
weibos.put(new String[]{weibo_id, weibo_name}, false);
System.out.println(weibo_id + "\t" + weibo_name);
long ref_id = findID(weibo_id);
if (ref_id == 0) {
add(new Object[]{weibo_id, weibo_name});
ref_id = findID(weibo_id);
}
System.out.println("发现新关系,准备入库:" + siteid + " -- " + ref_id);
add_ref(new Object[]{siteid, ref_id});
}
System.out.println("");
}
crawllWeibo(weibos);
}
public static Map<String, String> getTwoWeiboLinks(String id) {
Map<String, String> allLinks = new HashMap<String, String>();
for (int i = 1; i < 11; i++) {
String body = getHtml(id, i);
Map<String, String> links = getWeiboLinks(body);
allLinks.putAll(links);
}
return allLinks;
}
/**
* 解析Json获取用户名和ID
*
* @param jsonStr
* @return
*/
public static Map<String, String> getWeiboLinks(String jsonStr) {
Map<String, String> links = new HashMap<String, String>();
try {
JSONObject jsonObject = JSON.parseObject(jsonStr);
JSONArray cards = jsonObject.getJSONArray("cards");
JSONObject jsonObject1 = null;
for (int i = 0; i < cards.size(); i++) {
jsonObject1 = cards.getJSONObject(i);
JSONArray card_group = jsonObject1.getJSONArray("card_group");
if (card_group.size() >= 19) {
for (int j = 0; j < card_group.size(); j++) {
JSONObject cardobj = card_group.getJSONObject(j);
JSONObject user = cardobj.getJSONObject("user");
String id = user.getString("id");
String name = user.getString("screen_name");
links.put(id, name);
}
}
}
} catch (Exception e) {
System.out.println(e.toString());
}
return links;
}
/**
* @param id
* @return
*/
public static String getHtml(String id, int page) {
String url = "https://m.**.cn/api/container/getIndex?containerid=231051_-_followers_-_" + id +
"&page=" + page;
String body = "";
try {
System.out.println("发起请求:" + url);
HttpRequest request = new HttpRequest();
request.url(url);
request.followRedirects(true);
request.userAgent("Mozilla/5.0 (Linux; Android 5.1.1; Nexus 4 Build/LMY48T) AppleWebKit/537.36 (KHTML, " +
"like Gecko) Chrome/40.0.2214.89 Mobile Safari/537.36");
HttpResponse response = request.get();
body = response.body();
} catch (Exception e) {
e.printStackTrace();
}
return body;
}
}
核心代码已经给出,所以这里省略爬取流程。但是关于如何爬取博中的数据,这里不得不提一下:
由于博主站做了数据限制,只显示5页,通过伪造手机端ua发现手机端可加载10页,也就是10*20,可抓取200人关注者。
(PS:如果有大神有突破数据限制抓取所有关注者请不吝赐教~)
请求之后会返回20个他关注的人,通过JSON解析可以很方便的取出,但是这里有个小坑,取了cards后,要提取的数据可能不是在第一个,所以需要循环取。
我们以“余弦”作为爬虫起始点开始爬取数据,由于没有开多线程,总过爬取了接近两个小时,大约发起了一共26万请求(2.6w用户10页),爬行的过程中需要对数据进行入库存储,还需要构造相应的关系数据。
爬取的博用户数据如图:
关系数据:
在爬取过程中,开始出现大量非安全圈的*博账号,所以我停止了爬虫开始进行数据整理准备导入。
直接导出CSV然后将数据整理为以上格式,分别为关系数据和*博用户数据,准备好以上两个数据开始导入
导入节点数据:
导入边数据:
此时切换到“图”窗口,看到如下密集的点构成的正方形说明数据导入成功
选择一个布局算法,进行设置后点击应用,然后
随着时间过去,布局开始慢慢明显,等到点完全分开的时候我们就可以停止布局算法了(PS:布局算法特别消耗CPU和内存)
如图(不小心就玩得没内存了):
我们取消掉,然后停止布局算法。
此时的图应该已经处于展开状态,但是由于点太多,如果我们此时显示所有的微博名字是很吃内存的,我们可以运行一些算法和过滤来让可视化变得友好。
结果一系列操作后,可视化效果变得友好了,如图:
最后我们通过Gephi的Sigma插件生成HTML,
对于添加新连接
添加新关系类
的代码,小伙伴们请自行完善,完成的请联系小冰
,我们一起愉快的玩耍。关于现成的数据查询展示页面为 Web Security&Penetration Testing
交流圈小福利,有兴趣入圈的可以留言。
后续公开信息中秘密的寻找,就靠大家去慢慢发掘了。比方说通过分析一个人的所有微博,来给目标画像包括兴趣爱好、职业、作息规律、等等。