乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

       ccccshq 2015-05-03

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


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


      在上一篇中,我們實(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 genspider stack_crawler -t crawl

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

      stack.spiders.stack_crawler


      Scrapy項(xiàng)目現(xiàn)在看起來(lái)應(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”列表


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


      start_urls = [

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

      ]


      更新“rules”列表


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


      rules = [

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

      callback='parse_item', follow=True)

      ]


      現(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)。


      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


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


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


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


      DOWNLOAD_DELAY = 5


      這告訴爬蟲(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:


      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


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

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

        0條評(píng)論

        發(fā)表

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

        類(lèi)似文章 更多