该程序主体是《Python核心编程第二版》例20.2。本篇会修改部分代码及添加了相关注释。
ps:该书该例程不能直接运行,需要修改。
二、功能
网络爬虫crawl.py抓取web的开始页面地址,下载该页面和其他后续链接页面,但是仅限于那些与开始页面有着相同域名页面。
三、程序
crawl.py
#coding=utf-8
#20170628why
'''
本程序执行成功后会在本地产生文件名太长或文件夹路径太深无法删除的情况,解决方法如下:
在要删除的目录新建t1
在该目录下的cmd中执行D:\it\Python\HTTP_Client>robocopy t1 www.runoob.com /MIR
接着删除t1和www.runoob.com文件夹
'''
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
from urllib import urlretrieve
from urlparse import urlparse, urljoin
from formatter import DumbWriter, AbstractFormatter
from cStringIO import StringIO
class Retriever(object):
def __init__(self, url):
self.url = url
self.file = self.filename(url)
def filename(self, url, deffile = 'index.html'):
'''
该函数将输入的网址作为相对路径并创建。若该路径存在则删除后重新创建;若该路径不存在则新建。返回本地保存的路径。
:param url: 地址
:param deffile: 要爬的主页名
:return:返回路径
'''
parsedurl = urlparse(url, 'http:', 0)
# print parsedurl[0]
#http
# print parsedurl[1]
#www.null.com
# print parsedurl[2]
#/home/index.html
path = parsedurl[1] + parsedurl[2]
# print path
#www.null.com/home/index.html
ext = splitext(path)
# print ext
#('www.null.com/home/index', '.html')
# print ext[1]
#.html
# print path[-1]
#l
if ext[1] == '':
if path[-1] == '/':
path += deffile
# print path
else:
path += '/' + deffile
# print path
ldir = dirname(path)
# print ldir
#www.null.com/home
# print sep
#\
if sep != '/':
ldir = replace(ldir, '/', sep)
if not isdir(ldir):
#判断是否是文件夹,若不是文件夹isdir(ldir)是False;若是文件夹isdir(ldir)是True;
if exists(ldir):
#判断文件夹是否存在,若存在exists(ldir)是True;若不存在exists(ldir)是False;
unlink(ldir)
#unlink() 方法用于删除文件,如果文件是一个目录则返回一个错误。
makedirs(ldir) #修改错误处 makedirs() 方法用于递归创建目录。若之前存在或不存在都需要新建。
print path
#www.null.com/home/index.html
return path #返回路径
def download(self):
'''
该函数直接将远程数据下载到本地。
urlretrieve(url, filename, reporthook);
url :外部或者本地url
filename :指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
reporthook :是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
:return:返回网址
'''
try:
# print self.url
#http://www.null.com/home/index.html
# print self.file #www.null.com/home/index.html
retval = urlretrieve(self.url, self.file)
#直接将远程数据下载到本地。
except IOError:
retval = ('*** Error: invaild URL "%s"' % self.url)
return retval
#修改错误处
def parseAndGetLinks(self):
#HTMLParser实现HTML文件的分析。
#StringIO是从内存中读取数据;DumbWriter将事件流转换为存文本文档
self.paraser = HTMLParser(AbstractFormatter(DumbWriter(StringIO())))
print self.paraser
self.paraser.feed(open(self.file).read())
#feed方法将接收数据
self.paraser.close()
print self.paraser.anchorlist
return self.paraser.anchorlist #返回地址和日期
class Crawler(object):
count = 0
def __init__(self, url):
self.q = [url]
self.seen = []
self.dom = urlparse(url)[1]
def getPage(self, url):
r = Retriever(url)
retval = r.download()
#print retval #('www.null.com/home/index.html', )
if retval[0] == '*':
print retval, '... skipping parase'
return
Crawler.count += 1
print '\n(', Crawler.count,')'
print 'URL:', url
print 'FILE:', retval[0]
self.seen.append(url)
#['http://www.null.com/home/index.html'] append() 方法用于在列表末尾添加新的对象
print self.seen
links = r.parseAndGetLinks()
#20170628
本程序执行成功后会在本地产生文件名太长或文件夹路径太深无法删除的情况,解决方法如下:
在要删除的目录新建t1
在该目录下的cmd中执行
'''
from
from
from
from
from
from
from
from
from
class
class