更多有趣项目及代码见于:DesertsX/gulius-projects

前言

本文将带你用 neo4j 快速实现一个明星关系图谱,因为拖延的缘故,正好赶上又一年的4月1日,于是将文中的几个例子顺势改成了“哥哥”张国荣。正所谓“巧妇难为无米之炊”,本次爬取娱乐圈_专业的娱乐综合门户网站下属“明星”页的“更多明星”里所有9141条数据。

筛选出个人主页中含“明星关系”的数据,进一步爬取并解析出后续关系图谱所需的数据。以“张国荣-个人主页”为例,其直接相关的明星并不多,可见数据质量不一定多高,仅供练手,故不在此处过多纠缠。

数据到手后,存成 csv,丢到 neo4j 里,就能查询出“张国荣”的关系。

如果想进一步查看“张国荣”扩散出去的关系,也很方便。

因缘际会

有没有觉得很酷炫,很想赶紧学起来。不急,neo4j 部分很简单的,所以先照旧讲讲那些“因缘际会”的事。

细数过往,已经用 Gephi 搞过好几次关系图谱,相对于微博转发图谱和知乎大V关注图谱的中规中矩(见于:Gephi绘制微博转发图谱:以“@老婆孩子在天堂”为例374名10万+知乎大V(一):相互关注情况),拿自己的日记进行分析就显得别出心裁、令人眼前一亮,算得上自己蛮中意的作品,虽然技术细节非常粗糙(见于:2017,那些出现在日记中的人:简单的文本挖掘)。不过回头看来,这几个的数据格式完全可以无缝应用到 neo4j 里,感兴趣的朋友可以去微博转发图谱一文里领取数据并实现一波。

而说是“新近”其实也是半年前安利的红楼梦人物关系及事件的可视化图谱,才是正儿八经用到 neo4j 的,当初自己也曾兴致高昂地分析了下支撑该项目的json数据,手动写了稍显复杂的函数来提取“私通”相关的人物关系链,现在看来 neo4j 一行代码就能解决。(见于:安利一个惊艳的红楼梦可视化作品左手读红楼梦,右手写BUG,闲快活

def word2id(word):
df = edges_df[edges_df.label== word]
from_id = df['from'].values.tolist()
to_id = df['to'].values.tolist()
return from_id, to_id def id2label(ids):

tables = []

for ID in ids:

tables.append(person_df[person_df['id']==ID])

labels = pd.concat(tables)['label'].values.tolist()

return labels def get_relation(from_id,to_id):

for from_label, to_label in zip(id2label(from_id), id2label(to_id)):

print(from_label, '--> {} -->'.format(word), to_label) word = "私通"

from_id,to_id = word2id(word)

get_relation(from_id,to_id)

############################

# 以下为输出结果

贾蔷 --> 私通 --> 龄官

贾珍 --> 私通 --> 秦可卿

贾琏 --> 私通 --> 多姑娘

薛蟠 --> 私通 --> 宝蟾

王熙凤 --> 私通 --> 贾蓉

秦可卿 --> 私通 --> 贾蔷

司棋 --> 私通 --> 潘又安

宝蟾 --> 私通 --> 薛蟠

尤三姐 --> 私通 --> 贾珍

鲍二家的 --> 私通 --> 贾琏

智能儿 --> 私通 --> 秦钟

万儿 --> 私通 --> 茗烟

Neo4j 安装

Neo4j 属于图形数据库,与更广为人知的 MySQL 等关系型数据库不同,其保存的数据格式为节点和节点之间的关系,构建和查询关系数据非常高效便捷。

安装过程可参考:Neo4j 第一篇:在Windows环境中安装Neo4jWindows下安装neo4j,原本想跳过这部分,但因为也遇到几个小问题,所以简单讲下。

  • 安装 Java JDK。因为之前安装 Gephi 时就弄过了,所以本次跳过。

  • Neo4j官网下载最新社区(Community)版本 ,解压到目录,E:\neo4j-file\neo4j-community-3.5.3\

  • 启动Neo4j程序:组合键Windows+R,输入cmd,打开命令行窗口,切换到主目录cd E:\neo4j-file\neo4j-community-3.5.3,以管理员身份运行命令:neo4j.bat console后,会报错。

  • 百度解决方案,在“我的电脑”-“属性”-“高级系统设置”-“环境变量”,将主路径放入系统变量中NEO4J_HOME=E:\neo4j-file\neo4j-community-3.5.3,同时将%NEO4J_HOME%\bin添加到path中,注意英文分号分隔。

  • 接着还有错误:Import-Module : 未能加载指定的模块“\Neo4j-Management.psd1”,于是更改E:\neo4j-file\neo4j-community-3.5.3\bin\neo4j.ps1文件里的Import-Module "$PSScriptRoot\Neo4j-Management.psd1"为绝对路径Import-Module "E:\neo4j-file\neo4j-community-3.5.3\bin\Neo4j-Management.psd1"

  • 保存文件后,重新启用,红色提示消失,运行Neo4j install-service命令,将Neo4j服务安装在系统上。然后运行Neo4j start命令,启动Neo4j。

  • 浏览器中输入 http://localhost:7474 ,便可进入 neo4j 界面,初始登录名和密码均为neo4j,按照提醒修改密码后,便完成了准备工作。

Neo4j 初体验

安装完成后,在以后的岁月里,只需在命令行窗口进入E:\neo4j-file\neo4j-community-3.5.3\bin文件夹,运行neo4j start便可启动

neo4j,然后打开网址http://localhost:7474,输入初始登录名和密码均neo4j或修改后的密码即可。

cd /d E:
cd E:\neo4j-file\neo4j-community-3.5.3\bin
neo4j start

接着便可以用 Cypher 查询语言(CQL,像Oracle数据库具有查询语言SQL,Neo4j具有CQL作为查询语言)创建节点和关系。可阅读w3cschool的教程 快速入门:Neo4j - CQL简介

下面是一些入门的语句,简单了解下,后面实现明星关系图谱就够用了。

# 创建具有带属性(name ,age)的 People 节点
create(p:People{name:"Alex", age:20}); create(p:People{name:"Tom", age:22}); # 匹配 People节点,并返回其 name 和 age 属性

match (p:People) return p.name, p.age # 匹配所有 age 为20的 People 节点

match (p:People{age:20}) RETURN p # 创建 Alex 和 Tom 之间单向的 Friend 关系

create(:People{name:"Alex", age:20})-[r:Friends]->(:People{name:"Tom", age:22}) #

match p=()-[r:RELATION]->() return p LIMIT 25 # 匹配所有节点并查看其中25个

match (n) return n LIMIT 25; # 简单粗暴删除所有节点及节点相关的关系

match (n) detach delete n

数据爬取

爬虫部分不进行过多讲解,一直翻页直到获取全部9141条明星姓名及个人主页链接即可。完整代码见于:DesertsX/gulius-projects

另外提取了明星图片链接等信息,本次没用到,可以忽略的,但如果能在关系图谱中加入人物图片,效果会更佳,只是还不知道如何实现。

import time
import random
import requests
from lxml import etree
import pandas as pd
from fake_useragent import UserAgent ylq_all_star_ids = pd.DataFrame(columns = ['num', 'name', 'star_id', 'star_url', 'image'])

total_pages=153

for page in range(1, total_pages+1):

ua = UserAgent()

url = 'http://www.ylq.com/star/list-all-all-all-all-all-all-all-{}.html'

r = requests.get(url=url.format(page), headers=headers)

r.encoding = r.apparent_encoding

dom = etree.HTML(r.text)
<span class="hljs-comment"># 'http://www.ylq.com/neidi/xingyufei/'</span>
star_urls = dom.xpath(<span class="hljs-string">'//div[@class="fContent"]/ul/li/a/@href'</span>)
star_ids = [star_url.split(<span class="hljs-string">'/'</span>)[<span class="hljs-number">-2</span>] <span class="hljs-keyword">for</span> star_url <span class="hljs-keyword">in</span> star_urls]
star_names = dom.xpath(<span class="hljs-string">'//div[@class="fContent"]/ul/li/a/h2/text()'</span>)
star_images = dom.xpath(<span class="hljs-string">'//div[@class="fContent"]/ul/li/a/img/@src'</span>) print(page, len(star_urls), len(star_ids), len(star_images), len(star_names)) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(star_ids)):
ylq_all_star_ids = ylq_all_star_ids.append({<span class="hljs-string">'num'</span>:int((page<span class="hljs-number">-1</span>)*<span class="hljs-number">60</span>+i+<span class="hljs-number">1</span>), <span class="hljs-string">'name'</span>: star_names[i],
<span class="hljs-string">'star_id'</span>:star_ids[i], <span class="hljs-string">'star_url'</span>: star_urls[i],
<span class="hljs-string">'image'</span>:star_images[i]},ignore_index=<span class="hljs-keyword">True</span>)
<span class="hljs-comment"># if page%5 == 0:</span>
<span class="hljs-comment"># time.sleep(random.randint(0,2))</span>

print("爬虫结束!")

验收下数据,没问题。

由于并不是多有明星的个人主页都含有“明星关系”的数据,所有筛选出含关系数据的1263条链接。注意这部分比较耗时,可自行优化加速,后续有空再改进。

star_has_relations = []
for num, url in enumerate(star_urls):
ua = UserAgent()
headers ={"User-Agent": ua.random,
'Host': 'www.ylq.com'}
try:
r = requests.get(url=url, headers =headers, timeout=5)
r.encoding = r.apparent_encoding
    <span class="hljs-keyword">if</span> <span class="hljs-string">'starRelation'</span> <span class="hljs-keyword">in</span> r.text:
star_has_relations.append(url)
print(num, <span class="hljs-string">"Bingo!"</span>, end=<span class="hljs-string">' '</span>)
<span class="hljs-keyword">if</span> num%<span class="hljs-number">100</span>==<span class="hljs-number">0</span>:
print(num, end=<span class="hljs-string">' '</span>)
<span class="hljs-keyword">except</span>:
print(num, star_has_relations)

# if (num+index)%50==0:

# time.sleep(random.randint(0,2))

接着有针对性的爬取这部分关系数据即可,当然爬虫部分可根据自己喜好,合并一些步骤,比如筛选含关系链接与爬取关系数据这个一步到位也可以。

datas = []
ylq_all_star_relations = pd.DataFrame(columns = ['num', 'subject', 'relation', 'object',
'subject_url', 'object_url', 'obeject_image'])
for num, subject_url in enumerate(star_has_relations):
ua = UserAgent()
headers ={"User-Agent": ua.random,
'Host': 'www.ylq.com'}
try:
r = requests.get(url=subject_url, headers =headers, timeout=5)
r.encoding = r.apparent_encoding
dom = etree.HTML(r.text)
subject = dom.xpath('//div/div/div/h1/text()')[0]
relations = dom.xpath('//div[@class="hd starRelation"]/ul/li/a/span/em/text()')
objects = dom.xpath('//div[@class="hd starRelation"]/ul/li/a/p/text()')
object_urls = dom.xpath('//div[@class="hd starRelation"]/ul/li/a/@href')
object_images = dom.xpath('//div[@class="hd starRelation"]/ul/li/a/img/@src')
for i in range(len(relations)):
relation_data = {'num': int(num+1), 'subject': subject, 'relation': relations[i],
'object': objects[i], 'subject_url':subject_url,
'object_url': object_urls[i], 'obeject_image':object_images[i]}
datas.append(relation_data)
ylq_all_star_relations = ylq_all_star_relations.append(relation_data,
ignore_index=True)
print(num, subject, end=' ')
except:
print(num, datas)
# if num%20 == 0:
# time.sleep(random.randint(0,2))
# print(num, 'sleep a moment')

获取的明星关系数据格式如下,后面还考虑到情况,但貌似都可以删减掉,所以在此就不赘述了,完整代码见于:DesertsX/gulius-projects

构建明星关系图谱

如果你对爬虫不感兴趣,只是想知道如何导入现有的csv数据,然后用neo4j构建关系图谱,那么直接从这里开始实践即可,毕竟这次的数据也是无偿提供的。

手动去掉一些无用的列数据后,将ylq_star_nodes.csvylq_star_relations.csv 两个csv文件,放到E:\neo4j-file\neo4j-community-3.5.3\import目录下,然后分别执行下面两个命令,就完成了关系图谱的创建!是的,一秒完成,当然数据量大的话,可能会等上一小会。

LOAD CSV  WITH HEADERS FROM 'file:///ylq_star_nodes.csv' AS data CREATE (:star{starname:data.name, starid:data.id});

LOAD CSV  WITH HEADERS FROM "file:///ylq_star_relations.csv" AS relations

MATCH (entity1:star{starname:relations.subject}) , (entity2:star{starname:relations.object})

CREATE (entity1)-[:rel{relation: relations.relation}]->(entity2)

之后就可以分别查询各种信息了。

# 查某人全部关系
return (:star{starname:"张国荣"})-->();
# 查某人朋友的朋友(5层关系)
match p=(n:star{starname:"张国荣"})-[*..5]->() return p limit 50;
# 查询特定关系
match p=()-[:rel{relation:"旧爱"}]->() return p LIMIT 25;
# 使用函数,查询张国荣与张卫健的最短路径
match p=shortestpath((:star{starname:"张国荣"})-[*..5]->(:star{starname:"张卫健"})) return p;

更多有趣的命令可自行学习和尝试,其他好玩的数据集也可按个人兴趣去耍耍。

      </div>

一文教你用 Neo4j 快速构建明星关系图谱的更多相关文章

  1. 玩转Windows服务系列——使用Boost.Application快速构建Windows服务

    玩转Windows服务系列——创建Windows服务一文中,介绍了如何快速使用VS构建一个Windows服务.Debug.Release版本的注册和卸载,及其原理和服务运行.停止流程浅析分别介绍了Wi ...

  2. Apache Commons CLI官方文档翻译 —— 快速构建命令行启动模式

    昨天通过几个小程序以及Hangout源码学习了CLI的基本使用,今天就来尝试翻译一下CLI的官方使用手册. 下面将会通过几个部分简单的介绍CLI在应用中的使用场景. 昨天已经联系过几个基本的命令行参数 ...

  3. 使用Asp.net WebAPI 快速构建后台数据接口

    现在的互联网应用,无论是web应用,还是移动APP,基本都需要实现非常多的数据访问接口.其实对一些轻应用来说Asp.net WebAPI是一个很快捷简单并且易于维护的后台数据接口框架.下面我们来快速构 ...

  4. 利用Nodejs快速构建应用原型

    利用Nodejs快速构建应用原型 开发一个应用往往需要快速的构建原型,然后在此基础上设计和改进,前端可能立马能看到效果,但是后端业务逻辑不会那么快,这个时候其实我们需要额只是一些模拟数据,所以不需要真 ...

  5. C# Winform 通过FlowLayoutPanel及自定义的编辑控件,实现快速构建C/S版的编辑表单页面

    个人理解,开发应用程序的目的,不论是B/S或是C/S结构类型,无非就是实现可供用户进行查.增.改.删,其中查询用到最多,开发设计的场景也最为复杂,包括但不限于:表格记录查询.报表查询.导出文件查询等等 ...

  6. Java Swing快速构建窗体应用程序

    以前接触java感觉其在桌面开发上,总是不太方便,没有一个好的拖拽界面布局工具,可以快速构建窗体. 最近学习了一下NetBeans IDE 8.1,感觉其窗体设计工具还是很不错的 , 就尝试一下做了一 ...

  7. 【Android】如何快速构建Android Demo

    [Android]如何快速构建Android Demo 简介 在 Android 学习的过程中,经常需要针对某些项目来写一些测试的例子,或者在做一些 demo 的时候,都需要先写 Activity 然 ...

  8. 使用 Responsive Elements 快速构建响应式网站

    Responsive Elements 可以使任何元素来适应和应对他们所占据的区域.这是一个轻量的 JavaScript 库,你可以轻松嵌入到你的项目.元素会更具自己的宽度,自动响应和适应空间的增加或 ...

  9. Winform 通过FlowLayoutPanel及自定义的编辑控件,实现快速构建C/S版的编辑表单页面 z

    http://www.cnblogs.com/zuowj/p/4504130.html 不论是B/S或是C/S结构类型,无非就是实现可供用户进行查.增.改.删,其中查询用到最多,开发设计的场景 也最为 ...

随机推荐

  1. (数论)51NOD 1136 欧拉函数

    对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目.此函数以其首名研究者欧拉命名,它又称为Euler's totient function.φ函数.欧拉商数等.例如:φ(8) = 4(Phi( ...

  2. 【杂文】虚拟键码表(供函数GetAsyncKeyState()使用)

    [杂文]虚拟键码表(供函数GetAsyncKeyState()使用) 什么?你说你不知道 \(GetAsyncKeyState()\) ?\(→\)戳我\(←\) (惊奇的发现 \(0\) ~ \(9 ...

  3. 探寻宝藏 --- 双线DP

    双线DP , 在郑轻的时候 做过 这种双线DP  ,  这是多维DP 应该是比较简单的  但是那个 时间复杂度的优化 始终看不懂 .  先附上代码吧 , 等看懂了再来 , 补充一下 解释  . #in ...

  4. laravel学习一

    Laravel 是一款简洁,优雅的一款框架,可以说是入门TP后的第二款可以选择的框架. 目录部分: app -> 自己写的代码 http -> Controller -> 控制器 b ...

  5. [读书笔记2]《C语言嵌入式系统编程修炼》

    第3章 屏幕操作   3.1 汉字处理 现在要解决的问题是,嵌入式系统中经常要使用的并非是完整的汉字库,往往只是需要提供数量有限的汉字供必要的显示功能.例如,一个微波炉的LCD上没有必要提供显示&qu ...

  6. 51nod 1029 大数除法

    1029 大数除法 基准时间限制:4 秒 空间限制:131072 KB 分值: 160 难度:6级算法题  收藏  关注 给出2个大整数A,B,计算A / B和A Mod B的结果. Input 第1 ...

  7. 在控制台中输出 ASP.NET 网站的跟踪信息

    实现方法: 1. 可以在 C# 代码中调用 System.Diagnostics.Debug.WriteLine() 来实现. 其效果类似于在控制台应用程序中调用 Console.WriteLine( ...

  8. Python安装第三方包(setup.py)

    在github上下载了records文件到本地. 解压文件 cmd切换到文件setup.py的目录下 先执行 python setup.py build 再执行python setup.py inst ...

  9. Asp 循环输出 form 表单提交的数据

    亲测asp提交form表单数据,在接收页面循环输出数据 dim var for each var in request.form response.write var&"=" ...

  10. 专题四:自定义Web浏览器

    前言: 前一个专题介绍了自定义的Web服务器,然而向Web服务器发出请求的正是本专题要介绍的Web浏览器,本专题通过简单自定义一个Web浏览器来简单介绍浏览器的工作原理,以及帮助一些初学者揭开浏览器这 ...