课程设计报告doc.docx
《课程设计报告doc.docx》由会员分享,可在线阅读,更多相关《课程设计报告doc.docx(20页珍藏版)》请在冰点文库上搜索。
课程设计报告doc
计算机科学与工程学院
课程设计报告
题目全称:
搜索引擎之网络蜘蛛
题目难度等级:
4
指导老师:
职称:
学生姓名:
学号:
班号:
设计过程(30分)
课程设计报告(30分)
课程设计程序(40分)
总分
备注:
如参加答辩,请指导教师只给出设计过程30分,课程设计报告、课程设计程序由答辩老师给出。
如参加答辩,请答辩老师签字:
指导老师评语:
指导教师签字:
搜索引擎之网络蜘蛛
1、设计背景与目的:
随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战。
搜索引擎(SearchEngine),例如传统的通用搜索引擎AltaVista,Yahoo!
和Google等,作为一个辅助人们检索信息的工具成为用户访问万维网的入口和指南。
但是,这些通用性搜索引擎也存在着一定的局限性,如:
(1)不同领域、不同背景的用户往往具有不同的检索目的和需求,通用搜索引擎所返回的结果包含大量用户不关心的网页。
(2)通用搜索引擎的目标是尽可能大的网络覆盖率,有限的搜索引擎服务器资源与无限的网络数据资源之间的矛盾将进一步加深。
(3)万维网数据形式的丰富和网络技术的不断发展,图片、数据库、音频、视频多媒体等不同数据大量出现,通用搜索引擎往往对这些信息含量密集且具有一定结构的数据无能为力,不能很好地发现和获取。
(4)通用搜索引擎大多提供基于关键字的检索,难以支持根据语义信息提出的查询。
为了解决上述问题,网络爬虫应运而生。
网络蜘蛛(Webspider)也叫网络爬虫(Webcrawler)[1],蚂蚁(ant),自动检索工具(automaticindexer),或者(在FOAF软件概念中)网络疾走(WEBscutter),是一种“自动化浏览网络”的程序,或者说是一种网络机器人。
它们被广泛用于互联网搜索引擎或其他类似网站,以获取或更新这些网站的内容和检索方式。
它们可以自动采集所有其能够访问到的页面内容,以供搜索引擎做进一步处理(分检整理下载的页面),而使得用户能更快的检索到他们需要的信息。
2、设计原理:
网络爬虫始于一张被称作种子的统一资源地址(URLs)列表。
当网络爬虫访问这些统一资源定位器时,它们会甄别出页面上所有的超链接,并将它们写入一张"待访列表",即所谓"爬行疆域"(crawlfrontier)。
此疆域上的统一资源地址将被按照一套策略循环访问。
如果爬虫在他执行的过程中复制归档和保存网站上的信息,这些档案通常储存,使他们可以被查看。
阅读和浏览他们的网站上实时更新的信息,并保存为网站的“快照”。
大容量的体积意味着网络爬虫只能在给定时间内下载有限数量的网页,所以要优先考虑其下载。
高变化率意味着网页可能已经被更新或者删除。
一些被服务器端软件生成的URLs(统一资源定位符)也使得网络爬虫很难避免检索到重复内容。
基于目标数据模式的爬虫针对的是网页上的数据,所抓取的数据一般要符合一定的模式,或者可以转化或映射为目标数据模式。
3、设计内容:
通过winsocket编程,读取指定网页信息。
然后采用广度优先算法搜索该网页上面的链接地址(搜索深度不超过3),将网页数据的标题和正文内容及网址存储到文件中。
详细功能描述:
使用python3语言编写网络爬虫,建立图形界面,输入目标链接地址以及存储地址以及搜索深度(不超过3),执行搜索访问,并扩展至该链接上的其他链接,经过简单筛选将正文内容和标题存储在文件中。
支持以及几个操作:
链接框:
输入初始链接
路径框:
输入存储路径
路径选择:
在计算机中选择存储文件(爬下来资料)的放置位置
深度选择:
选择深度在1~3范围内的搜索
执行搜索:
点击后执行爬的操作
停止搜索:
点击后停止爬的操作并返回截止当前的结果
清空按钮:
点击后清空路径、链接、以及状态栏
状态栏:
即时反馈当前搜索的状态
弹框:
当正常结束搜索或点击停止结束搜索时弹出,返回已爬网页数目以及所用总时间
4、设计环境:
操作系统:
windows8.1
程序设计语言:
Python3.4
Tkinter(图形界面)
5、设计步骤:
首先,安装Python3并学习基础的使用方法。
使用Python3的原因:
Python是一种面向对象、直译式的计算机程序语言,具有近二十年的发展历史。
它包含了一组功能完备的标准库,能够轻松完成很多常见的任务。
Python为我们提供了非常完善的基础代码库,覆盖了网络、文件、GUI、数据库、文本等大量内容,被形象地称作“内置电池(batteriesincluded)”。
用Python开发,许多功能不必从零编写,直接使用现成的即可。
但有两个缺点:
第一个缺点就是运行速度慢,和C程序相比非常慢,因为Python是解释型语言,你的代码在执行时会一行一行地翻译成CPU能理解的机器码,这个翻译过程非常耗时,所以很慢。
第二个缺点就是代码不能加密。
但是对于课程设计来说本着学习的目的,可以忽略这两个缺点所带来的影响。
接下来,学会基于网络爬虫和python3的宽度优先搜索以及队列简单使用:
伪代码如下:
queueQ队列
setS集合
StartPoint="
Q.push(StartPoint)将起点加入队列
S.insert(StartPoint)将起点加入集合
while(Q.empty()==false)当队列非空时
T=Q.top()获取队首元素并且弹出
forpointinT:
对于元素内的所用url链接point
if(pointnotinS)如果该链接不在集合内(则表示没有访问过)
Q.push(point)将point加入队列
S.insert(point)将point加入集合
当然,在上述伪代码中没有考虑深度的控制,这个非常简单,只需要加几句话就够了。
为了实现上述的伪代码,首先是要实现链接的抓取,这个py3中已经有很好的实现模版了:
#encoding:
UTF-8
#编码方式
importurllib.request
#类似于C++语言中的声明头文件
url="
data=urllib.request.urlopen(url).read()
#获取链接
data=data.decode('UTF-8')
#解码,输出
print(data)
输出如下:
输出中有着大量冗余的代码,而需要仅仅只有标题、文本、和链接。
于是需要使用类似于字符串匹配的功能,还好py3中有着字符串匹配神器:
正则表达式。
花了半天的时间学习了正则表达式的使用以及HTML语言的基本规则。
(因为需要使用正则表达式去筛选基于HTML语言的文本)
书写了基于HTML筛选的简单正则表达式:
抓取标题:
re.findall(r'
([\s\S]*?)
',data)
抓取正文:
re.findall(r'>(.+?
)<',data)
以及对正文的筛选:
ifre.match(r'.*?
[{}|&<>]',正文内容):
continue
ifre.match(r'[\S]*?
',正文内容)andlen(正文内容)>1:
print(正文内容,file=f)
抓取链接:
re.findall(r'href=["\'](.+?
)["\']',data)
再接下来,抓取其他网页的过程中,发现有些合法的网页会出现解码错误的情况。
查阅资料发现不同的网站有不同的编码,于是选取4种较为常见的编码方式,并用py3的try来实现:
try:
data=data.decode('utf-8')
except:
try:
data=data.decode('gbk')
except:
try:
data=data.decode('gb2312')
except:
try:
data=data.decode('ISO-8859-1')
except:
#print(END,"Decodeerror!
\n")
然后,我们需要把抓下来的数据全部写入文件,又花了一定时间学习了py3中文件的简单读写,以及操作文件和目录的基本使用方法。
学习一下几个基本的操作:
importos
获取当前文件位置:
pos=sys.path[0]
清除某个文件夹的内容:
defdelete_it(pos):
#用于清空目录
forroot,dirs,filesinos.walk(pos,topdown=False):
fornameinfiles:
os.remove(os.path.join(root,name))
fornameindirs:
os.rmdir(os.path.join(root,name))
判断路径是否合法:
os.path.exists(pos)
路径相加:
os.path.join(pos,"dirname")
标准化路径格式:
os.path.normpath(pos)
文件输出流的打开与关闭
f=open(pos,'w',encoding="utf-8")
f.close()
另一种方法:
withopen(pos,'w',encoding="utf-8")asf:
…
现在已经完成了链接的抓取,文件的存储方法,用正则表达式对网页内容进行简单的筛选和分析,那么我们现在再使用宽度优先搜索和队列以及堆(集合)等数据结构和算法来实现整体的功能。
#-*-coding:
utf-8-*-
__author__='acerlawson___Hongji_Li___2013060203010'
__update_time__='2015-07-1109:
15:
53'
queue=deque()
#队列
visited=set()
#集合,用于判断是否已经访问过
url="
#设置初始链接
pos=sys.path[0]
#设置初始存储位置
depth=3
#设置深度
useless=['css','png','jpg',';','gif','ico']
#对爬虫无用的链接后缀,用于筛选对于我们无用的链接,节约时间,避免程序做多了冗余的运算而导致运行时间增加。
cnt=0
#计数器,用于统计链接的个数
queue.append((url,depth))
#加入初始链接到队列
visited|={url}
#加入初始链接到集合
whilequeue:
url,depth=queue.popleft()
#弹出队列
try:
data=urllib.request.urlopen(url,timeout=3).read()
#尝试获取数据
except:
#print('Failed!
')
#失败或者超时
continue
try:
data=data.decode('utf-8')
except:
try:
data=data.decode('gbk')
except:
try:
data=data.decode('gb2312')
except:
try:
data=data.decode('ISO-8859-1')
except:
#print(END,"Decodeerror!
\n")
#将解码错误的url放在一起
continue
#尝试各个常用类型的解码方式
cnt=cnt+1
#计数器+1
withopen(os.path.normpath(os.path.join(pos,str(cnt)+'.txt'))
'w',encoding="utf-8")asf:
#打开文件写入数据
print('抓取第',cnt,'个:
',url,file=f)
#记录抓取的序号
forsinre.findall(r'
([\s\S]*?)
',data):
#在这里我们找出了所有
(………)满足这种字符子串的括号内容,并将其写入到文件中去。
print("Title:
",s,file=f)
#写入title
forsinre.findall(r'>(.+?
)<',data):
#正则表达式筛选
#在这里我们找出了所有…>(………)<…满足这种字符子串的括号内容,并准备进行下一步筛选。
ifre.match(r'.*?
[{}|&<>]',s):
#在这里我们去掉所有字符子串中包含了{}|&<>等非正文常用符号的信息
continue
#正则表达式过滤1
ifre.match(r'[\S]*?
',s)andlen(s)>1:
#在这里我们去掉所有字符子串中的空串,以及单个字符所的信息。
进行接单的过滤
print(s,file=f)
#正则表达式过滤2
#筛选并写入内容
#print(cnt,'get!
')
#抓取成功的记录到his中
show.insert(END,str(cnt)+'ok!
'+'\n')
show.update()
#抓取成功!
ifdepth>1:
#如果剩余的深度>1则扩展
forsinre.findall(r'href=["\'](.+?
)["\']',data):
#对于所有外链url
#在这里我们抓取的是所有href=……的内容
l=len(s)#获取长度
flag=0
fortinuseless:
ifre.match('.*?
'+t,s):
#如果抓取的链接是图片或者脚本格式等之类的链接,我们将其筛掉
flag=1
break
ifflag==1:
continue
ifnotre.match(r'.*?
http.*?
',s):
#补充url
s=url+s
#有可能是同一目录下的链接,我们将其进行补充根目录
ifsinvisited:
continue
#是否访问过是则跳过
visited|={s}
#加入集合
queue.append((s,depth-1))
#加入队列
endtime=time.clock()
#时间函数统计搜索过程中所总共使用的时间
#printf('Allfinished!
\nwithtotals:
%d\nwithtime:
%.1fs'%(cnt,endtime-begtime))
爬虫基本的功能已经实现了,现在我们加上一定的图形化界面,在这里我们使用Tkinter的图形化界面。
TkInter是标准的PythonGUI库。
Python与Tkinter的结合提供了一个快速和容易的方法来创建GUI应用程序。
Tkinter的提供了一个强大的面向对象的接口Tk的GUI工具包.
使用Tkinter创建一个GUI应用程序是一件容易的事。
所有你需要做的是执行以下步骤:
导入Tkinter模块.
创建GUI应用程序的主窗口.
添加上述部件之一或更多的GUI应用程序.
进入主事件循环的由用户触发每个事件响应.
根据Tkinter本身提供的工具,我们只需要简单添加几句话就可以实现简单的图形化界面了。
fromtkinterimport*
importtkinter.messageboxasmessagebox
fromtkinter.filedialogimportaskdirectory
#类似于调用头文件之类的作用
root=Tk()
#声明一个图形化界面
root.title('小呀小爬虫v2.2.3')
#设置标题
a=StringVar()
urlname=Message(root,textvariable=a)
a.set("链接地址")
urlname.pack()
#图形界面文字说明的设置
urlinput=Entry(root,width=80)
#设置宽度为80
urlinput.pack()
#链接窗口安附在界面上
b=StringVar()
posname=Message(root,textvariable=b)
b.set("存储地址")
posname.pack()
#同上的作用,上次是链接,这次是存储
posinput=Entry(root,width=80)
#设置宽度为80
posinput.pack()
#地址窗口安附在界面上
pathbutton=Button(root,text='Path...',command=set_dir,width=30)
#设置功能(调用set_dir)和附件的宽度
pathbutton.pack()
#触发按钮安附在界面上
c=StringVar()
depname=Message(root,textvariable=c)
c.set("深度")
depname.pack()
#图形界面上关于深度标注的文字说明
w=Spinbox(root,from_=1,to=3,width=5)
#定义取值范围以及附件宽度大小
w.delete(0,END)
w.insert(END,2)
#初始化为2
w['state']='readonly'
#设置为只能通过按钮来改变而不能通过键盘
w.pack()
#将附件安附在界面上去
workbutton=Button(root,text='Search!
',command=work,width=30)
#设置搜索按钮,名字叫Search!
,触发后调用work函数,附件宽度为30
workbutton.pack()
#将搜索按钮安附在界面上去
stopbutton=Button(root,text='Stop!
',command=stop,state='disable',width=30)
#设置停止按钮,名字叫Stop!
,触发后调用stop函数,初始的时候不可用,附件宽度为30
stopbutton.pack()
#将停止按钮安附在附件上去
clearbutton=Button(root,text='Clear!
',command=clear_it,width=30)
#设置清空按钮,名字交Clear!
,触发后调用clear函数,附件宽度为30
clearbutton.pack()
#将情况按钮安附在界面上去
show=Text(root,width=100)
#设置状态栏,用于实时返回程序运行的状态,附件宽度为100
show.pack()
#将状态栏安附在界面上去
root.mainloop()
这样,图形化也有了,我们只需要将写好的程序封装成各个函数,然后相互调用,协调关系,就能很简单的写出基本所有的功能了。
版本更新记录:
########Ver1.0
#1.添加了文字解说
#2.保持状态栏在更新时在底部
#3.优化了筛选的正则表达式
#4.修复了部分的bug
#5.增强了程序的健壮性
########Ver1.1
#1.添加了停止功能
#2.添加了路径选择功能
########Ver1.2
#1.添加了自动删除历史功能
#2.添加了清楚状态框功能
#######Ver1.3
#1.优化了界面
#2.提高了程序的健壮性
#ver1.3说明:
正在爬的时候按除了stop以外的自动提示错误
#######Ver2.0
#1.修复了stop的bug
#2.增加了说明(正常结束输出'allfinished',stop结束输出'notfinished')
#3.增加灰色按钮,取消了避免了按键不合理的情况发生
######Ver2.1
#1.修了路径选择时点取消时自动清空的bug
#2.交换了消息弹出和编码统计的顺序
######Ver2.2
#1.修复了界面放大的bug,虽然让界面变丑了,但是健壮性增强了。
。
#2.增加了深度设置功能
######Ver2.2.2
#1.修复了错误路径造成混乱的bug
#2.修复了上次修复bug中产生的bug。
。
######Ver2.2.3
#1.修复了搜索时深度未锁定的bug
6、设计结果与展示:
首先是对学校主页进行了深度为3的爬行,使用的版本为2.2(具体情况看版本更新历史介绍)。
花了大概一个小时,爬了4500多个网页链接。
结果如图:
以及现在最新版本的使用情况:
路径选择:
爬到一半暂停,返回Notfinish!
爬到完全部返回Allfinished!
7、设计感想与总结:
通过本次课程设计,从基本目标的定型到实践开发这三、四天的过程,收获还是巨大的。
首先感谢指导老师的耐心指导、解答在开发过程中遇到的困惑与问题,并且在完成之后还给我提供了一些合理的新功能的思路,使得程序一步一步得到了完善。
其次是对一门新语言和新事物的认知和掌握。
在没有任何实践经验的情况下(也就是除了这学期的计算机网络在理论上学习了一点),通过课程设计,我花了较短的时间学习了Python3和实战了计算机网络编程。
当然这和Py3的语言特点也是脱不了关系的。
除了一门新语言的简单掌握以及计算机网络编程的简单实现,还锻炼了个人的学习以及动手能力。
以及通过老师和网络的帮助,达成了“提出问题-分析问题-解决问题”的解决途径。
过去一直以为网络爬虫是一些需要复杂的算法或者对计算机底层原理有很高要求的东西,通过本次网络爬虫的选题,让我重新审视了网络爬虫的存在。
门槛可高可低,深度可深可浅。
比如除了我这样简单实现以外,还可以去伪装成浏览器去爬一些反爬虫的网站等等。
总之,让我认识到了计算机网络编程的精彩与美妙。