故障分析系列(01) —— scrapy爬蟲速度突然變慢原因分析

故障分析系列(01) —— scrapy爬蟲速度突然變慢原因分析

1. 問題背景

  • 在所有環境都沒變的情況下,scrapy爬蟲每天能爬取的數據量從3月5號開始急劇減少,後面幾天數據量也是越來越少。
    這裏寫圖片描述

2. 環境

  • 系統:win7
  • python 3.6.1
  • scrapy 1.4.0
  • 網絡:電信100Mb
  • 代理:阿布雲(服務商是阿里雲)
  • 爬取站點:amazon,amztracker

3. 排查步驟

3.1. 抓取scrapy爬蟲的Log

# 文件 settings.py中
import datetime

LOG_LEVEL = 'DEBUG'		# log等級設置爲debug模式
startDate = datetime.datetime.now().strftime('%Y%m%d')
LOG_FILE = f"redisClawerSlaver_1_log{startDate}.txt"	# 將log寫入文件中

# 小技巧:因爲debug模式下,一天下來,log會非常大,用Notepad++無法打開,可以使用UltraEdit來打開
  • 後來分析Log,搜索failed, 發現了大量的 timeout error,佔到了錯誤的九成,而且這兩個站點的鏈接都有:

  • 大量的Timeout會導致大量的重試,而且每個timeout,都要等待20s,才返回錯誤,所以極大的拉慢了爬蟲的速度。
    這裏寫圖片描述

  • 結論1:所以大膽猜測可能有幾個原因:

  • 第一,本地網絡變慢。

  • 第二,爬取的站點發生了變化,包括爬取的內容發生了變化。

  • 第三,阿布雲代理故障。

  • 第四,爬蟲錯誤。

  • **思考與完善:**其實在這一步,應該做好詳細的error統計的,記錄在數據庫中,這個後期要完善起來。補充一下,形如此類:

# 文件 spider.py中
from scrapy.spidermiddlewares.httperror import HttpError
from twisted.internet.error import TimeoutError, TCPTimedOutError, DNSLookupError, ConnectionRefusedError

yield response.follow(
    url=re.sub(r'page=\d+',f'page={page}',url,count=1),
    meta={'dont_redirect':True,'key':response.meta['key']},
    callback=self.galance,
    errback=self.error    # 做好error記錄
)

RETRY = 4    # settings中最大重試次數

def error(self, failure):
    if failure.check(HttpError):
        response = failure.value.response
        if response.meta['depth'] < RETRY:
            failure.request.dont_filter = True
            yield failure.request
        else:
            yield {
                'url': response.url, 'error': 'HttpError', 'depth': response.meta['depth'],
                'priority': response.request.priority, 'status': response.status,
                'callback': response.request.callback.__name__,
                'key': response.meta.get('key') or response.meta.get('item', {}).get('key', ''),
            }  # 日誌用

    elif failure.check(TimeoutError, TCPTimedOutError, ConnectionRefusedError, DNSLookupError):
        request = failure.request
        yield {
            'url': request.url,
            'error': 'TimeoutError',
            'priority': request.priority,
            'callback': request.callback.__name__,
            'key': request.meta.get('key') or request.meta.get('item', {}).get('key', ''),
        }  # 日誌用,只在最後一次超時後才執行

    else:
        request = failure.request
        yield {'url': request.url, 'error': 'UnknownError', 'priority': request.priority,
               'callback': request.callback.__name__}  # 日誌用

3.2. 爬取站點以及鏈接檢查。

2018-03-17 00:10:29 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.amazon.com/s/ref=lp_3734591_nr_n_6/143-5700955-1921713?fst=as%3Aoff&rh=n%3A1055398%2Cn%3A%211063498%2Cn%3A1063278%2Cn%3A1063282%2Cn%3A3734591%2Cn%3A3734671&bbn=3734591&ie=UTF8&qid=1517900687&rnid=3734591> (failed 1 times): User timeout caused connection failure: Getting https://www.amazon.com/s/ref=lp_3734591_nr_n_6/143-5700955-1921713?fst=as%3Aoff&rh=n%3A1055398%2Cn%3A%211063498%2Cn%3A1063278%2Cn%3A1063282%2Cn%3A3734591%2Cn%3A3734671&bbn=3734591&ie=UTF8&qid=1517900687&rnid=3734591 took longer than 20.0 seconds..
2018-03-17 00:10:29 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.amazon.com/s/ref=lp_3422251_nr_n_8/134-3091133-0771864?fst=as%3Aoff&rh=n%3A3375251%2Cn%3A%213375301%2Cn%3A10971181011%2Cn%3A3407731%2Cn%3A3422251%2Cn%3A7261122011&bbn=3422251&ie=UTF8&qid=1517900684&rnid=3422251> (failed 1 times): User timeout caused connection failure: Getting https://www.amazon.com/s/ref=lp_3422251_nr_n_8/134-3091133-0771864?fst=as%3Aoff&rh=n%3A3375251%2Cn%3A%213375301%2Cn%3A10971181011%2Cn%3A3407731%2Cn%3A3422251%2Cn%3A7261122011&bbn=3422251&ie=UTF8&qid=1517900684&rnid=3422251 took longer than 20.0 seconds..

  • 結論2:發現這些失敗的鏈接基本上都能在瀏覽器中打開,說明站點和本地網絡的聯通度沒有問題。

3.3. 本地網絡和代理網絡檢查。

3.3.1. 本地網絡檢查

  • 可以選擇三種方式來確認:
  • 第一種:找專門的網速測試網站,進行測試。
    這裏寫圖片描述
    這裏寫圖片描述
  • 第二種:360寬帶測試。
    這裏寫圖片描述
  • 第三種:編寫腳本,直接爬取對應站點,觀察所需的時間。
  • 其實,到這一步的時候,就應該看出問題所在了,只是當時有盲點,只測試了amazon站,而沒有去測試amztracker站,導致後面走了很多彎路。不說了,看看走的彎路吧…
The speed result of not use proxy for amazon detail page. 
No_proxy Totalurls:20, successCount:20, totalSuccessTime:68.56400000000001, avgTime:3.4282000000000004, connectFailCount:0, proxyFailCount:0
  • 結論3:本地網絡連通度和速度都沒有問題。

3.3.2. 代理網絡檢查

Amazon Totalurls:20, successCount:14, totalSuccessTime:104.4075, avgTime:7.457678571428572, connectFailCount:0, proxyFailCount:6
  • 於是找到阿布雲代理,詳細瞭解了他們代理的一些信息,比如說動態IP的時效性是20(爲了提高爬蟲速度,將timeout時間設置爲了20s,這纔是最合理的),然後請他們提供了一下我的代理使用情況的統計數據:
    這裏寫圖片描述
  • 這是按天統計的數據,從這份數據中可以看到,每天scrapy向代理髮送的請求數(下載流量/請求(KB))基本上維持不變,下載時長也一致,但是下載的數據量(下載流量/分(KB), 累計下載(MB))明顯變少。
  • 說明什麼問題?:說明爬蟲發出去的請求量沒變,但是代理爬取下來的數據量明顯變少,也就是說代理沒法爬下來數據,問題在出在代理方

4. 故障原因

  • 然後在原有爬蟲設置的基礎之上,分別來跑 timeout 的url,最後發現:當跑amztracker站的鏈接時,在不加代理的情況下,是可以抓下來的。
2018-03-22 14:09:02 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.amztracker.com/unicorn.php?rank=189599&category=Sports+%26+Outdoors> (referer: www.amazon.com)
  • 但是在加代理的情況下,就發現這個amztracker站的鏈接都抓不下來。
# 在middleware.py中增加代理的情況下,會無法抓下來

18-03-21 11:09:22 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.amztracker.com/unicorn.php?rank=189599&category=Sports+%26+Outdoors> (failed 1 times): User timeout caused connection failure: Getting https://www.amztracker.com/unicorn.php?rank=189599&category=Sports+%26+Outdoors took longer than 20.0 seconds..
  • 也就發現,是代理無法抓到amztracker這個站的頁面。所以找到阿布雲的客服人員,最終發現原因是:因爲是召開2018全國兩會期間,對國外站進行了管控,阿布雲這邊對amztracker站進行了屏蔽,後來他們將這個站的屏蔽打開,問題得以最終解決。

  • 最終總結:其實在一開始的時候,就有機會很快分析問題的所在的。重點是做到心中有數,知道自己爬取了哪些頁面,這些頁面是否都能爬取,這些頁面在加代理的情況下是否能爬取,需要做這樣的測試。如果一開始就做了這樣的測試,結果很快就出來了,而不用折騰這麼久。

  • 我們再看一下,爬蟲在正常情況下,上傳和下載的速度的對比情況如下,一旦爬蟲異常,從速度上就可以觀測得到:
    這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章