容器中Scrapy Splash缓存清除及登录异常问题排查求助
问题:Scrapy Splash登录失效,抛出异常后反而成功
编辑:此问题并非Zyte专属,在Docker容器中运行时也会出现相同问题。我必须抛出异常才能登录,需要在容器持久化的前提下实现多次运行正常工作。
我原本有个稳定运行的登录函数,突然失效了。排查过程中写了个检查登录状态的新函数,换了好几种Lua脚本重试登录,理论上这些脚本都应该有效,但就是登不上。
def start_requests(self): login_url = "URL" yield SplashRequest( login_url, splash_headers={ # used for initializing zyte splash "Authorization": basic_auth_header(self.settings["APIKEY"], "") }, callback=self.start_scraping, endpoint="execute", cache_args=["lua_source"], args={ "wait": random.uniform(2.1, 3.4), "lua_source": self.LUA_LOGIN_SOURCE, "url": login_url, "ua": self.random_user_agent, }, meta={ "max_retry_times": 0, }, )
后来误加了不带状态码的exit(),触发了unhandled in Deferred错误,之后start_scraping再次运行,居然登录成功了,功能一切正常。
我怀疑这和Zyte/Scrapy的缓存、Cookie存储机制有关。上一个会话的Cookie已经过期,但我觉得这些Cookie不应该在Zyte实例里持久化。
抛出错误是不是会重置Zyte里的Scrapy Splash?这是不是问题解决的关键?我得找到根本原因,不想每次任务都要靠抛未处理错误才能正常运行。
以下是临时的检查/重试函数:
def start_scraping(self, response): if response.xpath("/html/body/h1//text()").extract_first() != "Forbidden": while self.login_counter < 4: self.login_counter += 1 if self.login_counter == 1: self.LUA_LOGIN_SOURCE # if the login function fails on attempt 3, # then try window-not-selected lua version elif self.login_counter == 2: lua_source = self.LUA_LOGIN2_TAB_SOURCE # try unhandled error (logs in successfully) elif self.login_counter == 3: exit() login_url = "URL" yield SplashRequest( login_url, splash_headers={ # used for initializing zyte splash "Authorization": basic_auth_header(self.settings["APIKEY"], "") }, callback=self.start_scraping, endpoint="execute", cache_args=["lua_source"], args={ "wait": random.uniform(4.1, 5.4), "lua_source": lua_source, "url": login_url, "ua": self.random_user_agent, }, meta={ "max_retry_times": 0, }, ) else: print("Logged in!")
有效的Lua函数示例:
function main(splash, args) splash:init_cookies(splash.args.cookies) assert(splash:go{args.url, headers=splash.args.headers, http_method=splash.args.http_method, body=splash.args.body,}) assert(splash:wait(1)) -- splash:send_keys("<Tab>") splash:send_text('<USERNAME>') assert(splash:wait(0.5)) splash:send_keys("<Tab>") assert(splash:wait(0.5)) splash:send_text('<PASSWORD>') assert(splash:wait(0.5)) splash:send_keys("<Return>") assert(splash:wait(2)) return { html = splash:html(), har = splash:har(), png = splash:png(), cookies = splash:get_cookies(), } end
编辑:我还把Cookie存在字典里,不确定和问题有没有关系:
cookies_dict = { cookie["name"]: cookie["value"] for cookie in response.data["cookies"] }
内容的提问来源于stack exchange,提问作者cforcomputer
相关产品推荐
相关产品推荐

