Python实战之手写一个搜索引擎

news2025/1/11 9:18:26

文章目录

    • 一、前言
    • 二、工作流程
    • 三、数据模块
    • 四、索引模块
    • 五、搜索模块
      • 关于Python技术储备
        • 一、Python所有方向的学习路线
        • 二、Python基础学习视频
        • 三、精品Python学习书籍
        • 四、Python工具包+项目源码合集
        • ①Python工具包
        • ②Python实战案例
        • ③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 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

保存图片微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
在这里插入图片描述

二、Python基础学习视频

② 路线对应学习视频

还有很多适合0基础入门的学习视频,有了这些视频,轻轻松松上手Python~在这里插入图片描述
在这里插入图片描述

③练习题

每节视频课后,都有对应的练习题哦,可以检验学习成果哈哈!
在这里插入图片描述
因篇幅有限,仅展示部分资料

三、精品Python学习书籍

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
在这里插入图片描述

四、Python工具包+项目源码合集
①Python工具包

学习Python常用的开发软件都在这里了!每个都有详细的安装教程,保证你可以安装成功哦!
在这里插入图片描述

②Python实战案例

光学理论是没用的,要学会跟着一起敲代码,动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。100+实战案例源码等你来拿!
在这里插入图片描述

③Python小游戏源码

如果觉得上面的实战案例有点枯燥,可以试试自己用Python编写小游戏,让你的学习过程中增添一点趣味!
在这里插入图片描述

五、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
在这里插入图片描述
在这里插入图片描述

六、Python兼职渠道

而且学会Python以后,还可以在各大兼职平台接单赚钱,各种兼职渠道+兼职注意事项+如何和客户沟通,我都整理成文档了。
在这里插入图片描述
在这里插入图片描述
这份完整版的Python全套学习资料已经上传CSDN,朋友们如果需要可以保存图片微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1282187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

淘宝API接口申请指南

一、申请条件数据接口 已注册淘宝账号并完成实名认证;拥有良好的淘宝信用记录;符合淘宝API接口的相关规定。 二、申请流程 登录淘宝账号,进入“卖家中心”页面;点击“我要开店”-“申请应用”,选择“淘宝API”&…

外卖平台推荐算法的优化与实践

目录 引言 一、推荐算法的原理 二、推荐算法的挑战 三、实际案例分析 四、优化推荐算法的策略 五、结论 引言 在当今数字化社会,外卖平台成为了人们生活中不可或缺的一部分。为了提供更加个性化、高效的服务,外卖平台使用推荐算法成为了一项关键技…

分享78个节日PPT,总有一款适合您

分享78个节日PPT,总有一款适合您 78个节日PPT下载链接:https://pan.baidu.com/s/1FKJZsOEsWIQHOPxZ3ddcUw?pwd6666 提取码:6666 Python采集代码下载链接:采集代码.zip - 蓝奏云 学习知识费力气,收集整理更不易…

高效且实用的表单配置方式:低代码表单上传文件后即刻回显

在现代业务处理流程中,表单上传文件功能的实现已经变得日益重要。而对于用户在上传文件后能够即时看到文件名称的需求,更是对于表单设计的一个基本期望。为了满足这一期望,JVS低代码表单提供了一种高效且实用的配置方式,使得文件名…

光环云与亚马逊云科技成功举办“合作伙伴成长峰会:赋能与共赢”活动

光环云作为由光环新网和西云数据所提供的亚马逊云科技中国区域推广计划的授权增值推广商,致力于帮助中国企业更加方便、高效、安全地享受亚马逊云科技云服务,加速数字化转型。 2023年11月29日,光环云携手亚马逊云科技和商礼科技成功举办“合…

数据库管理-第122期 配置Halo数据库(202301204)

数据库管理-第122期 配置Halo数据库(202301204) 在120期完成了HaloDB的安装,那么紧接着就需要对数据库进行具体配置。 1 数据库配置 这里首先说一下我这里数据库的给的硬件配置:2个CPU,16GB内存 1 配置数据库访问控…

LabVIEW远程监控

LabVIEW远程监控 远程监控的应用场景 从办公室远程监控工厂车间的测试设备。 在世界另一端的偏远地区监控客户现场的发电设备。 从公司远程监控外场的产品。 技术更新与方法 自2018年以来,NI对基于Web的应用程序支持大幅增长。一些最初的方法(如Lab…

用CHAT如何写教研室工作总结?

问CHAT:写一份教研室工作总结 CHAT回复:以下是一个教研室工作总结的大纳,具体内容需要根据你们教研室的实际情况进行填充和修改。 教研室XXXX年度工作总结 1. 引言:简要介绍本年度工作总结的目的和主题。 2. 教育教学工作&…

MDK ARM环境下的伪指令的测试

目录 测试目标: 测试代码: 1. start.s 2. align.s 测试结果: 1 .ldr伪指令的测试结果: 2 .align伪操作测试结果: 结果分析: 测试目标: 熟悉ARM处理器的伪指令,本次实验主要来练习ldr伪指令和align…

自动化之旅成功的“秘诀”

原创 | 文 BFT机器人 引言 近年来,随着机器人技术的蓬勃发展,各行各业都向自动化方向进军,自动化已逐渐成为行业发展的必需品,贯穿各行业的各个环节,为各行业的发展提供助力。 然而,自动化是一把双刃剑。在…

【C++11(一)】右值引用以及列表初始化

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C   🔝🔝 C11 1. 前言2. 统一的列表初始化3. initializer…

C++ Easyx 让圆球跟随鼠标移动

目录 下载Easyx 检验 绘制窗口 画圆 响应事件的处理 清除原先绘图 渲染缓冲区 逻辑 代码托管 下载Easyx 在Easyx官网下载大暑版: 检验 写如下代码: 编译运行,如果控制台出现2023字样,代表配置成功: 绘制窗口 进入Eaxy官方网站,点…

【Java 基础】18 I/O流

文章目录 1.基本概念2.字节流3.字符流4.标准输入输出5.最佳实践 I/O流(Input/Output 流)是计算机程序中不可或缺的一部分, 往大了说所有的操作都是IO。Java 提供了强大而灵活的 I/O 框架,支持各种数据的 读取和 写入操作。 1.基…

Pandas操作数据库

一:Pandas读取数据库数据 二:Pandas读取海量数据 三:Pandas向数据库存数据 四:Pandas写入海量数据

docker 可视化工具操作说明 portainer

官网地址 https://docs.portainer.io/start/install-ce/server/docker/linux 1.First, create the volume that Port docker volume create portainer_data2.下载并安装容器 docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restartalways -v /var/run/docker…

web自动化 -- pyppeteer

由于Selenium流行已久,现在稍微有点反爬的网站都会对selenium和webdriver进行识别,网站只需要在前端js添加一下判断脚本,很容易就可以判断出是真人访问还是webdriver。虽然也可以通过中间代理的方式进行js注入屏蔽webdriver检测,但…

自然语言处理:电脑如何理解我们的语言?

☁️主页 Nowl 🔥专栏《机器学习实战》 《机器学习》 📑君子坐而论道,少年起而行之 ​ 文章目录 ​编辑 常见方法 1.基于词典的方法 2.基于计数的方法 基于推理的方法 Bert input_ids attention_mask token_type_ids 结语 在广…

英伟达狂卖50万台GPU!AI爆火背后,是显卡的争夺

据市场跟踪公司Omdia的统计分析,英伟达在第三季度大约卖出了50万台H100和A100 GPU! 此前,Omdia通过英伟达第二季度的销售额,估计其大概卖出了900吨GPU! 大语言模型火爆的背后,英伟达建立起了强大的显卡帝…

分治-归并排序

文章目录 🌞315. 计算右侧小于当前元素的个数🌈1. 题目⛅2. 算法原理🪐3. 代码实现 🌕493. 翻转对🌠1. 题目⭐2. 算法原理🌟3. 代码实现 🌞315. 计算右侧小于当前元素的个数 🌈1. 题…

深圳找工作的网站

深圳吉鹿力招聘网是一家在深圳做的比较好的招聘网站,提供一站式的专业人力资源服务,包括网络招聘、校园招聘、猎头服务、招聘外包、企业培训以及人才测评等。深圳吉鹿力招聘网在深圳的口碑相当好,是一个很好的选择。 深圳找工作用 吉鹿力招聘…