小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

【下篇】Python下用Scrapy和MongoDB構(gòu)建爬蟲系統(tǒng)

 ccccshq 2015-05-03

(點(diǎn)擊上方藍(lán)字,可快速關(guān)注我們)


提示:在歷史推送中,可查看昨天(04月24日)的上一篇。


在上一篇中,我們實(shí)現(xiàn)了一個(gè)基本網(wǎng)絡(luò)爬蟲,它可以從StackOverflow上下載最新的問題,并將它們存儲(chǔ)在MongoDB數(shù)據(jù)庫中。在本文中,我們將對(duì)其擴(kuò)展,使它能夠爬取每個(gè)網(wǎng)頁底部的分頁鏈接,并從每一頁中下載問題(包含問題標(biāo)題和URL)。


" 在你開始任何爬取工作之前,檢查目標(biāo)網(wǎng)站的使用條款并遵守robots.txt文件。同時(shí),做爬取練習(xí)時(shí)遵守道德,不要在短時(shí)間內(nèi)向某個(gè)網(wǎng)站發(fā)起大量請求。像對(duì)待自己的網(wǎng)站一樣對(duì)待任何你將爬取的網(wǎng)站。"


開始


有兩種可能的方法來接著從上次我們停下的地方繼續(xù)進(jìn)行。


第一個(gè)方法是,擴(kuò)展我們現(xiàn)有的網(wǎng)絡(luò)爬蟲,通過利用一個(gè)xpath表達(dá)式從”parse_item”方法里的響應(yīng)中提取每個(gè)下一頁鏈接,并通過回調(diào)同一個(gè)parse_item方法產(chǎn)生一個(gè)請求對(duì)象。利用這種方法,爬蟲會(huì)自動(dòng)生成針對(duì)我們指定的鏈接的新請求,你可以在Scrapy文檔這里找到更多有關(guān)該方法的信息。


另一個(gè)更簡單的方法是,使用一個(gè)不同類型的爬蟲—CrawlSpider(鏈接)。這是基本Spider的一個(gè)擴(kuò)展版本,它剛好滿足我們的要求。


CrawlSpider


我們將使用與上一篇教程中相同的爬蟲項(xiàng)目,所以如果你需要的話可以從repo上獲取這些代碼。


創(chuàng)建樣板


在“stack”目錄中,首先由crawl模板生成爬蟲樣板。


$ scrapy genspider stack_crawler -t crawl

Created spider 'stack_crawler' using template 'crawl' in module:

stack.spiders.stack_crawler


Scrapy項(xiàng)目現(xiàn)在看起來應(yīng)該像這樣:


├── scrapy.cfg

└── stack

├── __init__.py

├── items.py

├── pipelines.py

├── settings.py

└── spiders

├── __init__.py

├── stack_crawler.py

└── stack_spider.py


stack_crawler.py文件內(nèi)容如下:


# -*- coding: utf-8 -*-

import scrapy

from scrapy.contrib.linkextractors import LinkExtractor

from scrapy.contrib.spiders import CrawlSpider, Rule


from stack.items import StackItem


class StackCrawlerSpider(CrawlSpider):

name = 'stack_crawler'

allowed_domains = ['']

start_urls = ['http://www./']


rules = (

Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),

)


def parse_item(self, response):

i = StackItem()

#i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()

#i['name'] = response.xpath('//div[@id="name"]').extract()

#i['description'] = response.xpath('//div[@id="description"]').extract()

return i


我們只需要對(duì)這個(gè)樣板做一些更新。


更新“start_urls”列表


首先,添加問題的第一個(gè)頁面鏈接到start_urls列表:


start_urls = [

'http:///questions?pagesize=50&sort=newest'

]


更新“rules”列表


接下來,我們需要添加一個(gè)正則表達(dá)式到“rules”屬性中,以此告訴爬蟲在哪里可以找到下一個(gè)頁面鏈接:


rules = [

Rule(LinkExtractor(allow=r'questions?page=[0-9]&sort=newest'),

callback='parse_item', follow=True)

]


現(xiàn)在爬蟲能根據(jù)那些鏈接自動(dòng)請求新的頁面,并將響應(yīng)傳遞給“parse_item”方法,以此來提取問題和對(duì)應(yīng)的標(biāo)題。


如果你仔細(xì)查看的話,可以發(fā)現(xiàn)這個(gè)正則表達(dá)式限制了它只能爬取前9個(gè)網(wǎng)頁,因?yàn)樵谶@個(gè)demo中,我們不想爬取所有的176234個(gè)網(wǎng)頁。


更新“parse_item”方法


現(xiàn)在我們只需編寫如何使用xpath解析網(wǎng)頁,這一點(diǎn)我們已經(jīng)在上一篇教程中實(shí)現(xiàn)過了,所以直接復(fù)制過來。


def parse_item(self, response):

questions = response.xpath('//div[@class="summary"]/h3')


for question in questions:

item = StackItem()

item['url'] = question.xpath(

'a[@class="question-hyperlink"]/@href').extract()[0]

item['title'] = question.xpath(

'a[@class="question-hyperlink"]/text()').extract()[0]

yield item


這就是為爬蟲提供的解析代碼,但是現(xiàn)在先不要啟動(dòng)它。


添加一個(gè)下載延遲


我們需要通過在settings.py文件中設(shè)定一個(gè)下載延遲來善待StackOverflow(和任何其他網(wǎng)站)。


DOWNLOAD_DELAY = 5


這告訴爬蟲需要在每兩個(gè)發(fā)出的新請求之間等待5秒鐘。你也很有必要做這樣的限制,因?yàn)槿绻悴贿@么做的話,StackOverflow將會(huì)限制你的訪問流量,如果你繼續(xù)不加限制地爬取該網(wǎng)站,那么你的IP將會(huì)被禁止。所有,友好點(diǎn)—要像對(duì)待自己的網(wǎng)站一樣對(duì)待任何你爬取的網(wǎng)站。


現(xiàn)在只剩下一件事要考慮—存儲(chǔ)數(shù)據(jù)。


MongoDB


上次我們僅僅下載了50個(gè)問題,但是因?yàn)檫@次我們要爬取更多的數(shù)據(jù),所有我們希望避免向數(shù)據(jù)庫中添加重復(fù)的問題。為了實(shí)現(xiàn)這一點(diǎn),我們可以使用一個(gè)MongoDB的 upsert方法,它意味著如果一個(gè)問題已經(jīng)存在數(shù)據(jù)庫中,我們將更新它的標(biāo)題;否則我們將新問題插入數(shù)據(jù)庫中。


修改我們前面定義的MongoDBPipeline:


class MongoDBPipeline(object):


def __init__(self):

connection = pymongo.Connection(

settings['MONGODB_SERVER'],

settings['MONGODB_PORT']

)

db = connection[settings['MONGODB_DB']]

self.collection = db[settings['MONGODB_COLLECTION']]


def process_item(self, item, spider):

for data in item:

if not data:

raise DropItem("Missing data!")

self.collection.update({'url': item['url']}, dict(item), upsert=True)

log.msg("Question added to MongoDB database!",

level=log.DEBUG, spider=spider)

return item


為簡單起見,我們沒有優(yōu)化查詢,也沒有處理索引值,因?yàn)檫@不是一個(gè)生產(chǎn)環(huán)境。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多