一个简单的Web客户端(网络爬虫)
来源:互联网 发布:淘宝联盟手机版如何赚钱 编辑:程序博客网 时间:2024/05/25 16:40
本节演示网络爬虫。它是按照一定的规则,自动地抓取万维网信息的程序或者脚本。
在本节的演示程序中,抓取Web的开始页面地址,下载与开始页面相同域名的后续链接页面。
实现代码:
- #-*-coding: utf-8-*-
- from sys import argv
- from os import makedirs, unlink, sep
- from os.path import dirname, exists, isdir, splitext
- from string import replace, find, lower
- from htmllib import HTMLParser # HTMLParser是用来解析html页面的,解析html页面中的链接?
- from urllib import urlretrieve
- from urlparse import urlparse, urljoin
- from formatter import DumbWriter, AbstractFormatter # DumbWriter将事件流转换为存文本文档?AbstractFormatter?
- from cStringIO import StringIO # StringIO是指在内存中读写字符串
- # 类Retrieve负责从web下载页面
- class Retrieve(object): # download Web pages
- def __init__(self, url):
- self.url = url
- self.file = self.filename(url)
- # filename()方法使用给定的url找出安全、有效的相关文件名并储存在本地
- def filename(self, url, deffile='index.html'):
- parsedurl = urlparse(url, 'http:', 0) # 解析路径
- path = parsedurl[1] + parsedurl[2] # web页面(服务器位置+文件路径)
- ext = splitext(path) # 返回(文件名,扩展名)
- if ext[1] == '': # 没有扩展名,使用默认的deffile,即path变为'...(服务器路径)/index.html'
- if path[-1] == '/':
- path += deffile
- else:
- path += '/' + deffile
- ldir = dirname(path) # path所在的目录路径
- if sep != '/': # path路径分隔符?猜测可能是考虑到不同操作系统平台
- ldir = replace(ldir, '/', sep) # 统一采用linux系统的格式
- if not isdir(ldir): # 路径不存在时,存档。
- if exists(ldir): unlink(ldir) # 删除ldir下原有的文件?
- makedirs(ldir)
- return path
- # download()方法连接网络,下载给定链接的页面
- def download(self): # download web page
- try:
- retval = urlretrieve(self.url, self.file) # 下载url页面成功,并保存在filename中,retval是一个元组,第一项是文件名(包括路径),第二项是服务器的响应头,?
- except IOError:
- retval = ('*** ERROR: invalid URL "%s"' % self.url,) # 下载页面失败,retval是一个包含字符串的单元组
- return retval
- # 如果上面的的处理没有发现任何错误,就会调用parseAndGetLinks()对新下载的主页进行分析,确定对那个web页面上的每一个连接应该采取什么样的行动。
- def parseAndGetLinks(self): # 解析HTML,保存链接
- self.parser = HTMLParser(AbstractFormatter(DumbWriter(StringIO()))) # 解析器?
- self.parser.feed(open(self.file).read()) # open(self.file).read()就是下载的页面,feed()方法是提取其中的链接,自动存入anchorlist列表。
- self.parser.close() # 关闭解析器?
- return self.parser.anchorlist # anchorlist里储存解析出来的html页面的链接
- class Crawler(object): # 管理爬虫进程
- count = 0 # 已下载web页面计数器
- def __init__(self, url):
- self.q =[url] # 待下载链接队列,页面处理完毕变短,如果页面中发现新的链接,则会变长。
- self.seen = [] # 已下载队列
- self.dom = urlparse(url)[1] # 存储主链接域名,用于判断后续链接是否是该域的一部分。
- # 核心
- def getPage(self, url):
- r = Retrieve(url) # 实例化Retrieve对象
- retval = r.download() # 下载web页面
- if retval[0] == '*': # 下载出错,不进行解析
- print retval, '... skipping parse'
- return
- Crawler.count += 1 # 下载web页面没有问题,则已下载web页面计数器count加1,表示已经下载了一个web页面
- print '\n(', Crawler.count, ')'
- print 'URL:', url
- print 'FILE:', retval[0]
- self.seen.append(url) # 将url添加到已下载队列
- links = r.parseAndGetLinks() # links包含了url指向的HTML页面的所有链接
- for eachlink in links:
- if eachlink[:-4] != 'http' and find(eachlink, '://') == -1:
- eachlink = urljoin(url, eachlink)
- print '* ', eachlink,
- if find(lower(eachlink), 'mailto:') != -1:
- print '... discarded, mailto link'
- continue # 如果url指向的HTML页面有mailto链接(自动发送电子邮件的链接),则其将被忽略
- if eachlink not in self.seen:
- if find(eachlink, self.dom) == -1:
- print '... discarded, not in domain' # 不在主链接域名的链接也会被忽略,比如说很多网站上都会有另外一个网站(不同域名)的链接,这类链接也会被忽略。
- else:
- if eachlink not in self.q:
- self.q.append(eachlink)
- print '... new, added to Q' # 将链接加入到待下载链接队列中
- else:
- print '... discarded, already in Q' # 忽略已在待下载链接队列中的链接
- else:
- print '... discarded, already processed' # 忽略已经下载过的链接
- # 启动Crawler(),不停地推进处理过程,直到队列为空。
- def go(self): # 处理待下载链接队列里的链接
- while self.q:
- url = self.q.pop()
- self.getPage(url)
- def main():
- if len(argv) > 1:
- url = argv[1] # 就是在命令行以 python crawl.py url 启动程序
- else:
- try:
- url = raw_input('Enter starting URL: ')
- except (KeyboardInterrupt, EOFError):
- url = ''
- if not url: return
- robot = Crawler(url)
- robot.go()
- if __name__ == "__main__":
- main()
运行结果如下·:
Enter starting URL: write.blog.csdn.net
( 1 )
URL: http://write.blog.csdn.net/
FILE: write.blog.csdn.net/index.html
* http://edu.csdn.net/huiyiCourse/series_detail/65?utm_source= ... new, added to Q
* http://write.blog.csdn.net/account/fpwd?action=forgotpassword&service=http%3A%2F%2Fwrite.blog.csdn.net%2F ... new, added to Q
* https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=100270989&redirect_uri=https%3A%2F%2Fpassport.csdn.net%2Faccount%2Flogin%3Foauth_provider%3DQQProvider&state=test ... new, added to Q
* javascript:void(0) ... discarded, not in domain
* https://api.weibo.com/oauth2/authorize?client_id=2601122390&response_type=code&redirect_uri=https%3A%2F%2Fpassport.csdn.net%2Faccount%2Flogin%3Foauth_provider%3DSinaWeiboProvider ... new, added to Q
* https://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=cePqkUpKCBrcnQtARTNPxxQG&redirect_uri=https%3A%2F%2Fpassport.csdn.net%2Faccount%2Flogin%3Foauth_provider%3DBaiduProvider ... new, added to Q
* https://www.oschina.net/action/oauth2/authorize?response_type=code&client_id=cIh1UuWvSyrYlbe93rM6&redirect_uri=https%3A%2F%2Fpassport.csdn.net%2Faccount%2Flogin%3Foauth_provider%3DOsChinaProvider&state=test ... new, added to Q
* https://github.com/login/oauth/authorize?client_id=4bceac0b4d39cf045157&redirect_uri=https%3A%2F%2Fpassport.csdn.net%2Faccount%2Flogin%3Foauth_provider%3DGitHubProvider ... new, added to Q
* javascript:; ... discarded, not in domain
* http://write.blog.csdn.net/account/mobileregister?action=mobileRegisterGuideView&service=http%3A%2F%2Fwrite.blog.csdn.net%2F ... new, added to Q
- 一个简单的Web客户端(网络爬虫)
- 网络爬虫(六):一个简单的百度贴吧小爬虫
- 一个简单的java网络爬虫(spider)
- 一个简单的java网络爬虫(spider)
- 一个简单的宽度优先网络爬虫
- 一个简单的网络爬虫 - SharkCrawler
- 一个简单的网络爬虫程序
- [python脚本]一个简单的web爬虫(1)
- 一个简单的Web爬虫程序
- Java编写一个简单的Web爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- [Python]网络爬虫(六):一个简单的百度贴吧的小爬虫
- 为什么下一个5年java后台开发你该选择Spring Boot?
- 437. Path Sum III(二叉树的路径和之三)
- XStream 实现XML>Obj 和 obj>XML
- 【JS】JS中的时间做差处理
- libev学习资料
- 一个简单的Web客户端(网络爬虫)
- C语言-Wall编译指令
- 欢迎使用CSDN-markdown编辑器
- 到一定距离后会出现的图片以及记录坐标
- Revit中Dynamo编程——在Python Script中结合sql server数据库来存储材料的外观属性
- python之Character string
- HBase Java API 使用示例
- Java Jvm知识
- HttpClient4 客户端出现TIME_WAIT