python核心編程p564小爬蟲詳解

1 #!/usr/bin/python 使用魔法字符調(diào)用python

2

3 from sys import argv ?導(dǎo)入sys是導(dǎo)入python解釋器和他環(huán)境相關(guān)的參數(shù)

4 from os import makedirs,unlink,sep

os主要提供對系統(tǒng)路徑,文件重命名和刪除文件所需的函數(shù)

makedirs是創(chuàng)建遞歸文件夾的函數(shù)。比如說我們要創(chuàng)建一個新的目錄,/python/HTML/crawl,但是目前這三個文件夾都不存在,如果使用mkdir命令的話需要使用三次才能完成,但是使用os.makedir只需使用一次就可以創(chuàng)建好整個目錄。

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

os.unlink(path)刪除file路徑,和remove()相同。

sep os.sep系統(tǒng)用此來分割路徑名

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

使用os中的這些模塊來提取dirname路徑名,exists,isdir是文件類型測試,測試是否是一個目錄,splitext是將文件名和文件后綴分離。分成目錄文件名和后綴兩部分。

6 from string import replace,find,lower

導(dǎo)入string模塊,用于字符串的替換,查找,和小寫化。

7 from htmllib import HTMLParser

8 from urllib import urlretrieve

urlretrieve()函數(shù)用于將HTML文件整個下載到你的本地硬盤中去。

9 from urlparse import urlparse,urljoin

urlparse用于將URL分解成6個元素

而urljoin用于將baseurl和newurl組合在一起

10 from formatter import DumbWriter,AbstractFormatter

formatter函數(shù)主要用于格式化文本

11 from cStringIO import StringIO

調(diào)用cStringIO函數(shù)對內(nèi)存中的文件進(jìn)行處理

12

13 class Retriever:

Retriever類負(fù)責(zé)從網(wǎng)上下載網(wǎng)頁并對每一個文檔里面的連接進(jìn)行分析,如果符合下載原則就添加到“待處理”隊列中。從網(wǎng)上下載到的每個主頁都有一個與之對應(yīng)的Retriever實例。Retriever有幾個幫助實現(xiàn)功能的方法,分別是:構(gòu)造器(__init__()),filename(),download()和parseAndGetLinks()。

14 ?def __init__(self,url): 定義構(gòu)造器,指向當(dāng)前類的當(dāng)前實例的引用。 ? self 指向新創(chuàng)建的

對象,另外一個參數(shù)是url.構(gòu)造器實例化一個Retriever對象,并且把URL字符串和從filename()返回的與之對應(yīng)的文件名保存為本地屬性。

15 ? self.url=url

將url的值付給self.url

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

???

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

定義filename方法,涉及另外兩個參數(shù),url,deffile,很明顯deffile是后綴

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

urlparse(urlstr,defProtsch=None,allowFrag=None),defProtsch定義了缺醒的網(wǎng)絡(luò)協(xié)議和下載方式,allow是一個表示是否允許在URL中使用不完整成分的操作標(biāo)志。allow_fragment如果是false,即使在URL addressing scheme支持fragment identifiers得情況下fragment identifiers也不允許,默認(rèn)情況下fragment的默認(rèn)值是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分解成目錄文件名和后綴標(biāo)志。

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

如果沒有文件。ext是一個字符串,ext[0]就是目錄文件名,而ext[1]就是后綴名,說明沒有后綴

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

并且path是比如說是以我的博客為例,http://blog.csdn.net/yangwenchao1983,分離后path[-1]=3,也就是字符串的最后一個字母,如果是/,說明有文件內(nèi)容,

23 ? ? path=path+deffile

如果URL沒有尾綴的文件名,就用缺性的"index.html“作為文假名,可以說是一個主王爺,上面有各種文件公下載,現(xiàn)在沒有合適的文件,我們酒吧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創(chuàng)建目錄文件

32 ? return path

返回經(jīng)過整理的路徑

33 ?def download(self):

定義download()方法,使用try...except...來進(jìn)行異常處理,

34 ? try:

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

urlretrieve()不像urlopen()那樣對URL進(jìn)行讀操作,它只是簡單的把位于urlstr處的HTML文件整個下載到你的本地硬盤中去,如果沒有給出localfile,它就會把數(shù)據(jù)保存到一個臨時文件中去。很明顯,這行程序的意思就是將self.url從望上的某個地方拷貝到硬盤的self.file中去。

36 ? except IOError:

如果文件不存在,就會引發(fā)IOerror,

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

沒有在有效的網(wǎng)址上找到這個文件,就將"***ERROR: invalid URL "%s""打印出來

38 ? return retval

返回得到的文件

39 ?def parseAndGetLinks(self):

如果上面的的處理沒有發(fā)現(xiàn)任何錯誤,就會調(diào)用parseAndGetLinks()對新下載打破的主頁進(jìn)行分析,確定對那個主頁上的每一個連接應(yīng)該采取什么樣的行動。

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

使用HTMLParser的方法進(jìn)行處理,StringIO是從內(nèi)存中讀取數(shù)據(jù),DumbWriter將事件流轉(zhuǎn)換為存文本文檔。

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

將self.file文件打開并且一次性讀入上面定義的的文件中去

42 ? self.parser.close()

關(guān)閉文件

43 ? return self.parser.anchorlist

返回地址和日期

44

45 class Crawler:

Crawler由三個數(shù)據(jù)項組成,這三個數(shù)據(jù)項是由構(gòu)造器在實例化階段報存在這里的。

46 ?count = 0

靜態(tài)下載主頁計數(shù)器

47 ?def __init__(self,url):

48 ? self.q=[url]

第一個數(shù)據(jù)是q,這是一個有下載連接組成的隊列,這個清單在執(zhí)行過程中是會變化的,沒處理一個主頁它就縮短一次,而在各下載主頁中發(fā)現(xiàn)一個新的連接就會被加長。

49 ? self.seen=[]

Crawler的另外兩個數(shù)據(jù)項包括seen-這是我們已經(jīng)下載過的全體連接所組成的一個列表;

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

把主連接的域名報存在dom中,用這個值核對后續(xù)連接是否屬于這同一個區(qū)域。

51 ?def getPage(self,url):

getPage()方法用第一個連接實例化出一個Retriever對象,從她開始進(jìn)行后續(xù)的處理。

52 ? r=Retriever(url)

使用上面定義過得Retriever類,付給r。

53 ? retval=r.download()

下載網(wǎng)頁連接,

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

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

56 ? ?return

57 ? Crawler.count=Crawler.count+1

Crawler還有一個靜態(tài)數(shù)據(jù)叫做count。這個計數(shù)器的作用就是記錄我們呢已經(jīng)從望紅色那個下載到的對象的個數(shù),每成功下載一個主頁,就讓它增加一個數(shù)。

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,

以下鏈接將被忽略,不會被添加到待處理隊列里去的:屬于另外一個域的連接,已經(jīng)被下載過得鏈接,已經(jīng)放入待處理隊列里去的連接或者是"mailto:"連接。

67 ? ?if find(lower(eachLink),"mailto:")!=-1:應(yīng)該是超連接

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()只有在這個腳本程序在直接被調(diào)用時才會執(zhí)行,它是程序的出發(fā)點,其他導(dǎo)入了crawl.py的模塊需要明確的調(diào)用main()才能開始處理。要讓main()開始執(zhí)行,需要給它一個URL,如果已經(jīng)在一個命令行給出URL(例如我們直接調(diào)用這個腳本程序的時候),它就會從給定的URL起開始運行;否則,腳本程序?qū)⑦M(jìn)入交互模式,提示用戶輸入一個URL。有了初始連接之后,程序?qū)rawler類進(jìn)行實例化并開始執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容