单个账号流注册流程

This commit is contained in:
zyj
2025-09-27 18:13:59 +08:00
parent 90dfc3ac38
commit 22e21f6eb8
12 changed files with 404 additions and 29 deletions

View File

@@ -20,7 +20,20 @@ type BitBrowserService struct {
var Browser libs.Browser
var Chrome libs.Chrome
func (*BitBrowserService) CreateBrowser(proxy *models.Proxy) string {
type BitCookieParam struct {
Domain string `json:"domain"`
ExpirationDate float64 `json:"expirationDate"` // 必须为 number
HttpOnly bool `json:"httpOnly"`
Name string `json:"name"`
Path string `json:"path"`
Secure bool `json:"secure"`
Session bool `json:"session"`
StoreID *string `json:"storeId"` // 允许 null用指针
Value string `json:"value"`
SameSite *string `json:"sameSite,omitempty"` // 可选字段,不填时省略
}
func (*BitBrowserService) CreateBrowser(proxy *models.Proxy, cookies []*proto.NetworkCookieParam) string {
fingerprint := map[string]interface{}{
"name": fmt.Sprintf(`推特注册%s`, utils.RandString(10)),
"proxyMethod": 2,
@@ -42,6 +55,25 @@ func (*BitBrowserService) CreateBrowser(proxy *models.Proxy) string {
"resolutionType": "0",
},
}
if cookies != nil {
var cookie []BitCookieParam
for _, v := range cookies {
cookie = append(cookie, BitCookieParam{
Domain: v.Domain,
ExpirationDate: float64(v.Expires),
HttpOnly: v.HTTPOnly,
Name: v.Name,
Path: v.Path,
Secure: v.Secure,
Session: false,
StoreID: nil,
Value: v.Value,
SameSite: (*string)(&v.SameSite),
})
}
data, _ := json.Marshal(cookie)
fingerprint["cookie"] = data
}
if proxy != nil {
var proxyHandle utils.ProxyHandle
protocol, username, password, ip, port, err2 := proxyHandle.ParseProxy(proxy.Type + "://" + proxy.Proxy)
@@ -72,7 +104,7 @@ func (*BitBrowserService) CreateBrowser(proxy *models.Proxy) string {
UpdateTime: time.Now().Unix(),
CreateTime: time.Now().Unix(),
}
if proxy != nil {
if proxy != nil && proxy.Type != "" {
params.Proxy = proxy.Type + "://" + proxy.Proxy
}
browserInstanceService.Create(params)
@@ -81,6 +113,7 @@ func (*BitBrowserService) CreateBrowser(proxy *models.Proxy) string {
return ""
}
// 获取当前浏览器的pid
func (*BitBrowserService) GetPid(id string) int {
// 获取当前
bitBrowserRequest := utils.NewBitBrowserRequest()
@@ -151,9 +184,9 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo {
var browserId string
// 创建新的浏览器
if proxy != nil {
browserId = bit.CreateBrowser(proxy)
browserId = bit.CreateBrowser(proxy, nil)
} else {
browserId = bit.CreateBrowser(nil)
browserId = bit.CreateBrowser(nil, nil)
}
// 打开浏览器
if browserId == "" {
@@ -167,15 +200,19 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo {
emailService := InitEmailService()
emailInfo := emailService.GetEmailOne()
log.Println("当前邮箱信息", emailInfo)
obj := Browser.GetBitBrowser(ws)
page := obj.Page
page.MustNavigate("https://x.com/i/flow/signup").MustWaitLoad()
// 点击创建账号
createAccount := page.Timeout(5 * time.Second).MustElement(`button.css-175oi2r.r-sdzlij.r-1phboty.r-rs99b7.r-lrvibr.r-ywje51.r-184id4b.r-13qz1uu.r-2yi16.r-1qi8awa.r-3pj75a.r-1loqt21.r-o7ynqc.r-6416eg.r-1ny4l3l`)
createAccount.MustClick()
// 判断当前是否是邮箱注册
_, err := page.Element(`input[name="email"]`)
if err != nil {
switchButton := page.Timeout(5 * time.Second).MustElement(`button.css-146c3p1.r-bcqeeo.r-qvutc0.r-1qd0xha.r-1ff274t.r-a023e6.r-rjixqe.r-16dba41`)
switchButton.MustClick()
}
// _, err := page.Element(`input[name="email"]`)
// if err != nil {
switchButton := page.Timeout(5 * time.Second).MustElement(`button.css-146c3p1.r-bcqeeo.r-qvutc0.r-37j5jr.r-1ff274t.r-a023e6.r-rjixqe.r-16dba41`)
switchButton.MustClick()
// }
// 获取邮箱输入框
inputEmail := page.Timeout(5 * time.Second).MustElement(`input[name="email"]`)
inputEmail.MustFocus()
@@ -189,7 +226,7 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo {
}
inputName.MustInput(nameStr)
// 随机生成生日
dateParams := utils.RandDate(18, 100)
dateParams := utils.RandDate(18, 80)
dateSelects, _ := page.Timeout(5 * time.Second).Elements(`select.r-30o5oe.r-1niwhzg.r-17gur6a.r-1yadl64.r-18jsvk2.r-1loqt21.r-1inkyih.r-rjixqe.r-crgep1.r-1wzrnnt.r-1ny4l3l.r-t60dpp.r-xd6kpl.r-is05cd.r-ttdzmv`)
// 月份
dateSelects[0].WaitVisible()
@@ -206,13 +243,24 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo {
ocfSignupNextLink.MustClick()
// 判断是否需要验证码
time.Sleep(4 * time.Second)
codeInput, err1 := page.Timeout(5 * time.Second).Element(`input[name="verfication_code"]`)
_, err1 := page.Timeout(5 * time.Second).Element(`input[name="verfication_code"]`)
if err1 != nil {
// res := getApiResponse(page, "")
}
//TODO 对接获取邮箱信息接口
time.Sleep(10 * time.Second)
codeValue := LoopGetEmailCode("pop.dragonsmail.com:993", emailInfo.Email, emailInfo.Password)
if codeValue == "0" {
emailService.Update(emailInfo.Email, models.Email{
Status: 0,
})
return libs.ErrorCode["MailboxUnavailable"]
}
// 获取邮箱验证码
codeInput.MustInput("")
log.Println("获取当前验证码", codeValue)
codeInput1, _ := page.Timeout(5 * time.Second).Element(`input[name="verfication_code"]`)
codeInput1.MustInput(codeValue)
time.Sleep(2 * time.Second)
// 点击下一步
codeNextButton := page.Timeout(5 * time.Second).MustElement(`button.css-175oi2r.r-sdzlij.r-1phboty.r-rs99b7.r-lrvibr.r-19yznuf.r-64el8z.r-1fkl15p.r-1loqt21.r-o7ynqc.r-6416eg.r-1ny4l3l`)
codeNextButton.MustClick()
@@ -224,12 +272,15 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo {
if err2 != nil {
// res := getApiResponse(page, "")
}
passwordInput.MustInput(emailInfo.Password)
time.Sleep(5 * time.Second)
// 点击下一步
loginButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="LoginForm_Login_Button"]`)
loginButton.MustClick()
time.Sleep(5 * time.Second)
page.MustNavigate("https://x.com").MustWaitLoad()
time.Sleep(10 * time.Second)
// 获取cookie
cookieArr := getPageCookie(page, "https://x.com")
// 创建用户
@@ -243,13 +294,15 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo {
Status: "注册成功",
LoginStatus: "登录成功",
Proxy: func() string {
if proxy != nil {
if proxy != nil && proxy.Type != "" {
return proxy.Type + "://" + proxy.Proxy
}
return ""
}(),
})
emailService.Update(emailInfo.Email, models.Email{
UseStatus: 1,
})
// 删除浏览器
bit.DeleteBrowser(browserId)
return libs.ErrorCode["RegisterSuccessful"]
@@ -273,3 +326,20 @@ func getPageCookie(page *rod.Page, url string) []*proto.NetworkCookieParam {
}
return cookies
}
// 循环获取3次验证码
func LoopGetEmailCode(server, email, password string) string {
var emailImap utils.EmailImap
for i := 0; i < 3; i++ {
codeValue := emailImap.GetMailCode(server, email, password)
if codeValue != "0" {
return codeValue
}
time.Sleep(5 * time.Second)
}
return "0"
}
func (*BitBrowserService) AccountUnlock(id int64) *libs.ErrorInfo {
return libs.ErrorCode["UnlockedSuccessfully"]
}

View File

@@ -19,9 +19,13 @@ func InitEmailService() *EmailService {
func (e *EmailService) GetEmailOne() *models.Email {
var email models.Email
err := e.db.Model(email).Where("use_status = ?", 0).First(&email).Error
err := e.db.Model(email).Where("use_status = ? and status=?", 0, 1).First(&email).Error
if err != nil {
return nil
}
return &email
}
func (e *EmailService) Update(email string, params models.Email) {
e.db.Model(&models.Email{}).Where("email = ?", email).Updates(params)
}

View File

@@ -22,3 +22,62 @@ func (t *TwitterAccountService) Create(params *models.TwitterAccount) {
params.UpdateTime = time.Now().Unix()
t.db.Create(params)
}
func (t *TwitterAccountService) GetInfo(id int64) *models.TwitterAccount {
var account models.TwitterAccount
result := t.db.Model(&models.TwitterAccount{}).Where("id = ?", id).First(&account)
if result.Error != nil {
return nil
}
return &account
}
// 更改账号状态
func (u *TwitterAccountService) ChangeAccountStatus(accountId int, status string) bool {
u.db.Model(&models.TwitterAccount{}).Where("id = ?", accountId).Updates(map[string]interface{}{"status": status, "update_time": time.Now().Unix()})
return true
}
// 更改账号登录状态
func (u *TwitterAccountService) ChangeAccountLoginStatus(accountId int, loginStatus string) bool {
u.db.Model(&models.TwitterAccount{}).Where("id = ?", accountId).Updates(map[string]interface{}{"login_status": loginStatus, "update_time": time.Now().Unix()})
return true
}
// 下线所有账号
func (u *TwitterAccountService) OfflineAllAccount() bool {
u.db.Model(&models.TwitterAccount{}).Where("login_status = ?", "登录成功").Updates(&models.TwitterAccount{
LoginStatus: "账号下线",
UpdateTime: time.Now().Unix(),
})
return true
}
// 获取可用账号
func (u *TwitterAccountService) GetAvailableAccount(params *models.TwitterAccount) []models.TwitterAccount {
var users []models.TwitterAccount
res := u.db.Model(&models.TwitterAccount{}).Where(`status = ? AND (login_status != "账号异常" OR login_status IS NULL)`, params.Status)
// if params.Username != "" {
// res.Where("username LIKE ?", "%"+params.Username+"%")
// }
res.Order("id DESC").Find(&users)
return users
}
// 获取养号未运行或者运行失败的账号
func (u *TwitterAccountService) GetAccountListByStatus(params *models.TwitterAccount) []models.TwitterAccount {
var users []models.TwitterAccount
res := u.db.Model(&models.TwitterAccount{}).Where(`status = ? AND (login_status != "账号异常" OR login_status IS NULL)`, params.Status)
// if params.Username != "" {
// res.Where("username LIKE ?", "%"+params.Username+"%")
// }
res.Order("id DESC").Find(&users)
return users
}
// 清空状态字段
func (u *TwitterAccountService) ClearAccountStatus(params *models.TwitterAccount) bool {
u.db.Model(&models.TwitterAccount{}).Where("status = ?", params.Status).Update("status", nil)
return true
}

View File

@@ -0,0 +1,88 @@
package services
import (
"context"
"errors"
"fmt"
"go-account-register/libs"
"log"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/cdp"
)
type TwitterService struct{}
// 登录
func (*TwitterService) Login(id int) *libs.ErrorInfo {
UserService := InitTwitterAccountService()
user := UserService.GetInfo(int64(id))
obj := Browser.GetBrowser(id, &libs.Fingerprint{
Proxy: user.Proxy,
})
browser := obj.Browser
page := obj.Page
err3 := rod.Try(func() {
// 创建 Cookie 对象
cookies := user.Cookies
log.Println("获取cookie", cookies)
// 全局设置
browser.SetCookies(cookies)
page.MustNavigate("https://x.com/home").MustWaitLoad()
page.MustWaitNavigation()
})
if e, ok := err3.(*cdp.Error); ok {
if e.Code == -32000 && e.Message == "Inspected target navigated or closed" {
Browser.CancelBrowser(id)
return libs.ErrorCode["LoginFailed"]
}
}
time.Sleep(3 * time.Second)
url := page.MustEval("() => window.location.href").String()
if url == "https://x.com/account/access" {
Browser.CancelBrowser(id)
return libs.ErrorCode["AccountLocked"]
}
log.Println(url)
err1 := rod.Try(func() {
page.Timeout(5 * time.Second).MustElement(`input[autocomplete="username"]`)
})
if err1 == nil {
Browser.CancelBrowser(id)
return libs.ErrorCode["LoginFailed"]
}
// 是否检测到侧边栏
err2 := rod.Try(func() {
page.Timeout(5 * time.Second).MustElement(`a[data-testid="AppTabBar_Profile_Link"]`)
})
if err2 != nil {
Browser.CancelBrowser(id)
return libs.ErrorCode["LoginFailed"]
}
// 是否检测到帖子列表
err := rod.Try(func() {
page.Timeout(5 * time.Second).MustElement(`article[data-testid="tweet"]`)
})
if errors.Is(err, context.DeadlineExceeded) {
fmt.Println("请求空闲等待超时!")
// 关闭浏览器
Browser.CancelBrowser(id)
return libs.ErrorCode["NetworkTimeout"]
}
if err != nil {
fmt.Println(err)
}
return libs.ErrorCode["LoginSuccessful"]
}
// 退出登录
func (*TwitterService) Logout(id int) {
Browser.CancelBrowser(id)
}