- 编辑:这不是特定于Zyte,我在Docker容器中运行时也有同样的问题。我必须抛出一个异常才能登录。我需要它的工作多次运行,同时有容器是持久的。
我这里有一个登录功能,最初工作可靠,但它停止工作,我一直试图找出原因。在我尝试修复这个问题的过程中,我创建了一个新函数来检查登录成功,然后用不同的lua脚本重复登录。然而,这并不起作用,任何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或Scrappy中的该高速缓存有关,也许与我存储cookie的方式有关。cookie在最后一个会话结束时过期,但我认为它们不应该在Zyte示例中保留。
在Zyte中抛出一个错误会重置Scrapy Splash吗?这就是为什么它要修复这个问题吗?我需要弄清楚为什么会发生这种情况,这样我就不需要在每个作业开始时抛出一个未处理的错误了。
下面是QUICK AND DIRTY检查/重试功能:
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"]
}
1条答案
按热度按时间gupuwyp21#
问题是在LUA脚本中,我在start_requests方法中调用了
splash:init_cookies(splash.args.cookies)
。默认情况下,scrappy将cookie存储在cookie jar中。当您调用splash:init_cookies
时,您正在从cookie jar中检索cookie并替换请求中的cookie。由于cookie jar中没有cookie,因此请求失败。然后,由于新的请求cookie随后没有添加到cookie jar中,因此在下一次请求重试中,相同的错误将重复。通过抛出一个未处理的错误,我猜cookie jar内容在没有LUA脚本替换它们的情况下被更新,然后在下一个循环中,它能够从cookie jar初始化正确的cookie并成功运行。
从初始请求中删除
splash:init_cookies(splash.args.cookies)
解决了这个问题。在页面提取LUA脚本(而不是登录脚本)中保持init继续工作,以将登录cookie传输到每个新页面。