基于Neo4j的NBA球员知识图谱构建
作为一个老JR,老早就像弄一个关于NBA的图谱了。最近尝试使用Neo4j,一直苦于没有大规模的感兴趣的数据,所以就决定自己动手丰衣足食。最后构建出来的东西,为了逼格高一点还是叫“知识图谱”,其实离真正牛逼的图谱还差很远。
由于数据直接爬取的虎扑,所以省去了大量的信息抽取的时间。不得不说一句虎扑还是很程序员友好的,根本没有什么反爬机制,直接上代码,弄到所有球队的名字以及URL,球队详细的信息手懒没爬。每一个球队的所有球员信息都用excel存起来。
# 获取所有球队以及信息
def getTeamUrl():
root = 'https://nba.hupu.com/teams' # 获取所有球队的信息
response = requests.get(root)
text = response.text
soup = BS(text)
h2s = soup.find_all('h2')
teams = []
teamUrls = []
for h2 in h2s:
teams.append(h2.string)
print(teams)
urls = soup.find_all(name='a', attrs={'class':'a_teamlink'})
for url in urls:
teamUrls.append(url.get('href'))
print(teamUrls)
frame = pd.DataFrame(columns=['team','urls'])
frame['team'] = teams
frame['urls'] = teamUrls
frame.to_excel('./data/teamUrls.xlsx')
有了数据就该定义知识图谱的schema了,为了简单就定义了两个entity:球队和球员,一种关系:效力于,球员的属性可以参照虎扑。
之后就将excel中的数据导入neo4j,这部分用了py2neo,直接pip安装就可以。
##连接neo4j数据库,输入地址、用户名、密码
graph = Graph('http://localhost:7474', username='neo4j', password='123456')
# 导入球队的数据
def importTeam():
for root, dirs, files in os.walk('./data'):
for file in files:
team = file.split('.')[0]
node = Node('球队', name=team)
graph.create(node)
print(graph)
py2neo中操作数据库需要三个类就差不多了:
from py2neo import Graph, Node, Relationship
都可以通过Graph.create()直接创建结点或者关系。
导入关系的时候需要考虑NBA是一个商业联盟,球员老被交易,每个人可能会效力几只不同的球队,所以“效力于”这个关系需要添加个时间属性,表示这个球员在某个时间段效力于这支球队。整个过程也就导入球员关系复杂一些。
def importRelation():
for root, dirs, files in os.walk('./data'):
for file in files:
frame = pd.read_excel('./data/'+file)
team = file.split('.')[0]
for i in frame.index:
player = frame.get_value(i,'players')
career = str(frame.get_value(i,'生涯球队')).split()
career_dict = {}
for j in range(int(len(career)/2)):
year = career[j*2]
teamBefore = career[j*2+1]
if teamBefore in career_dict.keys():
career_dict[teamBefore] += (year+' ')
else:
career_dict[teamBefore] = year + ' '
# 最后加入当前效力的球队
if team in career_dict.keys():
career_dict[team] += '2019'
else:
career_dict[team] = '2019'
# 最后创建关系
a = graph.nodes.match('球员', name=player).first()
for key in career_dict.keys():
b = graph.nodes.match('球队',name=key).first()
relat = Relationship(a,'效力于',b)
relat['year'] = career_dict[key].strip()
try:
graph.create(relat)
except:
continue
最后得到497位球员,当然是30支球队,1099条关系。
为了规整做了一个LIMIT,只显示100条关系
至于各种条件查询以后再练习吧,吃饭去咯。