最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python實戰(zhàn)之手寫一個搜索引擎

 更新時間:2021年04月28日 09:24:27   作者:半虹  
這篇文章主要介紹了Python實戰(zhàn)之手寫一個搜索引擎,文中有非常詳細的代碼示例,對正在學習python的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、前言

這篇文章,我們將會嘗試從零搭建一個簡單的新聞搜索引擎

當然,一個完整的搜索引擎十分復雜,這里我們只介紹其中最為核心的幾個模塊

分別是數(shù)據(jù)模塊、排序模塊和搜索模塊,下面我們會逐一講解,這里先從宏觀上看一下它們之間的工作流程

二、工作流程

在這里插入圖片描述

三、數(shù)據(jù)模塊

數(shù)據(jù)模塊的主要作用是爬取網(wǎng)絡上的數(shù)據(jù),然后對數(shù)據(jù)進行清洗并保存到本地存儲

一般來說,數(shù)據(jù)模塊會采用非定向爬蟲技術廣泛爬取網(wǎng)絡上的數(shù)據(jù),以保證充足的數(shù)據(jù)源

但是由于本文只是演示,所以這里我們僅會采取定向爬蟲爬取中國社會科學網(wǎng)上的部分文章素材

而且因為爬蟲技術我們之前已經(jīng)講過很多,這里就不打算細講,只是簡單說明一下流程

首先我們定義一個數(shù)據(jù)模塊類,名為 DataLoader,類中有一個核心變量 data 用于保存爬取下來的數(shù)據(jù)

以及兩個相關的接口 grab_data (爬取數(shù)據(jù)) 和 save_data (保存數(shù)據(jù)到本地)

grab_data() 的核心邏輯如下:

1.首先調(diào)用 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.然后調(diào)用 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.接著調(diào)用 parse4datas(),遍歷文章鏈接,解析得到文章內(nèi)容

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)
    # 遍歷文章鏈接,解析得到文章內(nèi)容
    datas = self.parse4datas(links)
    # 將相關數(shù)據(jù)寫入變量 data
    self.data = pd.DataFrame(datas)

save_data() 的核心代碼如下:

def save_data(self):
    # 將變量 data 寫入 csv 文件
    self.data.to_csv(self.data_path, index = None)

至此,我們已經(jīng)爬取并保存好數(shù)據(jù) data,數(shù)據(jù)以 DataFrame 形式存儲,保存在 csv 文件,格式如下:

|---------------------------------------------------|
|    id    |     link   |     cont     |    title   |
|---------------------------------------------------|
|  page id |  page link | page content | page title |
|---------------------------------------------------|
|  ......  |   ......   |    ......    |   ......   |
|---------------------------------------------------|

四、索引模塊

索引模型的主要作用是構建倒排索引 (inverted index),這是搜索引擎中十分關鍵的一環(huán)

一般來說,構建索引的目的就是為了提高查詢速度

普通的索引一般是通過文章標識索引文章內(nèi)容,而倒排索引則正好相反,通過文章內(nèi)容索引文章標識

具體來說,倒排索引會以文章中出現(xiàn)過的詞語作為鍵,以該詞所在的文章標識作為值來構建索引

首先我們定義一個索引模塊類,名為 IndexModel,類中有一個核心變量 iindex 用于保存倒排索引

以及兩個相關的接口 make_iindex (構建索引) 和 save_iindex (保存索引到本地)

make_iindex() 的核心代碼如下(具體邏輯請參考注釋):

def make_iindex(self):
    # 讀取數(shù)據(jù)
    df = pd.read_csv(self.data_path)
    # 特殊變量,用于搜索模塊
    TOTAL_DOC_NUM = 0 # 總文章數(shù)量
    TOTAL_DOC_LEN = 0 # 總文章長度
    # 遍歷每一行
    for row in df.itertuples():
        doc_id = getattr(row, 'id') # 文章標識
        cont = getattr(row, 'cont') # 文章內(nèi)容

        TOTAL_DOC_NUM += 1
        TOTAL_DOC_LEN += len(cont)

        # 對文章內(nèi)容分詞
        # 并將其變成 {word: frequency, ...} 的形式
        cuts = jieba.lcut_for_search(cont)
        word2freq = self.format(cuts)

        # 遍歷每個詞,將相關數(shù)據(jù)寫入變量 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)) # 文章總數(shù)
    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()

至此,我們們經(jīng)構建并保存好索引 iindex,數(shù)據(jù)以 JSON 形式存儲,保存在 json 文件,格式如下:

{
    word: {
        'df': document_frequency,
        'ds': [{
            'id': document_id,
            'dl': document_length,
            'tf': term_frequency
        }, ...]
    },
    ...
}

五、搜索模塊

在得到原始數(shù)據(jù)和構建好倒排索引后,我們就可以根據(jù)用戶的輸入查找相關的內(nèi)容

具體怎么做呢?

1.首先我們對用戶的輸入進行分詞

2.然后根據(jù)倒排索引獲取每一個詞相關的文章

3.最后計算每一個詞與相關文章之間的得分,得分越高,說明相關性越大

這里我們定義一個搜索模塊類,名為 SearchEngine,類中有一個核心函數(shù) 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實戰(zhàn)之手寫一個搜索引擎的文章就介紹到這了,更多相關Python寫搜索引擎內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 利用Python中的mock庫對Python代碼進行模擬測試

    利用Python中的mock庫對Python代碼進行模擬測試

    這篇文章主要介紹了利用Python中的mock庫對Python代碼進行模擬測試,mock庫自從Python3.3依賴成為了Python的內(nèi)置庫,本文也等于介紹了該庫的用法,需要的朋友可以參考下
    2015-04-04
  • python文件特定行插入和替換實例詳解

    python文件特定行插入和替換實例詳解

    這篇文章主要介紹了python文件特定行插入和替換實例詳解的相關資料,需要的朋友可以參考下
    2017-07-07
  • python3實現(xiàn)多線程聊天室

    python3實現(xiàn)多線程聊天室

    這篇文章主要為大家詳細介紹了python3實現(xiàn)多線程聊天室,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Python 使用tempfile包輕松無痕的運行代碼

    Python 使用tempfile包輕松無痕的運行代碼

    大家好,我們知道軟件運行過程中一般會在指定位置生成臨時文件,這些資源不要輕易刪除,可能是過程文件,定時清理是必要的,今天給大家分享一款工具:tempfile,喜歡本文點贊支持,歡迎收藏學習
    2021-11-11
  • Windows中安裝使用Virtualenv來創(chuàng)建獨立Python環(huán)境

    Windows中安裝使用Virtualenv來創(chuàng)建獨立Python環(huán)境

    有時我們的程序中需要調(diào)用不同版本的Python包和模塊,那么借助Virtualenv的虛擬環(huán)境就可以幫助我們隔離使用,接下來我們就來看一下在Windows中安裝使用Virtualenv來創(chuàng)建獨立Python環(huán)境的方法
    2016-05-05
  • Python+OpenCV圖片局部區(qū)域像素值處理詳解

    Python+OpenCV圖片局部區(qū)域像素值處理詳解

    這篇文章主要為大家詳細介紹了Python+OpenCV圖片局部區(qū)域像素值處理,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • python基礎教程項目三之萬能的XML

    python基礎教程項目三之萬能的XML

    這篇文章主要為大家詳細介紹了python基礎教程項目三之萬能的XML,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • 詳解python3中socket套接字的編碼問題解決

    詳解python3中socket套接字的編碼問題解決

    本篇文章主要介紹了詳解python3中socket套接字的編碼問題解決,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 利用python如何處理百萬條數(shù)據(jù)(適用java新手)

    利用python如何處理百萬條數(shù)據(jù)(適用java新手)

    這篇文章主要給大家介紹了關于利用python如何處理百萬條數(shù)據(jù)的相關資料,本文的教程非常適用于java新手,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧
    2018-06-06
  • python中的 zip函數(shù)詳解及用法舉例

    python中的 zip函數(shù)詳解及用法舉例

    zip()是Python的一個內(nèi)建函數(shù),它接受一系列可迭代的對象作為參數(shù),將對象中對應的元素打包成一個個tuple(元組),然后返回由這些tuples組成的list(列表)。這篇文章主要介紹了python中的 zip函數(shù)詳解及用法舉例,需要的朋友可以參考下
    2020-02-02

最新評論

临湘市| 昔阳县| 眉山市| 霍城县| 临澧县| 南宁市| 长葛市| 广水市| 章丘市| 宁津县| 建瓯市| 潢川县| 灌南县| 阜新市| 玛多县| 横山县| 云龙县| 三台县| 太康县| 阿拉善盟| 和林格尔县| 横山县| 普安县| 石首市| 高密市| 兴城市| 丹凤县| 垦利县| 祁连县| 汨罗市| 湘西| 宁都县| 宝坻区| 通城县| 甘德县| 泰顺县| 勐海县| 丰宁| 岑溪市| 迭部县| 成安县|