最近在学习 scala ,用 v 站签到来练练手。 这个签到脚本主要是参考 https://github.com/lqccan/v2ex-sign/blob/master/v2ex.py 这位 v 友写的签到脚本,自己用 scala 实现了一下,登录是没问题的,但是到最后一步 /mission/daily/redeem?once=xxx 时却失败了,返回 302 ,跳转回 /mission/daily 页面。 以下是代码:
import java.net.HttpCookie
import scalaj.http.{Http, HttpResponse}
object V2Sigin2 {
  def main(args: Array[String]): Unit = {
    val signPage: HttpResponse[String] = Http("http://www.v2ex.com/signin").asString
    val html = signPage.body
    val cookieMap: scala.collection.mutable.Map[String, HttpCookie] = scala.collection.mutable.Map[String, HttpCookie]()
    signPage.cookies.foreach(f => cookieMap.put(f.getName, f))
    val nameMatch = "type=\"text\" class=\"sl\" name=\"([a-f0-9]{64,64})\"".r findFirstMatchIn html
    val pwdMatch = "type=\"password\" class=\"sl\" name=\"([a-f0-9]{64,64})\"".r findFirstMatchIn html
    val onceMatch = "value=\"(\\d+)\" name=\"once\"".r findFirstMatchIn html
    val nameName = if (nameMatch.isEmpty) "" else nameMatch.get.group(1)
    val pwdName = if (pwdMatch.isEmpty) "" else pwdMatch.get.group(1)
    val once = if (onceMatch.isEmpty) "" else onceMatch.get.group(1)
    val next = "/"
    val loginResult = Http("http://www.v2ex.com/signin").postForm(
      Seq(nameName -> "username",
        pwdName -> "password",
        "once" -> once,
        "next" -> next
      )
    ).headers(Seq("Referer" -> "http://www.v2ex.com/signin",
      "User-Agent" -> "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0"
    ))
      //      .cookies(signPage.cookies)
      .cookies(cookieMap.values.toSeq)
      .asString
    loginResult.cookies.foreach(f => cookieMap.put(f.getName, f))
    if (loginResult.code == 302) {
      val dailyResult = Http("http://www.v2ex.com/mission/daily")
        //      .cookies(loginResult.cookies)
        .cookies(cookieMap.values.toSeq)
        .asString
      dailyResult.cookies.foreach(f => cookieMap.put(f.getName, f))
      if (dailyResult.code != 200) {
        println("没有登录无法签到!")
        return
      }
      if (dailyResult.body.indexOf("fa-ok-sign") > -1) {
        println("本日已签到!")
      } else {
        val dailyMatch = "(/mission/daily/redeem\\?once=\\d+)".r findFirstMatchIn dailyResult.body
        val daily = if (dailyMatch.isEmpty) "" else dailyMatch.get.group(1)
        val signResult = Http("http://www.v2ex.com" + daily)
          .cookies(cookieMap.values.toSeq)
          //          .cookies(loginResult.cookies)
          //          .cookies(dailyResult.cookies)
          .headers(
          Seq("Referer" -> "http://www.v2ex.com/mission/daily",
            "User-Agent" -> "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0",
            "Host" -> "www.v2ex.com",
            "Connection" -> "keep-alive"
          )
        ).asString
        println(signResult.code)
        signResult.cookies.foreach(f => cookieMap.put(f.getName, f))
        println("签到成功!")
      }
    } else {
      println("登录失败!")
    }
    println("============")
    println(cookieMap)
  }
}
一开始以为是 cookie 问题,因为那位 v 友用的 python 的 requests.Session()是能自动管理 cookie 的,而我用的 http 包没有管理上下文的功能,但是不管我怎么设置 cookie ,最终都是返回 302 ,问题出在哪里呢? 代码写的不是很好,大家轻拍。。
自己重新用火狐分析了下登录、签到的相关报文,发现最后请求http://www.v2ex.com/mission/daily/redeem?once=xxx时比正常浏览器请求少了一个 cookie:V2EX_TAB,后面排查了一下,发现这个cookie是在登录成功后,跳转到首页时set进去的,而我上面的代码,在登录成功收到httpcode 302后,就直接进行签到的操作了,没有跳转首页,所以少了这个cookie。
重新修改代码,登录后跳转一次首页获取V2EX_TAB这个cookie,再继续后面操作,就能正常签到了。
|  |      1hicdn      2016-07-04 22:33:56 +08:00  1 #!/bin/sh cookie='' UA='' url=$( curl 'https://v2ex.com/mission/daily' -A "$UA" -H 'pragma: no-cache' -H 'dnt: 1' -H 'accept-language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4' -H 'upgrade-insecure-requests: 1' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'cache-control: no-cache' -H "cookie: $cookie" -H 'referer: https://v2ex.com/' | fgrep 'location.href ' | awk -F"'" '{print $(NF-1)}') curl "https://v2ex.com$url" --referer "https://v2ex.com/mission/daily" -H "cookie: $cookie" -A "$UA" -H 'pragma: no-cache' -H 'dnt: 1' -H 'accept-encoding: gzip, deflate, sdch' -H 'accept-language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4' -H 'upgrade-insecure-requests: 1' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'cache-control: no-cache' | 
|      2mx1700      2016-07-05 08:05:19 +08:00 via Android  1 领取每日奖励的请求本来就是个 302 跳转吧 |