最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何在scrapy中捕獲并處理各種異常

 更新時間:2020年09月28日 17:19:20   作者:海的鄰居  
這篇文章主要介紹了如何在scrapy中捕獲并處理各種異常,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

    使用scrapy進(jìn)行大型爬取任務(wù)的時候(爬取耗時以天為單位),無論主機(jī)網(wǎng)速多好,爬完之后總會發(fā)現(xiàn)scrapy日志中“item_scraped_count”不等于預(yù)先的種子數(shù)量,總有一部分種子爬取失敗,失敗的類型可能有如下圖兩種(下圖為scrapy爬取結(jié)束完成時的日志):

scrapy中常見的異常包括但不限于:download error(藍(lán)色區(qū)域), http code 403/500(橙色區(qū)域)。

不管是哪種異常,我們都可以參考scrapy自帶的retry中間件寫法來編寫自己的中間件。

正文

     使用IDE,現(xiàn)在scrapy項(xiàng)目中任意一個文件敲上以下代碼:

from scrapy.downloadermiddlewares.retry import RetryMiddleware

按住ctrl鍵,鼠標(biāo)左鍵點(diǎn)擊RetryMiddleware進(jìn)入該中間件所在的項(xiàng)目文件的位置,也可以通過查看文件的形式找到該中間件的位置,路徑是:site-packages/scrapy/downloadermiddlewares/retry.RetryMiddleware

該中間件的源代碼如下:

class RetryMiddleware(object):

  # IOError is raised by the HttpCompression middleware when trying to
  # decompress an empty response
  EXCEPTIONS_TO_RETRY = (defer.TimeoutError, TimeoutError, DNSLookupError,
              ConnectionRefusedError, ConnectionDone, ConnectError,
              ConnectionLost, TCPTimedOutError, ResponseFailed,
              IOError, TunnelError)

  def __init__(self, settings):
    if not settings.getbool('RETRY_ENABLED'):
      raise NotConfigured
    self.max_retry_times = settings.getint('RETRY_TIMES')
    self.retry_http_codes = set(int(x) for x in settings.getlist('RETRY_HTTP_CODES'))
    self.priority_adjust = settings.getint('RETRY_PRIORITY_ADJUST')

  @classmethod
  def from_crawler(cls, crawler):
    return cls(crawler.settings)

  def process_response(self, request, response, spider):
    if request.meta.get('dont_retry', False):
      return response
    if response.status in self.retry_http_codes:
      reason = response_status_message(response.status)
      return self._retry(request, reason, spider) or response
    return response

  def process_exception(self, request, exception, spider):
    if isinstance(exception, self.EXCEPTIONS_TO_RETRY) \
        and not request.meta.get('dont_retry', False):
      return self._retry(request, exception, spider)

  def _retry(self, request, reason, spider):
    retries = request.meta.get('retry_times', 0) + 1

    retry_times = self.max_retry_times

    if 'max_retry_times' in request.meta:
      retry_times = request.meta['max_retry_times']

    stats = spider.crawler.stats
    if retries <= retry_times:
      logger.debug("Retrying %(request)s (failed %(retries)d times): %(reason)s",
             {'request': request, 'retries': retries, 'reason': reason},
             extra={'spider': spider})
      retryreq = request.copy()
      retryreq.meta['retry_times'] = retries
      retryreq.dont_filter = True
      retryreq.priority = request.priority + self.priority_adjust

      if isinstance(reason, Exception):
        reason = global_object_name(reason.__class__)

      stats.inc_value('retry/count')
      stats.inc_value('retry/reason_count/%s' % reason)
      return retryreq
    else:
      stats.inc_value('retry/max_reached')
      logger.debug("Gave up retrying %(request)s (failed %(retries)d times): %(reason)s",
             {'request': request, 'retries': retries, 'reason': reason},
             extra={'spider': spider})

查看源碼我們可以發(fā)現(xiàn),對于返回http code的response,該中間件會通過process_response方法來處理,處理辦法比較簡單,大概是判斷response.status是否在定義好的self.retry_http_codes集合中,通過向前查找,這個集合是一個列表,定義在default_settings.py文件中,定義如下:

RETRY_HTTP_CODES = [500, 502, 503, 504, 522, 524, 408]

也就是先判斷http code是否在這個集合中,如果在,就進(jìn)入retry的邏輯,不在集合中就直接return response。這樣就已經(jīng)實(shí)現(xiàn)對返回http code但異常的response的處理了。

但是對另一種異常的處理方式就不一樣了,剛才的異常準(zhǔn)確的說是屬于HTTP請求error(超時),而另一種異常發(fā)生的時候則是如下圖這種實(shí)實(shí)在在的代碼異常(不處理的話):

你可以創(chuàng)建一個scrapy項(xiàng)目,start_url中填入一個無效的url即可模擬出此類異常。比較方便的是,在RetryMiddleware中同樣提供了對這類異常的處理辦法:process_exception

通過查看源碼,可以分析出大概的處理邏輯:同樣先定義一個集合存放所有的異常類型,然后判斷傳入的異常是否存在于該集合中,如果在(不分析dont try)就進(jìn)入retry邏輯,不在就忽略。

OK,現(xiàn)在已經(jīng)了解了scrapy是如何捕捉異常了,大概的思路也應(yīng)該有了,下面貼出一個實(shí)用的異常處理的中間件模板:

from twisted.internet import defer
from twisted.internet.error import TimeoutError, DNSLookupError, \
  ConnectionRefusedError, ConnectionDone, ConnectError, \
  ConnectionLost, TCPTimedOutError
from scrapy.http import HtmlResponse
from twisted.web.client import ResponseFailed
from scrapy.core.downloader.handlers.http11 import TunnelError

class ProcessAllExceptionMiddleware(object):
  ALL_EXCEPTIONS = (defer.TimeoutError, TimeoutError, DNSLookupError,
           ConnectionRefusedError, ConnectionDone, ConnectError,
           ConnectionLost, TCPTimedOutError, ResponseFailed,
           IOError, TunnelError)
  def process_response(self,request,response,spider):
    #捕獲狀態(tài)碼為40x/50x的response
    if str(response.status).startswith('4') or str(response.status).startswith('5'):
      #隨意封裝,直接返回response,spider代碼中根據(jù)url==''來處理response
      response = HtmlResponse(url='')
      return response
    #其他狀態(tài)碼不處理
    return response
  def process_exception(self,request,exception,spider):
    #捕獲幾乎所有的異常
    if isinstance(exception, self.ALL_EXCEPTIONS):
      #在日志中打印異常類型
      print('Got exception: %s' % (exception))
      #隨意封裝一個response,返回給spider
      response = HtmlResponse(url='exception')
      return response
    #打印出未捕獲到的異常
    print('not contained exception: %s'%exception)

spider解析代碼示例:

class TESTSpider(scrapy.Spider):
  name = 'TEST'
  allowed_domains = ['TTTTT.com']
  start_urls = ['http://www.TTTTT.com/hypernym/?q=']
  custom_settings = {
    'DOWNLOADER_MIDDLEWARES': {
      'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
      'TESTSpider.middlewares.ProcessAllExceptionMiddleware': 120,
    },
    'DOWNLOAD_DELAY': 1, # 延時最低為2s
    'AUTOTHROTTLE_ENABLED': True, # 啟動[自動限速]
    'AUTOTHROTTLE_DEBUG': True, # 開啟[自動限速]的debug
    'AUTOTHROTTLE_MAX_DELAY': 10, # 設(shè)置最大下載延時
    'DOWNLOAD_TIMEOUT': 15,
    'CONCURRENT_REQUESTS_PER_DOMAIN': 4 # 限制對該網(wǎng)站的并發(fā)請求數(shù)
  }
  def parse(self, response):
    if not response.url: #接收到url==''時
      print('500')
      yield TESTItem(key=response.meta['key'], _str=500, alias='')
    elif 'exception' in response.url:
      print('exception')
      yield TESTItem(key=response.meta['key'], _str='EXCEPTION', alias='')

Note:該中間件的Order_code不能過大,如果過大就會越接近下載器,就會優(yōu)先于RetryMiddleware處理response,但這個中間件是用來兜底的,即當(dāng)一個response 500進(jìn)入中間件鏈時,需要先經(jīng)過retry中間件處理,不能先由我們寫的中間件來處理,它不具有retry的功能,接收到500的response就直接放棄掉該request直接return了,這是不合理的。只有經(jīng)過retry后仍然有異常的request才應(yīng)當(dāng)由我們寫的中間件來處理,這時候你想怎么處理都可以,比如再次retry、return一個重新構(gòu)造的response。

下面來驗(yàn)證一下效果如何(測試一個無效的URL),下圖為未啟用中間件的情況:

再啟用中間件查看效果:

ok,達(dá)到預(yù)期效果:即使程序運(yùn)行時拋出異常也能被捕獲并處理。

到此這篇關(guān)于如何在scrapy中捕獲并處理各種異常的文章就介紹到這了,更多相關(guān)scrapy 捕獲處理異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python?Haul利器簡化數(shù)據(jù)爬取任務(wù)提高開發(fā)效率

    Python?Haul利器簡化數(shù)據(jù)爬取任務(wù)提高開發(fā)效率

    Haul?是一個專門為數(shù)據(jù)爬取任務(wù)而設(shè)計的?Python?庫,它提供了一系列的工具和功能,幫助我們輕松處理數(shù)據(jù)爬取中的重復(fù)工作和復(fù)雜問題
    2024-01-01
  • Python?OpenCV識別行人入口進(jìn)出人數(shù)統(tǒng)計

    Python?OpenCV識別行人入口進(jìn)出人數(shù)統(tǒng)計

    本文主要介紹了Python?OpenCV識別行人入口進(jìn)出人數(shù)統(tǒng)計,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>
    2023-01-01
  • python輸出100以內(nèi)的質(zhì)數(shù)與合數(shù)實(shí)例代碼

    python輸出100以內(nèi)的質(zhì)數(shù)與合數(shù)實(shí)例代碼

    本文通過實(shí)例代碼給大家介紹了python輸出100以內(nèi)的質(zhì)數(shù)與合數(shù)的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧
    2018-07-07
  • Python?多線程爬取案例

    Python?多線程爬取案例

    這篇文章主要介紹了Python?多線程爬取案例,爬蟲屬于I/O密集型的程序,所以使用多線程可以大大提高爬取效率,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-08-08
  • Python語法快速入門指南

    Python語法快速入門指南

    這篇文章主要介紹了Python語法快速入門指南,包括注釋和引號的使用等基本語法知識,需要的朋友可以參考下
    2015-10-10
  • PyQt5每天必學(xué)之創(chuàng)建窗口居中效果

    PyQt5每天必學(xué)之創(chuàng)建窗口居中效果

    這篇文章主要介紹了PyQt5每天必學(xué)之創(chuàng)建窗口居中效果,使應(yīng)用程序窗口顯示在屏幕的中心,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • python消費(fèi)kafka數(shù)據(jù)批量插入到es的方法

    python消費(fèi)kafka數(shù)據(jù)批量插入到es的方法

    今天小編就為大家分享一篇python消費(fèi)kafka數(shù)據(jù)批量插入到es的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • Python基礎(chǔ)教程之異常處理詳解

    Python基礎(chǔ)教程之異常處理詳解

    Python的異常處理能力是很強(qiáng)大的,它有很多內(nèi)置異常,可向用戶準(zhǔn)確反饋出錯信息,下面這篇文章主要給大家介紹了關(guān)于Python基礎(chǔ)教程之異常處理的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • Python實(shí)現(xiàn)新版正方系統(tǒng)滑動驗(yàn)證碼識別

    Python實(shí)現(xiàn)新版正方系統(tǒng)滑動驗(yàn)證碼識別

    這篇文章主要介紹了基于Python實(shí)現(xiàn)新版正方系統(tǒng)滑動驗(yàn)證碼識別算法和方案,文中示例代碼對我們的學(xué)習(xí)和工作有一定的幫助,感興趣的可以了解一下
    2021-12-12
  • 基于Python的接口測試框架實(shí)例

    基于Python的接口測試框架實(shí)例

    下面小編就為大家?guī)硪黄赑ython的接口測試框架實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11

最新評論

庄河市| 临高县| 盘山县| 新巴尔虎左旗| 花垣县| 梅州市| 藁城市| 沛县| 舟曲县| 望城县| 青海省| 内丘县| 东阳市| 古丈县| 昭通市| 康平县| 隆德县| 靖远县| 日照市| 桐梓县| 盐源县| 西乡县| 怀远县| 长子县| 乌海市| 乌拉特后旗| 上饶市| 德惠市| 高台县| 南川市| 井冈山市| 湟中县| 进贤县| 扶余县| 江达县| 晴隆县| 凤山县| 全椒县| 瑞丽市| 新余市| 临朐县|