package login
import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
)
func New() *Login2Yougou {
return &Login2Yougou{nil, false, 0, nil}
}
type Login2Yougou struct {
client *http.Client // client http
isLogin bool // 是否成功登录
iSerialNumber uint64 // 流水号,初时值可以固定,但每次请求自增,服务器会效验
cookie []*http.Cookie // cookies 以便多个client复用
}
//------------------------------------------------------------------------------
// 属性
func (this *Login2Yougou) SetCookies(cok []*http.Cookie) {
this.cookie = cok
}
func (this *Login2Yougou) GetCookies() []*http.Cookie {
return this.cookie
}
func (this *Login2Yougou) GetClient() *http.Client {
return this.client
}
func (this *Login2Yougou) GetLoginResult() bool {
return this.isLogin
}
func (this *Login2Yougou) GetSerialNumber() uint64 {
num := this.iSerialNumber
this.iSerialNumber += 1 // 下次请求流水号要自增1
return num
}
//------------------------------------------------------------------------------
// 操作
// 获取主页html 返回html字符串
func (this *Login2Yougou) getMainPage(url string) (ret string) {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
this.client = &http.Client{Transport: tr}
resp, err := this.client.Get(url)
defer resp.Body.Close()
// 获取失败
if err != nil {
fmt.Println("error:", err)
return ret
}
//fmt.Println(resp)
// 获取成功
arr, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("error:", err)
return
}
ret = string(arr)
//this.cookie = resp.Cookies()
this.SetCookies(resp.Cookies())
return ret
}
// 解析主页html 返回序列号,sKey,sValue,解析是否成功
func (this *Login2Yougou) parseMainPage(html string) (iSerialNumber uint64, sKey string, sValue string, err bool) {
// 使用正则进行局部匹配
reg := regexp.MustCompile("")
// 匹配到结果集
arr := reg.FindStringSubmatch(html)
for _, subXml := range arr {
//fmt.Println(subXml)
// 查询skey
findPos := strings.Index(subXml, "name=\"")
if findPos != -1 {
findPos += len(string("name=\""))
_subXml := string(subXml[findPos:])
findpos2 := strings.Index(_subXml, "\"")
if findpos2 != -1 {
sKey = string(_subXml[:findpos2])
//fmt.Println(sKey)
}
}
// 查询sValue
findPos = strings.Index(subXml, "value=\"")
if findPos != -1 {
findPos += len(string("value=\""))
_subXml := string(subXml[findPos:])
findpos2 := strings.Index(_subXml, "\"")
if findpos2 != -1 {
sValue = string(_subXml[:findpos2])
//fmt.Println(sValue)
}
}
}
iSerialNumber = 1464312215280
if len(sKey) == 0 || len(sValue) == 0 {
err = false
return
}
err = true
return
}
// 根据用户名密码登录
func (this *Login2Yougou) LoginYougou(userName string, passwd string) bool {
shtml := this.getMainPage("https://passport.yougou.com/signin.jhtml?redirectURL=http://www.yougou.com/")
if len(shtml) == 0 {
fmt.Println("https 请求主页失败")
return false
}
iSerialNumber, sKey, sValue, ret := this.parseMainPage(shtml)
if ret == false {
fmt.Println("获取流水号,键值对失败")
return false
}
fmt.Println(iSerialNumber, sKey, sValue)
// 进行login post
loginUrl := "https://passport.yougou.com/my/procsignin.jhtml?callback=" + strconv.FormatUint(iSerialNumber, 10)
fmt.Println(loginUrl)
// 设置form
form := make(url.Values)
form.Set("username", userName)
form.Set("password", passwd)
form.Set("verifycode", "")
form.Set("isVerify", "true")
form.Set(sKey, sValue)
form.Set("callback", "jsonp"+strconv.FormatUint(iSerialNumber, 10))
fmt.Println(form)
// 添加request http info
req, err := http.NewRequest("POST", loginUrl, strings.NewReader(form.Encode()))
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0")
req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
req.Header.Add("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("X-Requested-With", "XMLHttpRequest")
req.Header.Add("Connection", "Keep-Alive")
req.Header.Add("Pragma", "no-cache")
req.Header.Add("Cache-Control", "no-cache")
// 复用之前的cookies
for _, cok := range this.GetCookies() {
req.AddCookie(cok)
}
fmt.Println(req)
resp, err := this.client.Do(req)
defer resp.Body.Close()
if err != nil {
fmt.Println("post form失败:", err.Error())
return false
}
arr, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("post form返回内容为空 api可能改变:", err.Error())
return false
}
fmt.Println(string(arr))
findPos := strings.Index(string(arr), "login_success")
if findPos == -1 {
fmt.Println("未能登录成功")
return false
} else {
fmt.Println("恭喜你 登录成功")
}
this.isLogin = true
return true
}
main.go[主函数]
package main
import "fmt"
import "login"
func main() {
fmt.Println("主函数")
loginy := login.New()
loginy.LoginYougou("用户名", "密码")
}