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
结果: