搜索引擎原理模拟

基本原理#

搜索引擎由四部分组成:搜索器、索引器、检索器、用户接口。其运行过程如下:

  • 通过爬虫抓取网页
  • 建立索引数据库
  • 按索引进行排序
  • 处理用户请求,对查找结果排序

其中,网页的分析算法有pagerank,hits等,以下采用pagerank算法

搜索器#

爬取的页面#

为自己乱写了三个页面,便于验证自己的程序和之后的排序算法是否正确。这三个页面的引用关系为

爬虫#

采用scrapy框架
新建爬虫项目:scrapy startproject search
然后进入目录,新建爬虫: scrapy genspider MySearch 爬取的域名,之后可以修改
然后修改spiders/MySearch.py文件
其中start_url是开始爬取的链接,parse函数是爬取后对结果的处理
爬取后,将爬取的页面为以网页链接命名的文件保存在result文件夹中,如下

并且同时生成引用关系的文件result2/reltion.txt,用于保存各个页面间的引用关系,如下第一行为index.html引用了1.html

MySearch.py文件如下#

Copy
import scrapy class MysearchSpider(scrapy.Spider): name = 'MySearch' start_urls = ['http://127.0.0.1/qilinweb/index.html'] url = [] def parse(self, response): name1 = response.url.split('/')[-1] f2 = open('D:/code/python/search/result/' + name1, 'w') # 保存爬取的内容 f2.write(response.url + "\n" + response.text) # 对页面进行分析,提取每一个链接,加入到url中 for href in response.css('a::attr(href)').extract(): if href not in self.url: self.url.append(href) try: name2 = href # 保存页面的引用关系 with open('D:/code/python/search/result2/relation.txt', 'a+') as f: f.write(name2.split('/')[-1] + "," + name1 + "\n") yield scrapy.Request(href, callback=self.parse) # 生成器,对每一个链接再进行爬取 except: continue 然后scrapy crawl MySearch进行爬取

爬取过程

索引器#

因为页面比较简单,就不生成索引,直接对所有爬取保存的页面内容搜索

检索器#

分为检索和排序两部分

检索#

也比较简单,就是直接对所有爬取保存的页面内容搜索,代码在MyUser.py中的一小段
for file in fname:
f = open('D:/code/python/search/result/' + file, 'r')
if str in f.read():
result.append(file)

排序#

采用pagerank算法,因为该算法是静态的,所以在爬取完页面后就可以直接生成各页面的等级,页面等级以字典形式保存在result2/weight.txt中

代码为MyIndex.py中#

算法代码来自知乎https://zhuanlan.zhihu.com/p/81691075
但是感觉原作者算法实现好像有点问题,自己做了一下修改

Copy
# 用于存储图 class Graph(): def __init__(self): self.linked_node_map = {} # 邻接表, self.PR_map = {} # 存储每个节点的入度 self.L = {} # 存每个节点的出度 # 添加节点 def add_node(self, node_id): if node_id not in self.linked_node_map: self.linked_node_map[node_id] = set({}) self.PR_map[node_id] = 0 else: print("这个节点已经存在") # 增加一个从Node1指向node2的边。允许添加新节点 def add_link(self, node1, node2): if node1 not in self.linked_node_map: self.add_node(node1) self.L[node1] = 0 else: self.L[node1] = self.L[node1] + 1 if node2 not in self.linked_node_map: self.add_node(node2) self.L[node2] = 0 else: self.L[node2] = self.L[node2] + 1 self.linked_node_map[node1].add(node2) # 为node1添加一个邻接节点,表示ndoe2引用了node1 # 计算pr def get_PR(self, epoch_num=3, d=0.5): # 配置迭代轮数,以及阻尼系数 for i in range(epoch_num): for node in self.PR_map: # 遍历每一个节点 self.PR_map[node] = (1 - d) + d * sum( [self.PR_map[temp_node] / self.L[temp_node] for temp_node in self.linked_node_map[node]]) # 原始版公式 with open('D:/code/python/search/result2/weight.txt', 'w') as f: f.write(str(self.PR_map)) graph = Graph() with open('D:/code/python/search/result2/relation.txt', 'r') as f: for line in f: node1, node2 = line.strip().split(',') graph.add_link(node1, node2) graph.get_PR()

用户接口#

对输入的内容进行搜索,并且按页面的等级从高到低显示

程序在MyUser.py中

Copy
import os import ast # 按照页面等级排序 def p(s): return str[s] str = input("搜索:") fname = os.listdir(r'D:\code\python\search\result') result = [] for file in fname: f = open('D:/code/python/search/result/' + file, 'r') if str in f.read(): result.append(file) f2 = open('D:/code/python/search/result2/weight.txt', 'r') str = f2.read() str = ast.literal_eval(str) # 将读入的字符串转化为字典类型 show = sorted(result, key=p, reverse=True) print("搜索结果如下\n") print(show)
posted @   启林O_o  阅读(205)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示
CONTENTS