Bootstrap

基于知识图谱的古诗词推荐(python+爬虫+mysql+neo4j)(一)

基于知识图谱的古诗词推荐-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)(二)

;