python怎样写一个简单的搜索引擎?
Admin 2021-08-17 群英技术资讯 685 次浏览
这篇文章给大家分享的是有关python怎样做一个简单的搜索引擎的内容,这也是很多学习python的朋友比较感兴趣的一个内容,因此分享一个实例给大家做个参考,一起跟随小编看看吧。
这篇文章,我们将会尝试从零搭建一个简单的新闻搜索引擎当然,一个完整的搜索引擎十分复杂,这里我们只介绍其中最为核心的几个模块。分别是数据模块、排序模块和搜索模块,下面我们会逐一讲解,这里先从宏观上看一下它们之间的工作流程
数据模块的主要作用是爬取网络上的数据,然后对数据进行清洗并保存到本地存储。一般来说,数据模块会采用非定向爬虫技术广泛爬取网络上的数据,以保证充足的数据源。但是由于本文只是演示,所以这里我们仅会采取定向爬虫爬取中国社会科学网上的部分文章素材。而且因为爬虫技术我们之前已经讲过很多,这里就不打算细讲,只是简单说明一下流程
首先我们定义一个数据模块类,名为 DataLoader
,类中有一个核心变量 data
用于保存爬取下来的数据,以及两个相关的接口 grab_data
(爬取数据) 和 save_data
(保存数据到本地)grab_data()
的核心逻辑如下:
1.首先调用 get_entry()
,获取入口链接
def get_entry(self): baseurl = 'http://his.cssn.cn/lsx/sjls/' entries = [] for idx in range(5): entry = baseurl if idx == 0 else baseurl + 'index_' + str(idx) + '.shtml' entries.append(entry) return entries
2.然后调用 parse4links()
,遍历入口链接,解析得到文章链接
def parse4links(self, entries): links = [] headers = { 'USER-AGENT': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' } for entry in entries: try: response = requests.get(url = entry, headers = headers) html = response.text.encode(response.encoding).decode('utf-8') time.sleep(0.5) except: continue html_parser = etree.HTML(html) link = html_parser.xpath('//div[@class="ImageListView"]/ol/li/a/@href') link_filtered = [url for url in link if 'www' not in url] link_complete = [entry + url.lstrip('./') for url in link_filtered] links.extend(link_complete) return links
3.接着调用 parse4datas()
,遍历文章链接,解析得到文章内容
def parse4datas(self, entries): datas = [] headers = { 'USER-AGENT': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' } data_count = 0 for entry in entries: try: response = requests.get(url = entry, headers = headers) html = response.text.encode(response.encoding).decode('utf-8') time.sleep(0.2) except: continue html_parser = etree.HTML(html) title = html_parser.xpath('//span[@class="TitleFont"]/text()') content = html_parser.xpath('//div[@class="TRS_Editor"]//p//text()') content = [cont.replace('\u3000', '').replace('\xa0', '').replace('\n', '').replace('\t', '') for cont in content] content = [cont for cont in content if len(cont) > 30 and not re.search(r'[《|》]', cont)] if len(title) != 0 or len(content) != 0: data_count += 1 datas.append({ 'id' : data_count, 'link': entry, 'cont': '\t'.join(content), 'title': title[0] }) return datas
grab_data()
的核心代码如下:
def grab_data(self): # 获取入口链接 entries = self.get_entry() # 遍历入口链接,解析得到文章链接 links = self.parse4links(entries) # 遍历文章链接,解析得到文章内容 datas = self.parse4datas(links) # 将相关数据写入变量 data self.data = pd.DataFrame(datas)
save_data()
的核心代码如下:
def save_data(self): # 将变量 data 写入 csv 文件 self.data.to_csv(self.data_path, index = None)
至此,我们已经爬取并保存好数据 data
,数据以 DataFrame 形式存储,保存在 csv
文件,格式如下:
|---------------------------------------------------| | id | link | cont | title | |---------------------------------------------------| | page id | page link | page content | page title | |---------------------------------------------------| | ...... | ...... | ...... | ...... | |---------------------------------------------------|
索引模型的主要作用是构建倒排索引 (inverted index),这是搜索引擎中十分关键的一环。一般来说,构建索引的目的就是为了提高查询速度,普通的索引一般是通过文章标识索引文章内容,而倒排索引则正好相反,通过文章内容索引文章标识。具体来说,倒排索引会以文章中出现过的词语作为键,以该词所在的文章标识作为值来构建索引
首先我们定义一个索引模块类,名为 IndexModel
,类中有一个核心变量 iindex
用于保存倒排索引,以及两个相关的接口 make_iindex
(构建索引) 和 save_iindex
(保存索引到本地)make_iindex()
的核心代码如下(具体逻辑请参考注释):
def make_iindex(self): # 读取数据 df = pd.read_csv(self.data_path) # 特殊变量,用于搜索模块 TOTAL_DOC_NUM = 0 # 总文章数量 TOTAL_DOC_LEN = 0 # 总文章长度 # 遍历每一行 for row in df.itertuples(): doc_id = getattr(row, 'id') # 文章标识 cont = getattr(row, 'cont') # 文章内容 TOTAL_DOC_NUM += 1 TOTAL_DOC_LEN += len(cont) # 对文章内容分词 # 并将其变成 {word: frequency, ...} 的形式 cuts = jieba.lcut_for_search(cont) word2freq = self.format(cuts) # 遍历每个词,将相关数据写入变量 iindex for word in word2freq: meta = { 'id': doc_id, 'dl': len(word2freq), 'tf': word2freq[word] } if word in self.iindex: self.iindex[word]['df'] = self.iindex[word]['df'] + 1 self.iindex[word]['ds'].append(meta) else: self.iindex[word] = {} self.iindex[word]['df'] = 1 self.iindex[word]['ds'] = [] self.iindex[word]['ds'].append(meta) # 将特殊变量写入配置文件 self.config.set('DATA', 'TOTAL_DOC_NUM', str(TOTAL_DOC_NUM)) # 文章总数 self.config.set('DATA', 'AVG_DOC_LEN', str(TOTAL_DOC_LEN / TOTAL_DOC_NUM)) # 文章平均长度 with open(self.option['filepath'], 'w', encoding = self.option['encoding']) as config_file: self.config.write(config_file)
save_iindex()
的核心代码如下:
def save_iindex(self): # 将变量 iindex 写入 json 文件 fd = open(self.iindex_path, 'w', encoding = 'utf-8') json.dump(self.iindex, fd, ensure_ascii = False) fd.close()
至此,我们们经构建并保存好索引 iindex
,数据以 JSON 形式存储,保存在 json
文件,格式如下:
{ word: { 'df': document_frequency, 'ds': [{ 'id': document_id, 'dl': document_length, 'tf': term_frequency }, ...] }, ... }
在得到原始数据和构建好倒排索引后,我们就可以根据用户的输入查找相关的内容
具体怎么做呢?
1.首先我们对用户的输入进行分词
2.然后根据倒排索引获取每一个词相关的文章
3.最后计算每一个词与相关文章之间的得分,得分越高,说明相关性越大
这里我们定义一个搜索模块类,名为 SearchEngine
,类中有一个核心函数 search
用于查询搜索
def search(self, query): BM25_scores = {} # 对用户输入分词 # 并将其变成 {word: frequency, ...} 的形式 query = jieba.lcut_for_search(query) word2freq = self.format(query) # 遍历每个词 # 计算每个词与相关文章之间的得分(计算公式参考 BM25 算法) for word in word2freq: data = self.iindex.get(word) if not data: continue BM25_score = 0 qf = word2freq[word] df = data['df'] ds = data['ds'] W = math.log((self.N - df + 0.5) / (df + 0.5)) for doc in ds: doc_id = doc['id'] tf = doc['tf'] dl = doc['dl'] K = self.k1 * (1 - self.b + self.b * (dl / self.AVGDL)) R = (tf * (self.k1 + 1) / (tf + K)) * (qf * (self.k2 + 1) / (qf + self.k2)) BM25_score = W * R BM25_scores[doc_id] = BM25_scores[doc_id] + BM25_score if doc_id in BM25_scores else BM25_score # 对所有得分按从大到小的顺序排列,返回结果 BM25_scores = sorted(BM25_scores.items(), key = lambda item: item[1]) BM25_scores.reverse() return BM25_scores
关于Python如何写一个搜索引擎实例就分享到这里了,虽然上述内容不是网站的代码,但是对大家学如何用Python写搜索引擎具有一定的参考价值和帮助,如果对此感兴趣的朋友,可以了解看看上述的思路讲解。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
大家好,本篇文章主要讲的是Python不同格式打印九九乘法表示例,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下哦,方便下次浏览
在本篇文章里小编给大家整理的是一篇关于python如何建立web服务的相关知识点内容,有需要的朋友们可以参考下。
TFRecord格式的文件存储形式会很合理的帮我们存储数据,本文主要介绍了Tensorflow中TFRecord生成与读取的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
通常,当我们需要对对象的敏感属性或者不希望外部直接访问的属性进行私有化,但是某些时候我们又需要对这些私有属性进行修改,该怎么处理呢,感兴趣的可以了解一下
在一般情况下,语句是顺序执行的:在一个函数的第一条语句,首先执行,然后是第二条,第三条...等等。可能有一种情况,当你需要执行代码块几次或多数。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008