原来在网上找了一份python版实现, 见这里 ,仿照着这个用go语言实现了一编。

只是在实现的过程中,go的http cookie比较麻烦,也是从网上找了一段InMemoryCookieJar

总的来说go语言还是挺方便的。

直接贴代码吧:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main

import (
	"fmt"
	"os"
	"net/http"
	"net/url"
	"io/ioutil"
	"regexp"
	"strings"
)

type InMemoryCookieJar struct{
	storage map[string][]http.Cookie
}

// buggy... but works

func (jar InMemoryCookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
	for _, ck := range cookies {
		path := ck.Domain
		if ck.Path != "/" {
			path = ck.Domain + ck.Path
		}
		if ck.Domain[0] == '.' {
			path = path[1:]		// FIXME: .hi.baidu.com won't match hi.baidu.com
		}
		if _, found := jar.storage[path]; found {
			setted := false
			for i, v := range jar.storage[path] {
				if v.Name == ck.Name {
					jar.storage[path][i] = *ck
					setted = true
					break
				}
			}
			if ! setted {
				jar.storage[path] = append(jar.storage[path], *ck)
			}
		} else {
			jar.storage[path] = []http.Cookie{*ck}
		}
	}
}

func (jar InMemoryCookieJar) Cookies(u *url.URL) []*http.Cookie {
	cks := []*http.Cookie{}
	//fmt.Println("get cookies", u)
	for pattern, cookies := range jar.storage {
		if strings.Contains(u.String(), pattern) {
			for i := range cookies {
				cks = append(cks, &cookies[i])
				//fmt.Println("add cookie", cookies[i].Name, cookies[i].Value)
			}
		}
	}
	return cks
}

func newCookieJar() InMemoryCookieJar {
	storage := make(map[string][]http.Cookie)
	return InMemoryCookieJar{storage}
}

func checkError(err error) {
	if err != nil {
		fmt.Println("Fatal error ", err.Error())
		os.Exit(1)
	}
}

func check(b string)  {
	pattern := regexp.MustCompile(`<div class="idh">(已连续签到\d+天)</div>`)
	s := pattern.FindStringSubmatch(string(b))
	
	if len(s) > 0 {
		fmt.Println("[Succeed] Checkin Already!", s[1])
	} else {
		fmt.Println("[Error] Login Failed!")
	}
}

func main() {
	if len(os.Args) != 3 {
		fmt.Println("Usage: ", os.Args[0], "email password")
		os.Exit(1)
	}

	email := os.Args[1]
	passwd := os.Args[2]

	client := http.Client{Jar: newCookieJar()}

	resp, err := client.PostForm("http://www.xiami.com/web/login", url.Values{
		"email": {email},
		"password": {passwd},
		"LoginButton": {"登陆"},
	})
	checkError(err)
	resp.Body.Close()
	
	resp, err = client.Get("http://www.xiami.com/web/login")
	checkError(err)
	b, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	// check if login already
	pattern := regexp.MustCompile(`<a class="check_in" href="(.*?)">`)
	if m := pattern.FindStringSubmatch(string(b)); len(m) == 0 {
		// already checkin | login failed
	        check(string(b))
	} else {
		// start checking in
		url := "http://www.xiami.com" + m[1]
		request, err := http.NewRequest("GET", url, nil)
		checkError(err)
		request.Header.Add("Referer", "http://www.xiami.com/web/login")
		request.Header.Add("User-Agent", "Opera/9.60")
		resp, err = client.Do(request)
		checkError(err)
		b, _ := ioutil.ReadAll(resp.Body)
		defer resp.Body.Close()
		check(string(b))
	}
}