diff --git a/cmd/jdTdudfp.go b/cmd/jdTdudfp.go new file mode 100644 index 0000000..4bf037e --- /dev/null +++ b/cmd/jdTdudfp.go @@ -0,0 +1,122 @@ +package cmd + +import ( + "context" + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/cdproto/network" + "github.com/chromedp/cdproto/target" + "github.com/chromedp/chromedp" + "github.com/spf13/cobra" + "github.com/tidwall/gjson" + "github.com/ztino/jd_seckill/common" + "github.com/ztino/jd_seckill/jd_seckill" + "log" + "net/http" + "net/http/httptest" + "net/url" + "time" +) + +func init() { + rootCmd.AddCommand(jdTdudfpCmd) +} + +var jdTdudfpCmd = &cobra.Command{ + Use: "jdTdudfp", + Short: "auto get jd eid and fp", + Run: startJdTdudfp, +} + +func startJdTdudfp(cmd *cobra.Command, args []string) { + session:=jd_seckill.NewSession(common.CookieJar) + err:=session.CheckLoginStatus() + if err!=nil { + log.Println("自动获取eid和fp失败,请重新登录") + }else { + log.Println("开始自动获取eid和fp,如遇卡住请结束进程,重新启动") + ctx := context.Background() + options := []chromedp.ExecAllocatorOption{ + chromedp.Flag("headless", false), + chromedp.Flag("hide-scrollbars", false), + chromedp.Flag("mute-audio", false), + chromedp.UserAgent(common.Config.MustValue("config","default_user_agent","")), + } + options = append(chromedp.DefaultExecAllocatorOptions[:], options...) + + c, cc := chromedp.NewExecAllocator(ctx, options...) + defer cc() + + ctx, cancel := chromedp.NewContext(c) + ch := addNewTabListener(ctx) + defer cancel() + + u, _ := url.Parse("http://jd.com") + cookies := common.CookieJar.Cookies(u) + err := chromedp.Run(ctx, + chromedp.Tasks{ + chromedp.ActionFunc(func(ctx context.Context) error { + expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour)) + for _, cookie := range cookies { + _, _ = network.SetCookie(cookie.Name, cookie.Value). + WithExpires(&expr). + WithPath("/"). + WithDomain("." + cookie.Domain). + Do(ctx) + } + return nil + }), + chromedp.Navigate("https://jd.com"), + chromedp.Click(".cate_menu_lk"), + }, + ) + if err != nil { + log.Fatal(err) + } + newCtx, cancel := chromedp.NewContext(ctx, chromedp.WithTargetID(<-ch)) + ch = addNewTabListener(newCtx) + defer cancel() + + err = chromedp.Run(newCtx, + chromedp.Click(`.goods_item_link`), + ) + if err != nil { + log.Fatal(err) + } + + newCtx, cancel = chromedp.NewContext(ctx, chromedp.WithTargetID(<-ch)) + defer cancel() + + var res []byte + err = chromedp.Run(newCtx, + chromedp.Click(`#InitCartUrl`), + chromedp.WaitVisible(".btn-addtocart"), + chromedp.Click(".btn-addtocart"), + chromedp.WaitVisible(".common-submit-btn"), + chromedp.Click(".common-submit-btn"), + chromedp.WaitVisible("#sumPayPriceId"), + chromedp.Sleep(2*time.Second), + chromedp.Evaluate("_JdTdudfp", &res), + ) + if err != nil { + log.Fatal(err) + } + value:=string(res) + if !gjson.Valid(value) { + log.Println("获取失败,请重新尝试") + }else{ + log.Println("获取成功,请手动填入配置文件") + log.Println("eid:"+gjson.Get(value,"eid").String()) + log.Println("fp:"+gjson.Get(value,"fp").String()) + } + } +} + +func addNewTabListener(ctx context.Context) <-chan target.ID { + mux := http.NewServeMux() + ts := httptest.NewServer(mux) + defer ts.Close() + + return chromedp.WaitNewTarget(ctx, func(info *target.Info) bool { + return info.URL != "" + }) +} \ No newline at end of file diff --git a/cmd/login.go b/cmd/login.go new file mode 100644 index 0000000..66d58cd --- /dev/null +++ b/cmd/login.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "github.com/ztino/jd_seckill/common" + "github.com/ztino/jd_seckill/jd_seckill" + "log" + "os" + "time" +) + +func init() { + rootCmd.AddCommand(loginCmd) +} + +var loginCmd = &cobra.Command{ + Use: "login", + Short: "Open JD’s simulated login", + Run: startLogin, +} + +func startLogin(cmd *cobra.Command, args []string) { + session:=jd_seckill.NewSession(common.CookieJar) + //检测是否登录过 + if common.Exists("./cookie.txt") { + //已登录,检测登录状态 + err:=session.CheckLoginStatus() + if err!=nil { + log.Println("登录失效,请重新登录") + return + } + user:=jd_seckill.NewUser(common.Client,common.Config) + log.Println("登录成功") + userInfo,_:=user.GetUserInfo() + log.Println("用户:"+userInfo) + }else{ + //未登录 + user:=jd_seckill.NewUser(common.Client,common.Config) + wlfstkSmdl,err:=user.QrLogin() + if err!=nil{ + os.Exit(0) + } + ticket:="" + for { + ticket,err=user.QrcodeTicket(wlfstkSmdl) + if err==nil && ticket!=""{ + break + } + time.Sleep(2*time.Second) + } + _,err=user.TicketInfo(ticket) + if err==nil { + if status:=user.RefreshStatus();status==nil { + //保存cookie + _=session.SaveCookieToFile("./cookie.txt") + log.Println("登录成功") + userInfo,_:=user.GetUserInfo() + log.Println("用户:"+userInfo) + }else{ + log.Println("登录失效") + } + }else{ + log.Println("登录失败") + } + } +} diff --git a/cmd/logout.go b/cmd/logout.go new file mode 100644 index 0000000..2e48a4f --- /dev/null +++ b/cmd/logout.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "github.com/ztino/jd_seckill/common" + "log" + "os" +) + +func init() { + rootCmd.AddCommand(logoutCmd) +} + +var logoutCmd = &cobra.Command{ + Use: "logout", + Short: "Open JD’s simulated logout", + Run: startLogout, +} + +func startLogout(cmd *cobra.Command, args []string) { + if common.Exists("./cookie.txt") { + _=os.Remove("./cookie.txt") + log.Println("退出成功") + }else{ + log.Println("退出失败,未登录") + } +} \ No newline at end of file diff --git a/cmd/reserve.go b/cmd/reserve.go new file mode 100644 index 0000000..1a549d2 --- /dev/null +++ b/cmd/reserve.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "github.com/ztino/jd_seckill/common" + "github.com/ztino/jd_seckill/jd_seckill" + "log" +) + +func init() { + rootCmd.AddCommand(reserveCmd) +} + +var reserveCmd = &cobra.Command{ + Use: "reserve", + Short: "Open JD Moutai buying appointment", + Run: startReserve, +} + +func startReserve(cmd *cobra.Command, args []string) { + session:=jd_seckill.NewSession(common.CookieJar) + err:=session.CheckLoginStatus() + if err!=nil { + log.Println("预约失败,请重新登录") + }else{ + //开始预约,预约过的就重复预约 + seckill:=jd_seckill.NewSeckill(common.Client,common.Config) + seckill.MakeReserve() + } +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..57b9f75 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,25 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "github.com/ztino/jd_seckill/common" + "os" +) + +var rootCmd = &cobra.Command{ + Use: common.SoftName, + Short: "jd_seckill is a Jingdong Moutai seckill script", + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 0 { + _=cmd.Help() + } + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/cmd/seckill.go b/cmd/seckill.go new file mode 100644 index 0000000..f6d68c6 --- /dev/null +++ b/cmd/seckill.go @@ -0,0 +1,122 @@ +package cmd + +import ( + "errors" + "fmt" + "github.com/Albert-Zhan/httpc" + "github.com/spf13/cobra" + "github.com/tidwall/gjson" + "github.com/ztino/jd_seckill/common" + "github.com/ztino/jd_seckill/jd_seckill" + "log" + "net/http" + "os" + "time" +) + +func init() { + rootCmd.AddCommand(seckillCmd) +} + +var seckillCmd = &cobra.Command{ + Use: "seckill", + Short: "Start panic buying procedure", + Run: startSeckill, +} + +func startSeckill(cmd *cobra.Command, args []string) { + session:=jd_seckill.NewSession(common.CookieJar) + err:=session.CheckLoginStatus() + if err!=nil { + log.Println("抢购失败,请重新登录") + }else{ + //活跃用户会话,当会话失效自动退出程序 + user:=jd_seckill.NewUser(common.Client,common.Config) + go KeepSession(user) + //计算抢购时间 + nowLocalTime:=time.Now().UnixNano()/1e6 + jdTime,_:=GetJdTime() + buyDate:=common.Config.MustValue("config","buy_time","") + loc, _ := time.LoadLocation("Local") + t,_:=time.ParseInLocation("2006-01-02 15:04:05",buyDate,loc) + buyTime:=t.UnixNano()/1e6 + diffTime:=nowLocalTime-jdTime + log.Println(fmt.Sprintf("正在等待到达设定时间:%s,检测本地时间与京东服务器时间误差为【%d】毫秒",buyDate,diffTime)) + timerTime:=(buyTime+diffTime)-jdTime + if timerTime<=0 { + log.Println("请设置抢购时间") + os.Exit(0) + } + //等待抢购 + time.Sleep(time.Duration(timerTime)*time.Millisecond) + //开始抢购 + log.Println("时间到达,开始执行……") + seckill:=jd_seckill.NewSeckill(common.Client,common.Config) + //开启抢购任务,第二个参数为开启几个协程 + //怕封号的可以减少协程数量,相反抢到的成功率也减低了 + Start(seckill,5) + } +} + +func GetJdTime() (int64,error) { + req:=httpc.NewRequest(common.Client) + resp,body,err:=req.SetUrl("https://a.jd.com//ajax/queryServerData.html").SetMethod("get").Send().End() + if err!=nil || resp.StatusCode!=http.StatusOK { + log.Println("获取京东服务器时间失败") + return 0,errors.New("获取京东服务器时间失败") + } + return gjson.Get(body,"serverTime").Int(),nil +} + +func Start(seckill *jd_seckill.Seckill,taskNum int) { + seckillTotalTime:=time.Now().Add(2*time.Minute).Unix() + //开始检测抢购状态 + go CheckSeckillStatus() + //抢购总时间两分钟,超时程序自动退出 + for time.Now().Unix()