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)行分析查描,如果符合下載原則就添加到“待處理”隊(duì)列中。從網(wǎng)上下載到的每個主頁都有一個與之對應(yīng)的Retriever實(shí)例速警。Retriever有幾個幫助實(shí)現(xiàn)功能的方法叹誉,分別是:構(gòu)造器(__init__()),filename(),download()和parseAndGetLinks()。

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

對象,另外一個參數(shù)是url.構(gòu)造器實(shí)例化一個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作為補(bǔ)充骆莹。

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ù)保存到一個臨時(shí)文件中去比驻。很明顯该溯,這行程序的意思就是將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ù)項(xiàng)組成堤撵,這三個數(shù)據(jù)項(xiàng)是由構(gòu)造器在實(shí)例化階段報(bào)存在這里的。

46 ?count = 0

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

47 ?def __init__(self,url):

48 ? self.q=[url]

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

49 ? self.seen=[]

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

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

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

51 ?def getPage(self,url):

getPage()方法用第一個連接實(shí)例化出一個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。這個計(jì)數(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蚀乔,

以下鏈接將被忽略烁竭,不會被添加到待處理隊(duì)列里去的:屬于另外一個域的連接,已經(jīng)被下載過得鏈接吉挣,已經(jīng)放入待處理隊(duì)列里去的連接或者是"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)用時(shí)才會執(zhí)行,它是程序的出發(fā)點(diǎn)睬魂,其他導(dǎo)入了crawl.py的模塊需要明確的調(diào)用main()才能開始處理终吼。要讓main()開始執(zhí)行,需要給它一個URL氯哮,如果已經(jīng)在一個命令行給出URL(例如我們直接調(diào)用這個腳本程序的時(shí)候)际跪,它就會從給定的URL起開始運(yùn)行;否則喉钢,腳本程序?qū)⑦M(jìn)入交互模式姆打,提示用戶輸入一個URL。有了初始連接之后肠虽,程序?qū)rawler類進(jìn)行實(shí)例化并開始執(zhí)行幔戏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市舔痕,隨后出現(xiàn)的幾起案子评抚,更是在濱河造成了極大的恐慌,老刑警劉巖伯复,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慨代,死亡現(xiàn)場離奇詭異,居然都是意外死亡啸如,警方通過查閱死者的電腦和手機(jī)侍匙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人想暗,你說我怎么就攤上這事妇汗。” “怎么了说莫?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵杨箭,是天一觀的道長。 經(jīng)常有香客問我储狭,道長互婿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任辽狈,我火速辦了婚禮慈参,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刮萌。我一直安慰自己驮配,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布着茸。 她就那樣靜靜地躺著壮锻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪涮阔。 梳的紋絲不亂的頭發(fā)上躯保,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音澎语,去河邊找鬼。 笑死验懊,一個胖子當(dāng)著我的面吹牛擅羞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播义图,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼减俏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了碱工?” 一聲冷哼從身側(cè)響起娃承,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怕篷,沒想到半個月后历筝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡廊谓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年梳猪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒸痹。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡春弥,死狀恐怖呛哟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情匿沛,我是刑警寧澤扫责,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站逃呼,受9級特大地震影響鳖孤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜘渣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一淌铐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔫缸,春花似錦腿准、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至校翔,卻和暖如春弟跑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背防症。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工孟辑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔫敲。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓饲嗽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親奈嘿。 傳聞我的和親對象是個殘疾皇子貌虾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容