搜索引擎课程大作业,老师给了几百份带标签的文档,用来做搜索引擎的查询内容,最后查了半天资料决定用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
来源:CSDN
作者:琵琶大王
链接:https://blog.csdn.net/qq_37315051/article/details/80085497