基于知识图谱的古诗词推荐-python+爬虫+mysql+neo4j(一)
这是个人最近大创项目的成果,整理一下发出来。第一次写文
数据准备
https://www.xungushici.com/
这个网站内容还较为丰富,并且好像没有反爬,新手党的福音啊,我在最后爬取古诗的时候,连续访问了几万次都没有被封ip,简直了。
一开始学爬虫的时候,都是使用BeautifulSoup和re的组合,但是对文本爬取的效率极低(是我不会用),后来就用Xpath语法了,贼快。
import requests
from lxml import etree #导入相应的包
url='https://www.xungushici.com/shici/1' #输入我们的url
get = requests.get(url).text # get(url) 得到我们的网页, text将源网页转化为字符串
selector = etree.HTML(get) # 将源码转换为xpath可以识别的TML格式
接下来就是找到要爬取的内容的xpath路径
用浏览器(我的是chrome)打开网页https://www.xungushici.com/shici/1,按一下F12进入查看源码,找到要爬取的内容在源码的位置,以标题为例,对着内容点击右键,然后移到copy选项上,选择copy xpath,相应内容的xpath就会复制了
#/html/body/div/div/div[1]/div[1]/div/h3 #这是最初复制出来的xpath
#//html/body/div/div/div[1]/div[1]/div/h3/text()#将它添头加尾
selector.xpath('//html/body/div/div/div[1]/div[1]/div/h3/text()')#获取标题的内容
运行之后发现出来的是列表
那就改一下
selector.xpath('//html/body/div/div/div[1]/div[1]/div/h3/text()')[0]
所以要耐心的实验和细心的观察
标题搞定,朝代和作者都是类似的。
但是正文又不一样了
它的每一句诗词都是分开的,也不能一个一个复制xpath,那会go die 的,观察一下它的第一句的xpath
#/html/body/div/div/div[1]/div[1]/div/div[1]/text()[1]
那我们就可以猜出它的整首诗的xpath因该是
#/html/body/div/div/div[1]/div[1]/div/div[1]/text()
(如果熟悉xpath语法的话,当我没说)
selector.xpath('//html/body/div/div/div[1]/div[1]/div/div[1]/text()')
添头加尾就可以获取正文了
发现是一个列表,那我们可以用join把它们给串起来
''.join(selector.xpath('//html/body/div/div/div[1]/div[1]/div/div[1]/text()'))
获取内容的过程就差不多了,为了方便之后的写代码,我们可以采取字典的形式把各个xpath给组织起来
Xpath={'标题':'/html/body/div/div/div[1]/div[1]/div/h3',
'朝代':'/html/body/div/div/div[1]/div[1]/div/p/a[1]',
'作者':'/html/body/div/div/div[1]/div[1]/div/p/a[2]',
'正文':'/html/body/div/div/div[1]/div[1]/div/div[1]',#需要合并
'译文':'/html/body/div/div/div[1]/div[2]/div[2]/p[4]',#需要合并
'注释':'/html/body/div/div/div[1]/div[2]/div[2]/p[4]',
'赏析':'/html/body/div/div/div[1]/div[3]/div[2]/p[%d]',
'创作背景':'/html/body/div/div/div[1]/div[4]/div[2]/p',
'关于诗人':'/html/body/div/div/div[2]/div[2]/div[2]/p'}
Xpath_keys=['标题', '朝代', '作者', '正文','译文', '注释', '赏析', '创作背景','关于诗人']
最后获得的诗也用字典存储,爬取一首诗的完整代码
import requests
from lxml import etree
url='https://www.xungushici.com/shici/1' #输入我们的url
get = requests.get(url).text # get(url) 得到我们的网页, text将源网页转化为字符串
selector = etree.HTML(get) # 将源码转换为xpath可以识别的TML格式
Xpath={'标题':'/html/body/div/div/div[1]/div[1]/div/h3',
'朝代':'/html/body/div/div/div[1]/div[1]/div/p/a[1]',
'作者':'/html/body/div/div/div[1]/div[1]/div/p/a[2]',
'正文':'/html/body/div/div/div[1]/div[1]/div/div[1]',#需要合并
'译文':'/html/body/div/div/div[1]/div[2]/div[2]/p[4]',#需要合并
'注释':'/html/body/div/div/div[1]/div[2]/div[2]/p[4]',
'赏析':'/html/body/div/div/div[1]/div[3]/div[2]/p[%d]',
'创作背景':'/html/body/div/div/div[1]/div[4]/div[2]/p',
'关于诗人':'/html/body/div/div/div[2]/div[2]/div[2]/p'}
Xpath_keys=['标题', '朝代', '作者', '正文','译文', '注释', '赏析', '创作背景','关于诗人']
content={}
for i in range(9):
if i in [3,4,5]:
ls=[]
ls=selector.xpath('/'+Xpath[Xpath_keys[i]]+'/text()')
content[Xpath_keys[i]] = ''.join(ls)
elif i==6:
ls=[]
for j in range(1,17):
path='/html/body/div/div/div[1]/div[3]/div[2]/p[%d]'%j
ls+=selector.xpath('/'+path+'/text()')
content[Xpath_keys[i]] = ''.join(ls)
else:
content[Xpath_keys[i]] = selector.xpath('/'+Xpath[Xpath_keys[i]]+'/text()')[0]
print(content)
可以看到已经爬取成功了
现在就考虑批量爬取了
urls=['https://www.xungushici.com/shici/%d'%p for p in range(1,20001)]#用列表生成表达式批量产生链接
用列表生成表达式批量产生链接,因为不同的页面的链接就最后一个数字不同
因为不是每个链接都是能爬取成功的,所以用try except捕捉异常
import requests
from lxml import etree
ls1=[]
k = 0
p = 0
for count in range(0,20000):
try:
get = requests.get(urls[count]).text # get(url) 得到我们的网页, text将源网页转化为字符串
selector = etree.HTML(get) # 将源码转换为xpath可以识别的TML格式
Xpath={'标题':'/html/body/div/div/div[1]/div[1]/div/h3',
'朝代':'/html/body/div/div/div[1]/div[1]/div/p/a[1]',
'作者':'/html/body/div/div/div[1]/div[1]/div/p/a[2]',
'正文':'/html/body/div/div/div[1]/div[1]/div/div[1]',#需要合并
'译文':'/html/body/div/div/div[1]/div[2]/div[2]/p[2]',#需要合并
'注释':'/html/body/div/div/div[1]/div[2]/div[2]/p[4]',
'赏析':'/html/body/div/div/div[1]/div[3]/div[2]/p[%d]',
'创作背景':'/html/body/div/div/div[1]/div[4]/div[2]/p',
'关于诗人':'/html/body/div/div/div[2]/div[2]/div[2]/p'}
Xpath_keys=['标题', '朝代', '作者', '正文','译文', '注释', '赏析', '创作背景','关于诗人']
content={}
content['pome_id']=count+1#将页面链接最后的数字保存
for i in range(9):
if i in [3,4,5]:
ls=[]
ls=selector.xpath('/'+Xpath[Xpath_keys[i]]+'/text()')
if i==3:
content[Xpath_keys[i]] = '\n'.join(ls)
else:
content[Xpath_keys[i]] = ''.join(ls)
elif i==6:
ls=[]
for j in range(1,17):
path='/html/body/div/div/div[1]/div[3]/div[2]/p[%d]'%j
ls+=selector.xpath('/'+path+'/text()')
content[Xpath_keys[i]] = ''.join(ls)
else:
content[Xpath_keys[i]] = selector.xpath('/'+Xpath[Xpath_keys[i]]+'/text()')[0]
flag = True
for i in range(9):
if len(content[Xpath_keys[i]].split()) == 0:
flag = False
if flag:
k += 1
ls1.append(content)
print("下载的数量:%d 诗的编号%d"%(k,content['pome_id']))
except:
p+= 1
print("pass:%d"%p)
pass
效果图:(机子慢,这个代码跑了将近一个小时)
至此就将所有古诗都进行爬取了,但是只是存进了列表ls1中,并没有下载下来,下一步就是将列表中的数据存入excl中,采用xlwt+pandas
import xlwt
import pandas as pd
def export_excel(export):
#将字典列表转换为DataFrame
pf = pd.DataFrame(list(export))
#指定字段顺序
order = ['pome_id','标题', '朝代', '作者', '正文','译文', '注释', '赏析', '创作背景','关于诗人']
pf = pf[order]
columns_map = {
'pome_id':'pome_id',
'标题':'标题',
'朝代':'朝代',
'作者':'作者',
'正文':'正文',
'译文':'译文',
'注释':'注释',
'赏析':'赏析',
'创作背景':'创作背景',
'关于诗人':'关于诗人'
}
pf.rename(columns =columns_map ,inplace = True)
#指定生成的Excel表格名称
file_path = pd.ExcelWriter('name7.xlsx')
#替换空单元格
pf.fillna(' ',inplace = True)
#输出
pf.to_excel(file_path,encoding = 'utf-8',index = False)
#保存表格
file_path.save()
if __name__ == '__main__':
#将分析完成的列表导出为excel表格
export_excel(ls1)
至此数据准备阶段基本完成了(需要最后的数据的可以告诉我一下)
太晚了,之后再写吧,整理一下发现要用到的东西也是挺多的
下一篇应该是将数据导入进数据库
基于知识图谱的古诗词推荐(python+爬虫+mysql+neo4j)(二)