更多有趣项目及代码见于: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. 赋予option元素点击事件后,点击select时却触发了option事件。如何解决?

    将select的优先级提到option之前就可以了. 方法:为select元素添加position:relative: <select class="adt" name=&q ...

  2. [Swift通天遁地]一、超级工具-(6)通过JavaScript(脚本)代码调用设备的源生程序

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  3. python程序展现图片

    突然想写一个python程序能够显示图片的 ,展示文字的已经实现了 现在就搞一搞这个吧 相信也是很简单 首先是放一张图片在e盘下面 等会程序打包的时候将会用到 就决定是你啦 皮卡丘: 然后就写代码吧:

  4. php数据类型的转换

    1.强制类型的转换 setType('变量','值') 值:可以是8大数据类型的任何一种 变量:(8大数据类型)需要转换的变量 $var="123abc"; setType($va ...

  5. sql server nullif的使用技巧,除数为零的处理技巧

    在sql server中做除法处理的时候,我们经常需要处理除数为零的情况,因为如果遇到这种情况的时候,sqlserver会抛出遇到以零作除数错误的异常,我们总不希望把这个异常显示给用户吧. 做个会报这 ...

  6. 外观模式(Facade)-子系统的协作与整合-接口模式

    对子系统进行整合,对外提供更强大或更便捷的接口. 在一个模块和几个子系统进行通信时考虑. 什么是外观模式? 外观模式(Facade),为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口 ...

  7. MySql学习笔记(三) —— 聚集函数的使用

    1.AVG() 求平均数 select avg(prod_price) as avg_price from products; --返回商品价格的平均值 ; --返回生产商id为1003的商品价格平均 ...

  8. pl/sql编程语言

    –pl/sql编程语言–pl/sql编程语言是对sql语言的扩展,是的sql语言具有过程化编程的特性–pl/sql编程语言比一般的过程化编程语言,更加灵活高效–pl/sql编程语言主要用来编写存储过程 ...

  9. kdump机制和crash常见使用

    kdump简介 kdump是系统崩溃的时候,用来转储运行内存的一个工具. 系统一旦崩溃,内核就没法正常工作了,这个时候将由kdump提供一个用于捕获当前运行信息的内核, 该内核会将此时内存中的所有运行 ...

  10. 运行jar包的命令

    windows下使用java -jar xxx.jar运行,linux下使用nohup java -jar xxx.jar & 如果想停止jar运行,ps -ef查看进程(进程多的话也可以加上 ...