故障分析系列(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. 爬取站點以及鏈接檢查。
- 這個部分,可以參考之前的文章:
- python實現自動監測目標網站的爬取速度_以及整體網絡環境分析:http://blog.csdn.net/zwq912318834/article/details/77411148
- 第二種方式:就是將Log中這些失敗的鏈接放到瀏覽器中,看能不能打開。
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. 本地網絡和代理網絡檢查。
- 這個部分,也可以參考之前的文章:
- python實現自動監測目標網站的爬取速度_以及整體網絡環境分析:http://blog.csdn.net/zwq912318834/article/details/77411148
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. 代理網絡檢查
- 由於當時看到每天跑的**環境腳本(http://blog.csdn.net/zwq912318834/article/details/77411148)**中出現了代理失誤率比較高的情況,而且速度達到了8秒左右,如下所示,所以,比較懷疑是代理這邊出現問題。
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站進行了屏蔽,後來他們將這個站的屏蔽打開,問題得以最終解決。
-
最終總結:其實在一開始的時候,就有機會很快分析問題的所在的。重點是做到心中有數,知道自己爬取了哪些頁面,這些頁面是否都能爬取,這些頁面在加代理的情況下是否能爬取,需要做這樣的測試。如果一開始就做了這樣的測試,結果很快就出來了,而不用折騰這麼久。
-
我們再看一下,爬蟲在正常情況下,上傳和下載的速度的對比情況如下,一旦爬蟲異常,從速度上就可以觀測得到: