(點(diǎn)擊上方藍(lán)字,可快速關(guān)注我們)
在上一篇中,我們實(shí)現(xiàn)了一個(gè)基本網(wǎng)絡(luò)爬蟲(chóng),它可以從StackOverflow上下載最新的問(wèn)題,并將它們存儲(chǔ)在MongoDB數(shù)據(jù)庫(kù)中。在本文中,我們將對(duì)其擴(kuò)展,使它能夠爬取每個(gè)網(wǎng)頁(yè)底部的分頁(yè)鏈接,并從每一頁(yè)中下載問(wèn)題(包含問(wèn)題標(biāo)題和URL)。 " 在你開(kāi)始任何爬取工作之前,檢查目標(biāo)網(wǎng)站的使用條款并遵守robots.txt文件。同時(shí),做爬取練習(xí)時(shí)遵守道德,不要在短時(shí)間內(nèi)向某個(gè)網(wǎng)站發(fā)起大量請(qǐng)求。像對(duì)待自己的網(wǎng)站一樣對(duì)待任何你將爬取的網(wǎng)站。" 開(kāi)始 有兩種可能的方法來(lái)接著從上次我們停下的地方繼續(xù)進(jìn)行。 第一個(gè)方法是,擴(kuò)展我們現(xiàn)有的網(wǎng)絡(luò)爬蟲(chóng),通過(guò)利用一個(gè)xpath表達(dá)式從”parse_item”方法里的響應(yīng)中提取每個(gè)下一頁(yè)鏈接,并通過(guò)回調(diào)同一個(gè)parse_item方法產(chǎn)生一個(gè)請(qǐng)求對(duì)象。利用這種方法,爬蟲(chóng)會(huì)自動(dòng)生成針對(duì)我們指定的鏈接的新請(qǐng)求,你可以在Scrapy文檔這里找到更多有關(guān)該方法的信息。 另一個(gè)更簡(jiǎn)單的方法是,使用一個(gè)不同類(lèi)型的爬蟲(chóng)—CrawlSpider(鏈接)。這是基本Spider的一個(gè)擴(kuò)展版本,它剛好滿足我們的要求。 CrawlSpider 我們將使用與上一篇教程中相同的爬蟲(chóng)項(xiàng)目,所以如果你需要的話可以從repo上獲取這些代碼。 創(chuàng)建樣板 在“stack”目錄中,首先由crawl模板生成爬蟲(chóng)樣板。
Scrapy項(xiàng)目現(xiàn)在看起來(lái)應(yīng)該像這樣:
stack_crawler.py文件內(nèi)容如下:
我們只需要對(duì)這個(gè)樣板做一些更新。 更新“start_urls”列表 首先,添加問(wèn)題的第一個(gè)頁(yè)面鏈接到start_urls列表:
更新“rules”列表 接下來(lái),我們需要添加一個(gè)正則表達(dá)式到“rules”屬性中,以此告訴爬蟲(chóng)在哪里可以找到下一個(gè)頁(yè)面鏈接:
現(xiàn)在爬蟲(chóng)能根據(jù)那些鏈接自動(dòng)請(qǐng)求新的頁(yè)面,并將響應(yīng)傳遞給“parse_item”方法,以此來(lái)提取問(wèn)題和對(duì)應(yīng)的標(biāo)題。 如果你仔細(xì)查看的話,可以發(fā)現(xiàn)這個(gè)正則表達(dá)式限制了它只能爬取前9個(gè)網(wǎng)頁(yè),因?yàn)樵谶@個(gè)demo中,我們不想爬取所有的176234個(gè)網(wǎng)頁(yè)。 更新“parse_item”方法 現(xiàn)在我們只需編寫(xiě)如何使用xpath解析網(wǎng)頁(yè),這一點(diǎn)我們已經(jīng)在上一篇教程中實(shí)現(xiàn)過(guò)了,所以直接復(fù)制過(guò)來(lái)。
這就是為爬蟲(chóng)提供的解析代碼,但是現(xiàn)在先不要啟動(dòng)它。 添加一個(gè)下載延遲 我們需要通過(guò)在settings.py文件中設(shè)定一個(gè)下載延遲來(lái)善待StackOverflow(和任何其他網(wǎng)站)。
這告訴爬蟲(chóng)需要在每?jī)蓚€(gè)發(fā)出的新請(qǐng)求之間等待5秒鐘。你也很有必要做這樣的限制,因?yàn)槿绻悴贿@么做的話,StackOverflow將會(huì)限制你的訪問(wèn)流量,如果你繼續(xù)不加限制地爬取該網(wǎng)站,那么你的IP將會(huì)被禁止。所有,友好點(diǎn)—要像對(duì)待自己的網(wǎng)站一樣對(duì)待任何你爬取的網(wǎng)站。 現(xiàn)在只剩下一件事要考慮—存儲(chǔ)數(shù)據(jù)。 MongoDB 上次我們僅僅下載了50個(gè)問(wèn)題,但是因?yàn)檫@次我們要爬取更多的數(shù)據(jù),所有我們希望避免向數(shù)據(jù)庫(kù)中添加重復(fù)的問(wèn)題。為了實(shí)現(xiàn)這一點(diǎn),我們可以使用一個(gè)MongoDB的 upsert方法,它意味著如果一個(gè)問(wèn)題已經(jīng)存在數(shù)據(jù)庫(kù)中,我們將更新它的標(biāo)題;否則我們將新問(wèn)題插入數(shù)據(jù)庫(kù)中。 修改我們前面定義的MongoDBPipeline:
為簡(jiǎn)單起見(jiàn),我們沒(méi)有優(yōu)化查詢,也沒(méi)有處理索引值,因?yàn)檫@不是一個(gè)生產(chǎn)環(huán)境。 |
|