關(guān)于python scrapy中添加cookie踩坑記錄
問題發(fā)現(xiàn):
前段時間項(xiàng)目中,為了防止被封號(提供的可用賬號太少),對于能不登錄就可以抓取的內(nèi)容采用不帶cookie的策略,只有必要的內(nèi)容才帶上cookie去訪問。
本來想著很簡單:在每個拋出來的Request的meta中帶上一個標(biāo)志位,通過在CookieMiddleware中查看這個標(biāo)志位,決定是否是給這個Request是否裝上Cookie。
實(shí)現(xiàn)的代碼大致如下:
class CookieMiddleware(object): """ 每次請求都隨機(jī)從賬號池中選擇一個賬號去訪問 """ def __init__(self): client = pymongo.MongoClient(MONGO_URI) self.account_collection = client[MONGO_DATABASE][ACCOUNT_COLLECTION] def process_request(self, request, spider): if 'target' in request.meta: logging.debug('進(jìn)入到process_request了') flag = request.meta['target'] if flag != 'no': all_count = self.account_collection.find({'status': 'success'}).count() if all_count == 0: raise Exception('當(dāng)前賬號池為空') random_index = random.randint(0, all_count - 1) random_account = self.account_collection.find({'status': 'success'})[random_index] request.cookies = json.loads(random_account['cookie']) else: logging.debug('對XXX的請求不做處理') else: all_count = self.account_collection.find({'status': 'success'}).count() if all_count == 0: raise Exception('當(dāng)前賬號池為空') random_index = random.randint(0, all_count - 1) random_account = self.account_collection.find({'status': 'success'})[random_index] request.cookies = json.loads(random_account['cookie'])
在settings.py中的配置如下:
DOWNLOADER_MIDDLEWARES = { 'eyny.middlewares.CookieMiddleware': 550, }
到這里可能有些大佬已經(jīng)能夠看出端倪了,和我一樣認(rèn)為這么寫沒啥問題的同志們繼續(xù)往下看。
在這么編寫完之后,我正常開啟了項(xiàng)目,還適當(dāng)調(diào)高了并發(fā)量,然后第二天發(fā)現(xiàn)賬號被封了。在debug過程中看到在抓取不需要攜帶cookie的url的時候,依然攜帶了cookie,并且cookie是被放在了header中,經(jīng)過我花費(fèi)了兩個多小時查看框架源碼之后,終于發(fā)現(xiàn)了原因。
原因&解決方案:
在scrapy的settings目錄下的default_settings.py文件中,初始聲明了一些DOWNLOADER_MIDDLEWARES_BASE,這些middlewares的聲明如下:
DOWNLOADER_MIDDLEWARES_BASE = { # Engine side 'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100, 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300, 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350, 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400, 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500, 'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550, 'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560, 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590, 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600, 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700, 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750, 'scrapy.downloadermiddlewares.stats.DownloaderStats': 850, 'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900, # Downloader side }
可以看到在DOWNLOADER_MIDDLEWARES_BASE中也聲明了一個CookiesMiddleware,而且是700,也就是說比我們寫的CookieMiddleware(500)要靠后執(zhí)行,而且在debug過程中也看到,在執(zhí)行完我們編寫的CookieMiddleware之后,header中沒有攜帶cookie,但是在執(zhí)行完scrapy.downloadermiddlewares.cookies.CookiesMiddleware: 700之后,在header中看到了cookie,這說明cookie是scrapy幫我們自動加了。
我們打開scrapy.downloadermiddlewares.cookies.CookiesMiddleware的實(shí)現(xiàn)源碼,主要關(guān)注process_request方法:
class CookiesMiddleware(object): """This middleware enables working with sites that need cookies""" def __init__(self, debug=False): self.jars = defaultdict(CookieJar) self.debug = debug @classmethod def from_crawler(cls, crawler): if not crawler.settings.getbool('COOKIES_ENABLED'): raise NotConfigured return cls(crawler.settings.getbool('COOKIES_DEBUG')) def process_request(self, request, spider): if request.meta.get('dont_merge_cookies', False): return cookiejarkey = request.meta.get("cookiejar") jar = self.jars[cookiejarkey] cookies = self._get_request_cookies(jar, request) for cookie in cookies: jar.set_cookie_if_ok(cookie, request) # set Cookie header request.headers.pop('Cookie', None) jar.add_cookie_header(request) self._debug_cookie(request, spider) def process_response(self, request, response, spider): if request.meta.get('dont_merge_cookies', False): return response # extract cookies from Set-Cookie and drop invalid/expired cookies cookiejarkey = request.meta.get("cookiejar") jar = self.jars[cookiejarkey] jar.extract_cookies(response, request) self._debug_set_cookie(response, spider) return response
在上面的代碼中,最中要的是process_request方法中的內(nèi)容,可以看到首先從request.meta中查看有沒有dont_merge_cookies屬性,如果沒有或者為false,就不運(yùn)行剩下的方法,臥槽,這就是我們要找的方法呀!是不是好簡單…
特別注意:如果要使用dont_merge_cookies=true,那么需要我們自己將cookie加入到header中,通過**request.cookies = json.loads(random_account[‘cookie'])**方式添加的cookie,scrapy也不再會幫我們合并到header 中了。
解決方案:我們的解決方法就是在request的meta中加入dont_merge_cookies屬性,并設(shè)置為true,在CookieMiddleware中,我們將cookie添加在header中,而不是賦值給request.cookies
問題解決了,但是這么簡單是不是很不爽,所以就繼續(xù)想看看是為什么scrapy可以自動給我們加上cookie,這個接下來就需要讀下面的代碼了。
總結(jié)
到此這篇關(guān)于關(guān)于python scrapy中添加cookie踩坑記錄的文章就介紹到這了,更多相關(guān)scrapy cookie問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python實(shí)現(xiàn)畫五角星和螺旋線的示例
今天小編就為大家分享一篇python實(shí)現(xiàn)畫五角星和螺旋線的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01Tensorflow 實(shí)現(xiàn)將圖像與標(biāo)簽數(shù)據(jù)轉(zhuǎn)化為tfRecord文件
今天小編就為大家分享一篇Tensorflow 實(shí)現(xiàn)將圖像與標(biāo)簽數(shù)據(jù)轉(zhuǎn)化為tfRecord文件,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02Python中的Numeric包和Numarray包使用教程
這篇文章主要介紹了Python中的Numeric包和Numarray包使用教程,來自IBM官方網(wǎng)站上的技術(shù)文檔,需要的朋友可以參考下2015-04-04在Python中執(zhí)行系統(tǒng)命令的方法示例詳解
最近在做那個測試框架的時候發(fā)現(xiàn)對python執(zhí)行系統(tǒng)命令不太熟悉,所以想著總結(jié)下,下面這篇文章主要給大家介紹了關(guān)于在Python中執(zhí)行系統(tǒng)命令的方法,需要的朋友可以參考借鑒,下面來一起看看吧。2017-09-09Python借助with語句實(shí)現(xiàn)代碼段只執(zhí)行有限次
這篇文章主要介紹了Python借助with語句實(shí)現(xiàn)代碼段只執(zhí)行有限次,首先要定義一個能夠在with語句中使用的類實(shí)現(xiàn)enter和exit,下文詳細(xì)介紹需要的小伙伴可以參考一下2022-03-03python list中append()與extend()用法分享
列表是以類的形式實(shí)現(xiàn)的?!皠?chuàng)建”列表實(shí)際上是將一個類實(shí)例化。因此,列表有多種方法可以操作2013-03-03python反轉(zhuǎn)(逆序)字符串的6種方法詳細(xì)
這篇文章主要介紹了python反轉(zhuǎn)(逆序)字符串的6種方法詳細(xì),需要的朋友可以參考下2021-04-04