我一直在创建一个登录并抓取网站的Android应用。不幸的是,我一直遇到JSoup和持久化会话cookie的问题。
每当我尝试发出POST请求时,网站都会抱怨会话已过期。我已将问题的原因隔离到JSESSIONID
cookie(因为在尝试登录时在浏览器上删除它会产生相同的结果)。但是,即使我使用.cookies()
方法包含所有以前的Cookie,网站仍会抱怨会话已过期。
我想知道我是否犯了任何明显错误,阻止我的应用程序正确维护会话。
到目前为止我的代码的相关部分(注意:我在这个项目中使用Kotlin):
val url = "omitted here"
val username = "user"
val password = "hunter2"
val initial = Jsoup.connect(url)
.method(Connection.Method.GET).execute()
val cookies = initial.cookies()
val login = Jsoup.connect(url)
.userAgent("Mozilla")
.data("login_name", username)
.data("password", password)
.cookies(cookies)
.post()
非常感谢任何帮助!
答案 0 :(得分:1)
您的代码看起来是正确的,假设Cookie是由服务器设置的,而不是稍后通过JavaScript设置的。假设没有丢失代码,cookie应该进入第二个请求。可能是您误解了网站的工作方式以及它如何使用Cookie,也许它在登录前不会分配有效的Cookie,并且总是在任何未登录的Cookie中抱怨“会话已过期”。可能根本不是代码错误,而是逻辑问题。
但是,如果您不考虑以下事项,那么您的完整代码 也可能错误:
您需要记住,当该特定请求从服务器收到Set-Cookie
标头时,Jsoup库仅返回请求的cookie。它不返回“所有已知的cookie”列表。因此,您必须维护一个映射,该映射是每个cookie响应的持续累积。
将response.cookies()
方法视为实际为response.newCookiesAddedFromThisRequest()
。代码模式是:
val cookies = mutableMapOf<String, String>()
val initialResponse = Jsoup.connect("http://www.whatarecookies.com/cookietest.asp")
.method(Connection.Method.GET)
.cookies(cookies)
.execute()
cookies.putAll(initialResponse.cookies())
val secondResponse = Jsoup.connect("http://www.whatarecookies.com/cookietest.asp")
.method(Connection.Method.GET)
.cookies(cookies)
.execute()
cookies.putAll(secondResponse.cookies())
// `cookies` now contains all cookies added accumulatively
在此代码中,每次将已返回的新Cookie添加到Cookie的托管地图中,并且每个请求都会发送所有Cookie的总数。
另请注意: Jsoup不按标题顺序处理Cookie,因此有时会为Cookie设置错误的值。它有时也会在事故中将cookie值保留为null。您应该检查Jsoup的known cookie issues。另一种方法是使用OkHttp之类的东西来检索文档,然后使用Jsoup解析它。 Jsoup没有像在HTTP解析和操作上那样关注HTTP协议。