python 爬虫应用——校园网搜索引擎(crawler application——Campus web search engine part-two)(下)

来自 《Python项目案例开发从入门到实战》(清华大学出版社  郑秋生 夏敏捷主编)中爬虫应用——校园网搜索引擎

这一部分的下半节代码内容主要讲的是 网页排名和搜索模块

网页排名采用TF(Term Frequency)/IDF(Inverse Document Frequency)统计。
其中TF意思是词频,表示词条t在文档d中出现的频率。IDF意思是逆文本频率指数,计算公式是 idf = log(N/df),其中N是文档总数,df是包含词条t的文档数量,当有TF(词频)和IDF(逆文档频率)后,将这两个词相乘,就能得到一个词的TF-IDF的值。某个词在文章中的TF-IDF越大,那么一般而言这个词在这篇文章的重要性会越高,所以通过计算文章中各个词的TF-IDF,由大到小排序,排在最前面的几个词,就是该文章的关键词。

注意: 要想这部分的代码运行成功,一定要先看我的博客中前两章的内容 《 python 爬虫应用——校园网搜索引擎(crawler application——Campus web search engine part-one)(上)》 然后生成 viewsdu.db 数据库才可以运行成功。

import sqlite3
import jieba
import urllib
import lxml
import math
from urllib import request
from collections import deque
from bs4 import BeautifulSoup

# 链接已经创建好的数据库(这个在上一篇博客中已经教了如何创建)
conn = sqlite3.connect("viewsdu.db")
# 创建游标对象
c = conn.cursor()
# 计算doc浏览器中的总函数
c.execute('select count (*) from doc')
# fetchall返回的是[(82,)],即文档的条目总数,为了计算IDF中的文档总数
N = 1 + c.fetchall()[0][0]
# target = input('请输入搜索词: ')
target = '校园'
# 将搜索内容粉刺
seggen = jieba.cut_for_search(target)
# 字典,用于存储“文档号: 文档得分”,文档得分越高,表示这个词在这个文档中的重要程度越高
score = {}
for word in seggen:
    print('得到查询词', word)
    # 创建字典,返回的是word在每个文档中出现的次数,即TF词频的结果
    tf = {}
    c.execute('select list from word where term=?', (word,))
    result = c.fetchall()
    if len(result) > 0:
        # 得到当 term=word 时的 list 的值,这里返回的是字符串,如'3 3 4 4 5 5 58 58'
        doclist = result[0][0]
        # 根据空格切割字符串,返回列表如 ['3', '3', '4', '4', '5', '5', '58', '58',]
        doclist = doclist.split(' ')
        # 把字符串转换为整型,返回的是 [3, 3, 4, 4, 5, 5, 58, 58]
        doclist = [int(x) for x in doclist]
        # set是集合,python中的集合主要用来去重,set(doclist)后结果就是 {3, 4, 5, 58},最终df再得到长度4
        df = len(set(doclist))
        # 逆文本频率指数的计算公式,IDF=log(文档总数/包含词条的文档数量)
        idf = math.log(N/df)
        # 计算词频TF,即在某文档中出现的次数,返回的结果是{3:2, 4:2, 5:2, 58:2}
        for num in doclist:
            if num in tf:
                tf[num] = tf[num] + 1
            else:
                tf[num] = 1
        # !!!注意,当你看懂了这个是用字典表示列表中每个字出现的次数的时候,你可以用下面这一行代码替换上面的5行代码,效果一样
        # tf = {i: doclist.count(i) for i in doclist}

        # TF统计结束,现在开始计算score=TF∗IDF
        for num in tf:
            if num in score:
                # 如果该num文档已经有分数了,则累加
                score[num] = score[num] + tf[num]*idf
            else:
                score[num] = tf[num]*idf
# 对score字典按字典的值排序
sortedlist = sorted(score.items(), key=lambda d: d[1], reverse=True)
print('得分列表', sortedlist)

cnt = 0
for num, docscore in sortedlist:
    cnt = cnt + 1
    # 根据num的值在doc浏览器中找到相对应的链接(网址)
    c.execute('select link from doc where id=?', (num,))
    # 得到具体链接的字符串
    url = c.fetchall()[0][0]
    # 输出网址和对应得分
    print(url, '得分: ', docscore)
    try:
        # 打开网页
        response = request.urlopen(url)
        # 可以输出网页内容
        content = response.read().decode('utf-8')
    except:
        print('oops...读取网页出错')
        continue
    # 解析网页输出标题
    soup = BeautifulSoup(content, 'lxml')
    # 得到网页标题
    title = soup.title
    if title is None:
        print('No title')
    else:
        # 
        title = title.text
        print(title)
    # 超过20条则结束,即输出前20条
    if cnt > 20:
        break
if cnt == 0:
    print('无搜索结果')

pass

结果:

原文地址:https://www.cnblogs.com/ttweixiao-IT-program/p/13332311.html