python核心编程p564小爬虫详解

1 #!/usr/bin/python 使用魔法字符调用python

2

3 from sys import argv ?导入sys是导入python解释器和他环境相关的参数

4 from os import makedirs,unlink,sep

os主要提供对系统路径,文件重命名和删除文件所需的函数

makedirs是创建递归文件夹的函数。比如说我们要创建一个新的目录,/python/HTML/crawl,但是目前这三个文件夹都不存在,如果使用mkdir命令的话需要使用三次才能完成,但是使用os.makedir只需使用一次就可以创建好整个目录。

os.makedirs(os.path.join(os.erviron["HOME"],"python","HTML","crawl")

os.unlink(path)删除file路径,和remove()相同。

sep os.sep系统用此来分割路径名

5 from os.path import dirname,exists,isdir,splitext

使用os中的这些模块来提取dirname路径名,exists,isdir是文件类型测试,测试是否是一个目录,splitext是将文件名和文件后缀分离。分成目录文件名和后缀两部分。

6 from string import replace,find,lower

导入string??椋糜谧址奶婊?,查找,和小写化。

7 from htmllib import HTMLParser

8 from urllib import urlretrieve

urlretrieve()函数用于将HTML文件整个下载到你的本地硬盘中去。

9 from urlparse import urlparse,urljoin

urlparse用于将URL分解成6个元素

而urljoin用于将baseurl和newurl组合在一起

10 from formatter import DumbWriter,AbstractFormatter

formatter函数主要用于格式化文本

11 from cStringIO import StringIO

调用cStringIO函数对内存中的文件进行处理

12

13 class Retriever:

Retriever类负责从网上下载网页并对每一个文档里面的连接进行分析,如果符合下载原则就添加到“待处理”队列中。从网上下载到的每个主页都有一个与之对应的Retriever实例。Retriever有几个帮助实现功能的方法,分别是:构造器(__init__()),filename(),download()和parseAndGetLinks()。

14 ?def __init__(self,url): 定义构造器,指向当前类的当前实例的引用。 ? self 指向新创建的

对象,另外一个参数是url.构造器实例化一个Retriever对象,并且把URL字符串和从filename()返回的与之对应的文件名保存为本地属性。

15 ? self.url=url

将url的值付给self.url

16 ? self.file=self.filename(url)

???

17 ?def filename(self,url,deffile="index.html"):

定义filename方法,涉及另外两个参数,url,deffile,很明显deffile是后缀

18 ? parsedurl=urlparse(url,"http:",0)

urlparse(urlstr,defProtsch=None,allowFrag=None),defProtsch定义了缺醒的网络协议和下载方式,allow是一个表示是否允许在URL中使用不完整成分的操作标志。allow_fragment如果是false,即使在URL addressing scheme支持fragment identifiers得情况下fragment identifiers也不允许,默认情况下fragment的默认值是true.

19 ? path=parsedurl[1]+parsedurl[2]

从urlparse分离出来的六个元素分别是(prot_shc,net_loc,path,params,query,frag).

parseurl[1]是net_loc,parseurl[2]是path.

和在一起正好是整个路径

20 ? ext=splitext(path)

将path分解成目录文件名和后缀标志。

21 ? if ext[1]=="":

如果没有文件。ext是一个字符串,ext[0]就是目录文件名,而ext[1]就是后缀名,说明没有后缀

22 ? ?if path[-1]=="/":

并且path是比如说是以我的博客为例,http://blog.csdn.net/yangwenchao1983,分离后path[-1]=3,也就是字符串的最后一个字母,如果是/,说明有文件内容,

23 ? ? path=path+deffile

如果URL没有尾缀的文件名,就用缺性的"index.html“作为文假名,可以说是一个主王爷,上面有各种文件公下载,现在没有合适的文件,我们酒吧index.html作为补充。

24 ? else:

25 ? ?path=path+"/"+deffile

如果是一个完整的文件名,我们需要在后面加上/index.html

如果不含有"/"符号的话,

26 ? dir=dirname(path)

提取path字符串的目录名称

27 ? if sep!="/":

如果文件的分割符不是/

28 ? ?dir=replace(dir,"/",sep)

将dir中的/替换成分割符,/

29 ? if not isdir(dir):

使用isdir辨别文件类型不是目录。

30 ? ?if exists(dir): unlink(dir)

如果不是目录文件,就是用unlink移除,

31 ? ?makedirs(dir)

重新使用makedirs创建目录文件

32 ? return path

返回经过整理的路径

33 ?def download(self):

定义download()方法,使用try...except...来进行异常处理,

34 ? try:

35 ? ?retval=urlretrieve(self.url,self.file)

urlretrieve()不像urlopen()那样对URL进行读操作,它只是简单的把位于urlstr处的HTML文件整个下载到你的本地硬盘中去,如果没有给出localfile,它就会把数据保存到一个临时文件中去。很明显,这行程序的意思就是将self.url从望上的某个地方拷贝到硬盘的self.file中去。

36 ? except IOError:

如果文件不存在,就会引发IOerror,

37 ? ?retval=("***ERROR: invalid URL "%s"" %\self.url,)

没有在有效的网址上找到这个文件,就将"***ERROR: invalid URL "%s""打印出来

38 ? return retval

返回得到的文件

39 ?def parseAndGetLinks(self):

如果上面的的处理没有发现任何错误,就会调用parseAndGetLinks()对新下载打破的主页进行分析,确定对那个主页上的每一个连接应该采取什么样的行动。

40 ? self.parser=HTMLParser(AbstractFormatter(DumbWriter(StringIO())))

使用HTMLParser的方法进行处理,StringIO是从内存中读取数据,DumbWriter将事件流转换为存文本文档。

41 ? self.parser.feed(open(self.file).read())

将self.file文件打开并且一次性读入上面定义的的文件中去

42 ? self.parser.close()

关闭文件

43 ? return self.parser.anchorlist

返回地址和日期

44

45 class Crawler:

Crawler由三个数据项组成,这三个数据项是由构造器在实例化阶段报存在这里的。

46 ?count = 0

静态下载主页计数器

47 ?def __init__(self,url):

48 ? self.q=[url]

第一个数据是q,这是一个有下载连接组成的队列,这个清单在执行过程中是会变化的,没处理一个主页它就缩短一次,而在各下载主页中发现一个新的连接就会被加长。

49 ? self.seen=[]

Crawler的另外两个数据项包括seen-这是我们已经下载过的全体连接所组成的一个列表;

50 ? self.dom=urlparse(url)[1]

把主连接的域名报存在dom中,用这个值核对后续连接是否属于这同一个区域。

51 ?def getPage(self,url):

getPage()方法用第一个连接实例化出一个Retriever对象,从她开始进行后续的处理。

52 ? r=Retriever(url)

使用上面定义过得Retriever类,付给r。

53 ? retval=r.download()

下载网页连接,

54 ? if retval[0]=="*":

55 ? ?print retval,"...skipping parse"

56 ? ?return

57 ? Crawler.count=Crawler.count+1

Crawler还有一个静态数据叫做count。这个计数器的作用就是记录我们呢已经从望红色那个下载到的对象的个数,每成功下载一个主页,就让它增加一个数。

58 ? print "\n(",Crawler.count,")"

59 ? print "URL:",url

60 ? print "FILE:",retval[0]

61 ? self.seen.append(url)

62

63 ? links=r.parseAndGetLinks()

64 ? for eachLink in Links:

65 ? ?if eachLink[:4]!="http" and find(eachLink,"://")==-1

66 ? ? print "*",eachLink,

以下链接将被忽略,不会被添加到待处理队列里去的:属于另外一个域的连接,已经被下载过得链接,已经放入待处理队列里去的连接或者是"mailto:"连接。

67 ? ?if find(lower(eachLink),"mailto:")!=-1:应该是超连接

68 ? ? print "...discard,mailto link"

69 ? ? contine

70 ? ?if eachlink not in self.seen:

71 ? ? if find(eachLink,self.dom)==-1:

72 ? ? ?print "...discarded,not in domain"

73 ? ? else:

74 ? ? ?if eachLink not in self.q:

75 ? ? ? self.q.append(eachLink)

76 ? ? ? print "...new,aded to Q"

77 ? ? ?else:

78 ? ? ? print "...discarded,already in Q"

79 ? ?else:

80 ? ? print "...discarded,already processed"

81 ?def go(self):

82 ? while self.q:

83 ? ?url=self.q.pop()

84 ? ?self.getPage(url)

85 ?def main():

86 ? if len(argv)>1:

87 ? ?url=argv[1]

88 ? else:

89 ? ?try:

90 ? ? url=raw_input("Enter starting URL:")

91 ? ?except(KeyboardInterrupt,EOFError):

92 ? ? url=""

93 ? if not url: return

94 ? robot=Crawler(url)

95 ? robot.go()

96

97 if __name__=="__main__":

98 ?main()

99

main()只有在这个脚本程序在直接被调用时才会执行,它是程序的出发点,其他导入了crawl.py的??樾枰魅返牡饔胢ain()才能开始处理。要让main()开始执行,需要给它一个URL,如果已经在一个命令行给出URL(例如我们直接调用这个脚本程序的时候),它就会从给定的URL起开始运行;否则,脚本程序将进入交互模式,提示用户输入一个URL。有了初始连接之后,程序将对Crawler类进行实例化并开始执行。

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容