python实现简易搜索引擎

不想你离开。 提交于 2019-11-27 16:37:33
搜索引擎课程大作业,老师给了几百份带标签的文档,用来做搜索引擎的查询内容,最后查了半天资料决定用python做。基本上就是预处理(去标签)——分词构建索引——查询三个部分。预处理比较简单,把文档的HTML标签去除,不过这里遇到个坑,那就是这些文档里面由好几种编码格式,所以只能解码后重新用utf-8编码,否则会出现乱码,然后为每一个文档建立目录文件(方便查询之后溯源),分词的话就是用jieba包将新闻进行分词,然后用sqlite3 做数据库构建索引。

最后查询模块就相当于在数据库里面查了,排序用的是TF-IDF,对于小型搜索引擎效率还行。

因为当时交作业比较急,参考了网上的资料,有些地方还有些简陋,仅供参考。

代码如下:

预处理:

import os
import sys
import re
import chardet


#扫描文件夹下面所有的文件,并保存在文件目录备份表中
lujing=input("请输入文件夹路径:")
def GetFileList(dir, fileList):
    newDir = dir
    if os.path.isfile(dir):         # 如果是文件则添加进 fileList
        fileList.append(dir)
    elif os.path.isdir(dir):
        for s in os.listdir(dir):   # 如果是文件夹
            newDir = os.path.join(dir, s)
            GetFileList(newDir, fileList)
    return fileList
# 主函数
# 重定向输出位置
output = sys.stdout
outputfile = open('lujing.txt', 'w')
sys.stdout = outputfile
list = GetFileList(lujing, []) # 获取所有myFolder文件夹下所有文件名称(包含拓展名)
# 输出所有文件夹中的路径(相对于当前运行的.py文件的相对路径)
for route in list:
    # route 为路径
    print(route)
# 关闭输出重定向
outputfile.close()
sys.stdout = output


#将生成的路径文件lujing.txt读取,并按照路径文件对文本处理,去标签
for line in open("lujing.txt"):
    print(line)
    #line=line[0:-2]
    line1=line[0:12]
    line2=line[13:16]
    line3=line[17:-1]
    line4=line[17:-6]
    line=line1+'\\'+line2+'\\'+line3
    print(line4)
    path=line
    fb=open(path,"rb")
    data = fb.read()
    bianma = chardet.detect(data)['encoding']#获取当前文件的编码方式,并按照此编码类型处理文档
    page=open(line,'r',encoding=bianma,errors='ignore').read()
    dr = re.compile(r'<[^>]+>', re.S)#去HTML标签
    dd = dr.sub('', page)
    print(dd)
    fname='TXT'+"\\"+line4+ ".txt"
    #print(fname)
    f = open(fname, "w+", encoding=bianma)#将去标签的文件写到文件夹内,并按照原命名以txt文档方式保存
    #fo=open(fname,"w+")
    f.write(dd)

分词索引:

import jieba
import chardet
import sqlite3
import importlib,sys
importlib.reload(sys)

conn = sqlite3.connect('suoyin.db3')
conn.text_factory = str

c = conn.cursor()
# 当已存在数据库的时候,需要将表删除,若不存在或第一次运行,则需要注释掉
c.execute('drop table doc')
c.execute('create table doc (id int primary key,link text)')
c.execute('drop table word')
c.execute('create table word (term varchar(25) primary key,list text)')
conn.commit()
conn.close()

def Fenci():
    num = 0
    for line in open("lujing.txt"):
        lujing=line
        print(1111111)
        print(lujing)
        num += 1
        print(line)
        line=line[17:-5]
        print(line)
        #line1 = line[0:3]
        #print(line1)
        #line2 = line[4:-1]
        #print(line2)
        line = 'TXT' + '\\' + line+'Txt'#line为文件位置
        print(line)#文件名称
        path = line
        fb = open(path, "rb")
        data = fb.read()
        bianma = chardet.detect(data)['encoding']#获取文件编码        print(bianma)
        #page = open(line, 'r', encoding=bianma, errors='ignore').read()

        #page1=page.decode('UTF-8')
        if bianma=='UTF-16':
            data = data.decode('UTF-16')
            data = data.encode('utf-8')
        word=jieba.cut_for_search(data)
        seglist = list(word)
        print(seglist)

        conn = sqlite3.connect('suoyin.db3')  # 创建数据库
        c = conn.cursor()  # 创建游标
        c.execute('insert into doc values(?,?)', (num,lujing))
       # 对每个分出的词语建立词表
        for word in seglist:
            #print(word)
        # 检验看看这个词语是否已存在于数据库
            c.execute('select list from word where term=?', (word,))
            result = c.fetchall()
        # 如果不存在
            if len(result) == 0:
                docliststr = str(num)
                c.execute('insert into word values(?,?)', (word, docliststr))
        # 如果已存在
            else:
                docliststr = result[0][0]  # 得到字符串
                docliststr += ' ' + str(num)
                c.execute('update word set list=? where term=?', (docliststr, word))
        conn.commit()
        conn.close()

Fenci()

查询:

import sqlite3
import jieba
import math

conn=sqlite3.connect("suoyin.db3")
c=conn.cursor()
c.execute('select count(*) from doc')
N=1+c.fetchall()[0][0]#文档总数
target=input('请输入搜索词:')
seggen=jieba.cut_for_search(target)
score={}#文档号:匹配度
for word in seggen:
    print('得到查询词:',word)
    #计算score
    tf={}#文档号:文档数
    c.execute('select list from word where term=?',(word,))
    result=c.fetchall()
    if len(result)>0:
        doclist=result[0][0]
        doclist=doclist.split(' ')
        doclist=[int(x) for x in doclist]#把字符串转换为元素为int的list
        df=len(set(doclist))#当前word对应的df数
        idf=math.log(N/df)
        print('idf:',idf)
        for num in doclist:
            if num in tf:
                tf[num]=tf[num]+1
            else:
                tf[num]=1
        #tf统计结束,现在开始计算score
        for num in tf:
            if num in score:
                #如果该num文档已经有分数了,则累加
                score[num]=score[num]+tf[num]*idf
            else:
                score[num]=tf[num]*idf
sortedlist=sorted(score.items(),key=lambda d:d[1],reverse=True)
#print('得分列表',sortedlist)

cnt=0
for num,docscore in sortedlist:
    cnt=cnt+1
    c.execute('select link from doc where id=?',(num,))
    url=c.fetchall()[0][0]
    print("当前关联度排名:",cnt)
    print('文件路径:',url,'匹配度:',docscore)

    if cnt>20:
        break
if cnt==0:
    print('无搜索结果,请更换关键词重试')

文档在我的git上可以下载到,链接放这里了:

https://github.com/pipadawang/search-engine

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!