Files
go-account-register/services/twitter_service.go
2025-11-20 11:42:48 +08:00

712 lines
23 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package services
import (
"context"
"encoding/json"
"errors"
"fmt"
"go-account-register/libs"
"go-account-register/models"
"go-account-register/utils"
"log"
"math/rand"
"os"
"strconv"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/cdp"
"github.com/go-rod/rod/lib/input"
"github.com/go-rod/rod/lib/proto"
)
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)
// b, _ := json.MarshalIndent(cookies, "", " ")
// log.Println(string(b))
// var token string
// for _, v := range user.Cookies {
// if v.Name == "auth_token" {
// token = v.Value
// }
// }
// log.Println("当前账号Token", token)
cookies := []*proto.NetworkCookieParam{
{
Name: "auth_token",
Value: user.Token,
Domain: ".x.com",
Path: "/",
Expires: proto.TimeSinceEpoch(time.Now().Add(24 * time.Hour).Unix()), // 过期时间
HTTPOnly: true, // 禁止 JS 访问
Secure: true, // 仅 HTTPS 传输
},
}
log.Println("Cookie", cookies[0].Value)
// 全局设置
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)
}
getAccountInfo(page, int64(id))
return libs.ErrorCode["LoginSuccessful"]
}
// 获取账号信息
func getAccountInfo(page *rod.Page, id int64) {
profileButton := page.Timeout(10 * time.Second).MustElement(`a[data-testid="AppTabBar_Profile_Link"]`)
profileButton.MustClick()
// 等待新页面加载完成
page.MustWaitLoad()
res := getApiResponse(page, "/UserByScreenName")
var dataBody map[string]interface{}
json.Unmarshal([]byte(res), &dataBody)
outerMap := dataBody["data"].(map[string]interface{})
userMap := outerMap["user"].(map[string]interface{})
resultMap := userMap["result"].(map[string]interface{})
// 获取头像
avatarMap := resultMap["avatar"].(map[string]interface{})
avatarImageURL := avatarMap["image_url"].(string)
legacyMap := resultMap["legacy"].(map[string]interface{})
// 获取背景图
backdropImgUrl := legacyMap["profile_banner_url"]
var backdropUrl string
if backdropImgUrl == nil {
backdropUrl = ""
} else {
backdropUrl = legacyMap["profile_banner_url"].(string)
}
// 获取昵称
coreMap := resultMap["core"].(map[string]interface{})
nickname := coreMap["name"].(string)
screenName := coreMap["screen_name"].(string)
// 获取自我介绍
bio := legacyMap["description"].(string)
// 获取自己设置的地理位置
locationObj := resultMap["location"].(map[string]interface{})
location := locationObj["location"].(string)
// 获取粉丝数量
followersCount := legacyMap["followers_count"].(float64)
// 获取关注数量
friendsCount := legacyMap["friends_count"].(float64)
// 获取发布的帖子数量
mediaCount := legacyMap["media_count"].(float64)
log.Println("头像地址", avatarImageURL)
log.Println("背景图地址", backdropUrl)
log.Println("昵称", nickname)
log.Println("用户名", screenName)
log.Println("自我介绍", bio)
log.Println("地理位置", location)
log.Println("粉丝数量", int64(followersCount))
log.Println("关注数量", int64(friendsCount))
log.Println("发布的帖子数量", int64(mediaCount))
userService := InitTwitterAccountService()
userService.Update(id, &models.TwitterAccount{
Uid: screenName,
})
}
// 退出登录
func (*TwitterService) Logout(id int) {
Browser.CancelBrowser(id)
}
// 注册账号
func (bit *TwitterService) Register() *libs.ErrorInfo {
// 随机获取代理
proxyService := InitProxyService()
proxy := proxyService.GetInfo()
// 获取一个邮箱
emailService := InitEmailService()
emailInfo := emailService.GetEmailOne()
log.Println("当前邮箱信息", emailInfo)
obj := Browser.GetNewBrowser(&libs.Fingerprint{})
page := obj.Page
page.MustNavigate("https://x.com/").MustWaitLoad()
// 点击创建账号
createAccountA := page.Timeout(5 * time.Second).MustElement(`a[data-testid="signupButton"]`)
createAccountA.MustClick()
// // 点击创建账号
// 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-37j5jr.r-1ff274t.r-a023e6.r-rjixqe.r-16dba41`)
switchButton.MustClick()
// }
// 获取邮箱输入框
inputEmail := page.Timeout(5 * time.Second).MustElement(`input[name="email"]`)
inputEmail.MustFocus()
inputEmail.MustInput(emailInfo.Email)
// 获取名称输入框
inputName := page.Timeout(5 * time.Second).MustElement(`input[name="name"]`)
inputName.MustFocus()
nameStr := emailInfo.Name
if emailInfo.Name == "" {
nameStr = utils.RandString(12)
}
inputName.MustInput(nameStr)
// 随机生成生日
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`)
log.Println(dateSelects)
fmt.Println(strconv.Itoa(dateParams.Month))
fmt.Println(strconv.Itoa(dateParams.Day))
fmt.Println(strconv.Itoa(dateParams.Year))
time.Sleep(2 * time.Second)
// 月份
dateSelects[0].WaitVisible()
opts, _ := dateSelects[0].Elements("option")
for i, opt := range opts {
txt, _ := opt.Text()
val, _ := opt.Attribute("value")
log.Printf("option[%d] text=%s value=%s\n", i, txt, *val)
if i != 0 && i == dateParams.Month {
dateSelects[0].MustSelect(txt)
}
}
// 年份
dateSelects[2].WaitVisible()
dateSelects[2].MustSelect(strconv.Itoa(dateParams.Year))
time.Sleep(2 * time.Second)
// 日期
dateSelects[1].WaitVisible()
dateSelects[1].MustSelect(strconv.Itoa(dateParams.Day))
// dateSelects[0].MustClick()
// monthOption := dateSelects[0].MustElement(fmt.Sprintf(`option[value="%d"]`, dateParams.Month))
// monthOption.MustClick()
time.Sleep(2 * time.Second)
// 点击下一步
ocfSignupNextLink := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfSignupNextLink"]`)
ocfSignupNextLink.MustClick()
// 判断是否需要验证码
time.Sleep(4 * time.Second)
_, 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"]
}
// 获取邮箱验证码
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()
// // 点击验证按钮
// verifyButton := page.Timeout(5 * time.Second).MustElement(`button[data-theme="home.verifyButton"]`)
// verifyButton.MustClick()
// 输入密码
passwordInput, err2 := page.Timeout(5 * time.Second).Element(`input[name="password"]`)
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")
// 创建用户
twitterAccountService := InitTwitterAccountService()
twitterAccountService.Create(&models.TwitterAccount{
Name: nameStr,
Email: emailInfo.Email,
Password: emailInfo.Password,
Birthday: strconv.Itoa(dateParams.Year) + "-" + strconv.Itoa(dateParams.Month) + "-" + strconv.Itoa(dateParams.Day),
Cookies: cookieArr,
Status: "注册成功",
LoginStatus: "登录成功",
Proxy: func() string {
if proxy != nil && proxy.Type != "" {
return proxy.Type + "://" + proxy.Proxy
}
return ""
}(),
})
emailService.Update(emailInfo.Email, models.Email{
UseStatus: 1,
})
// 设置fa2
page.MustNavigate("https://x.com/settings/account/login_verification").MustWaitLoad()
// 点击fa2按钮
inputCheckbox := page.Timeout(5 * time.Second).MustElement(`input[aria-describedby="CHECKBOX_2_LABEL"]`)
inputCheckbox.MustClick()
// 等待2秒
time.Sleep(2 * time.Second)
// 设置密码
inpurPassword := page.Timeout(5 * time.Second).MustElement(`input[name="password"]`)
inpurPassword.MustInput(emailInfo.Password)
// 点击确认
faConfirm := page.Timeout(5 * time.Second).MustElement(`button[data-testid="LoginForm_Login_Button"]`)
faConfirm.MustClick()
// 等待2秒
time.Sleep(2 * time.Second)
ActionListNextButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ActionListNextButton"]`)
ActionListNextButton.MustClick()
// 点击无法扫描二维码
queryCode := page.Timeout(5 * time.Second).MustElement("div.css-175oi2r.r-1awozwy.r-w7s2jr>div.css-175oi2r.r-95jzfe>div.css-146c3p1.r-bcqeeo.r-1ttztb7.r-qvutc0.r-37j5jr.r-a023e6.r-rjixqe.r-16dba41>button.css-1jxf684.r-bcqeeo.r-qvutc0.r-poiln3.r-fdjqy7")
queryCode.MustClick()
fa2Code := page.Timeout(5 * time.Second).MustElement(`div.css-146c3p1.r-bcqeeo.r-qvutc0.r-37j5jr.r-1blvdjr.r-vrz42v.r-b88u0q.r-x572qd.r-ywje51.r-1oqcu8e.r-q4m81j.r-13qz1uu`)
fa2CodeText := fa2Code.MustText()
log.Println("当前账号的二步验证码,", fa2CodeText)
ocfShowCodeNextLink := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfShowCodeNextLink"]`)
ocfShowCodeNextLink.MustClick()
codeText, _ := utils.GetFA2Code(fa2CodeText)
ocfEnterTextTextInput := page.Timeout(5 * time.Second).MustElement(`input[data-testid="ocfEnterTextTextInput"]`)
ocfEnterTextTextInput.MustInput(codeText)
ocfEnterTextNextButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfEnterTextNextButton"]`)
ocfEnterTextNextButton.MustClick()
// 删除浏览器
return libs.ErrorCode["RegisterSuccessful"]
}
// 发推
func (*TwitterService) SendPost(accountId int, Content string, Img []string) *libs.ErrorInfo {
// 获取账号状态
UserService := InitTwitterAccountService()
user := UserService.GetInfo(int64(accountId))
if user.LoginStatus != "登录成功" {
return libs.ErrorCode["AccountHasBeenTakenOffline"]
}
// 获取实例
obj := Browser.GetBrowser(accountId, &libs.Fingerprint{
Proxy: user.Proxy,
})
page := obj.Page
// 跳转到首页
page.MustNavigate("https://x.com/home").MustWaitLoad()
err := rod.Try(func() {
// 获取内容输入框
textInput := page.Timeout(10 * time.Second).MustElement(`div.notranslate.public-DraftEditor-content`)
textInput.MustInput(Content)
// 检测字符串是否包含标签
if strings.Contains(Content, "#") {
_, err := page.Timeout(5 * time.Second).Element(`div.css-175oi2r.r-14lw9ot.r-z2wwpe.r-1upvrn0.r-h3f8nf.r-11yh6sk.r-1rnoaur`)
time.Sleep(2 * time.Second)
if err == nil {
tagBuuton := page.Timeout(5 * time.Second).MustElement(`div.css-175oi2r.r-14lw9ot.r-z2wwpe.r-1upvrn0.r-h3f8nf.r-11yh6sk.r-1rnoaur div[data-testid="typeaheadResult"] button.css-175oi2r.r-x572qd.r-6dt33c.r-1loqt21.r-o7ynqc.r-6416eg.r-1ny4l3l`)
tagBuuton.MustClick()
time.Sleep(2 * time.Second)
}
}
// 循环保存图片到本地
if len(Img) > 0 {
var file libs.File
for _, v := range Img {
tempFile, _ := file.DownloadImage(v)
// 结束时删除临时文件
defer os.Remove(tempFile)
page.MustElement(`input[data-testid="fileInput"]`).MustSetFiles(tempFile)
time.Sleep(1 * time.Second)
}
time.Sleep(5 * time.Second)
}
})
if errors.Is(err, context.DeadlineExceeded) {
fmt.Println("请求空闲等待超时!")
return libs.ErrorCode["SendPostFailed"]
}
code := postButton(page)
if code == 200 {
return libs.ErrorCode["SendPostSuccessful"]
}
return libs.ErrorCode["SendPostFailed"]
}
// 发推按钮点击之后监听请求
func postButton(page *rod.Page) int {
// 定义一个通道接收消息
router := page.HijackRequests()
defer router.MustStop()
ch := make(chan int, 1)
router.MustAdd("*/CreateTweet*", func(ctx *rod.Hijack) {
ctx.ContinueRequest(&proto.FetchContinueRequest{})
ch <- ctx.Response.Payload().ResponseCode
})
go router.Run()
// 点击发布按钮
postButton := page.Timeout(10 * time.Second).MustElement(`button[data-testid="tweetButtonInline"]`)
postButton.MustClick()
select {
case res := <-ch:
return res
case <-time.After(30 * time.Second):
log.Println("等待上传响应超时")
return 500
}
}
// 搜索
func (*TwitterService) Search(accountId int, keyword string, twitterId string) *libs.ErrorInfo {
// 获取账号状态
UserService := InitTwitterAccountService()
user := UserService.GetInfo(int64(accountId))
if user.LoginStatus != "登录成功" {
return libs.ErrorCode["AccountHasBeenTakenOffline"]
}
// 获取实例
obj := Browser.GetBrowser(accountId, &libs.Fingerprint{
Proxy: user.Proxy,
})
page := obj.Page
// 跳转到首页
page.MustNavigate("https://x.com/home").MustWaitLoad()
err2 := rod.Try(func() {
forYou := page.Timeout(10 * time.Second).MustElement(`div[data-testid="ScrollSnap-List"] div.css-175oi2r.r-14tvyh0.r-cpa5s6.r-16y2uox:nth-child(1)`)
forYou.MustClick()
})
if err2 != nil {
}
page.MustWaitNavigation()
// 是否检测到帖子列表
err := rod.Try(func() {
page.Timeout(5 * time.Second).MustElement(`article[data-testid="tweet"]`)
})
if errors.Is(err, context.DeadlineExceeded) {
fmt.Println("请求空闲等待超时!")
// 关闭浏览器
Browser.CancelBrowser(accountId)
return libs.ErrorCode["NetworkTimeout"]
}
page.MustNavigate("https://x.com/explore").MustWaitLoad()
searchInput := page.Timeout(10 * time.Second).MustElement(`input[data-testid="SearchBox_Search_Input"]`)
// 聚焦
searchInput.Focus()
searchInput.MustInput(keyword)
searchCode := waitSearch(page)
if searchCode != 200 {
return libs.ErrorCode["SearchFailed"]
}
peopleButton := page.Timeout(10 * time.Second).MustElement(`div[data-testid="ScrollSnap-List"] div.css-175oi2r.r-14tvyh0.r-cpa5s6.r-16y2uox:nth-child(3)`)
peopleButton.MustClick()
retry, err1 := page.Timeout(5 * time.Second).Element(`div.css-175oi2r.r-1awozwy.r-16y2uox.r-1777fci.r-dd0y9b.r-3o4zer.r-f8sm7e.r-13qz1uu.r-1ye8kvj`)
if retry != nil || err1 == nil {
return libs.ErrorCode["SearchFailed"]
}
var isSearch bool = true
var searchCount int = 0
var activeUser *rod.Element = nil
var nameArr []string = []string{}
var nameBool map[string]bool = make(map[string]bool)
for isSearch && searchCount < 10 {
searchCount++
// 获取视口内的所有元素
ids, err2 := getVisibleElements(page, `div.css-175oi2r.r-f8sm7e.r-13qz1uu.r-1ye8kvj div.css-146c3p1.r-dnmrzs.r-1udh08x.r-1udbk01.r-3s2u2q.r-bcqeeo.r-1ttztb7.r-qvutc0.r-37j5jr.r-a023e6.r-rjixqe.r-16dba41.r-18u37iz.r-1wvb978`)
if err2 != nil || len(ids) <= 0 {
return libs.ErrorCode["SearchFailed"]
}
for _, v := range ids {
text := v.MustText()
if !nameBool[text] {
nameBool[text] = true
nameArr = append(nameArr, text)
}
if text == "@"+twitterId {
activeUser = v
break
}
}
if activeUser != nil {
isSearch = false
log.Println("循环:")
log.Println(searchCount)
log.Println(len(nameArr))
log.Println("找到用户")
} else {
log.Println("开始滚动")
scrollElementLocationTop(ids[len(ids)-1])
time.Sleep(5 * time.Second)
}
}
if searchCount >= 10 {
return libs.ErrorCode["SearchFailed"]
}
time.Sleep(1 * time.Second)
activeUser.MustClick()
// 等待5-8秒
s := 5 + rand.Intn(3)
time.Sleep(time.Duration(s) * time.Second)
posts := page.Timeout(10 * time.Second).MustElements(`div.css-175oi2r.r-j5o65s.r-qklmqi.r-1adg3ll.r-1ny4l3l`)
var postArr []*rod.Element
for _, post := range posts {
aid := post.Timeout(10 * time.Second).MustElement(`div.css-146c3p1.r-dnmrzs.r-1udh08x.r-1udbk01.r-3s2u2q.r-bcqeeo.r-1ttztb7.r-qvutc0.r-37j5jr.r-a023e6.r-rjixqe.r-16dba41.r-18u37iz.r-1wvb978`)
text := aid.MustText()
if text == "@"+twitterId {
postArr = append(postArr, post)
}
}
if len(postArr) <= 0 {
return libs.ErrorCode["SearchSuccessful"]
}
// 随机选择一个
activePost := postArr[rand.Intn(len(postArr))]
activePost.MustScrollIntoView() // 将元素滑动到页面中间
tweetText := activePost.Timeout(10 * time.Second).MustElement(`div[data-testid="tweetText"]`)
// 禁用链接点击
_, err3 := page.Evaluate(&rod.EvalOptions{
JS: `(selector) => {
const el = document.querySelector(selector);
const links = el.querySelectorAll('a');
links.forEach(a => {
a.style.pointerEvents = 'none';
});
}`,
JSArgs: []interface{}{`div[data-testid="tweetText"]`},
})
if err3 != nil {
}
tweetText.MustClick()
// 恢复链接的点击行为(如果需要)
_, _ = page.Evaluate(&rod.EvalOptions{
JS: `(selector) => {
const el = document.querySelector(selector);
const links = el.querySelectorAll('a');
links.forEach(a => {
a.style.pointerEvents = '';
});
}`,
JSArgs: []interface{}{`div[data-testid="tweetText"]`},
})
// 等待15-20秒
s2 := 15 + rand.Intn(10)
time.Sleep(time.Duration(s2) * time.Second)
// 返回上一页
// 模拟点击后退按钮
page.MustNavigateBack()
// 等待新页面加载完成
page.MustWaitLoad()
// 等待5-8秒
time.Sleep(time.Duration(s) * time.Second)
return libs.ErrorCode["SearchSuccessful"]
}
// 获取视口内可见的指定元素
func getVisibleElements(page *rod.Page, selector string) ([]*rod.Element, error) {
// 1. 获取所有候选元素
elements, err := page.Elements(selector)
if err != nil {
return nil, err
}
// 2. 过滤出视口内可见的元素
var visibleElements []*rod.Element
for _, el := range elements {
isVisible, err := el.Eval(`function() {
const rect = this.getBoundingClientRect();
const viewportHeight = window.innerHeight;
const viewportWidth = window.innerWidth;
// 判断元素是否至少部分在视口内
return (
rect.top < viewportHeight &&
rect.bottom > 0 &&
rect.left < viewportWidth &&
rect.right > 0
);
}`)
if err == nil && isVisible.Value.Bool() {
visibleElements = append(visibleElements, el)
}
}
return visibleElements, nil
}
// 将指定元素滑动到顶部
func scrollElementLocationTop(el *rod.Element) {
// 执行JS滚动到视口顶部平滑滚动
el.MustEval(`function() {
this.scrollIntoView({
behavior: "smooth",
block: "start" // 顶部对齐
});
}`)
// 等待滚动完成
// time.Sleep(2 * time.Second)
}
// 搜索按钮点击之后监听请求
func waitSearch(page *rod.Page) int {
// 定义一个通道接收消息
router := page.HijackRequests()
defer router.MustStop()
ch := make(chan int, 1)
router.MustAdd("*/SearchTimeline*", func(ctx *rod.Hijack) {
ctx.ContinueRequest(&proto.FetchContinueRequest{})
ch <- ctx.Response.Payload().ResponseCode
})
go router.Run()
// 点击搜索按钮
searchInput := page.Timeout(10 * time.Second).MustElement(`input[data-testid="SearchBox_Search_Input"]`)
searchInput.MustKeyActions().Press(input.Enter).MustDo()
select {
case res := <-ch:
return res
case <-time.After(30 * time.Second):
log.Println("等待上传响应超时")
return 500
}
}
// 获取指定接口的响应参数
func getApiResponse(page *rod.Page, url string) string {
// 定义一个通道接收消息
ch := make(chan string)
go page.EachEvent(func(e *proto.PageLoadEventFired) {
log.Println("1234567890")
}, func(e *proto.NetworkResponseReceived) {
if strings.Contains(e.Response.URL, url) {
reply, err := (proto.NetworkGetResponseBody{RequestID: e.RequestID}).Call(page)
if err != nil {
fmt.Println(err)
}
ch <- reply.Body
// fmt.Println(reply.Body)
}
})()
select {
case res := <-ch:
return res
case <-time.After(30 * time.Second):
log.Println("等待上传响应超时")
return ""
}
}
func (*TwitterService) LoopViewPost(id int) *libs.ErrorInfo {
UserService := InitTwitterAccountService()
user := UserService.GetInfo(int64(id))
obj := Browser.GetBrowser(id, &libs.Fingerprint{
Proxy: user.Proxy,
})
page := obj.Page
// 获取推文列表
postList := InitTwitterPostService().GetAll()
if len(postList) <= 0 {
return libs.ErrorCode["NoPostsToView"]
}
for _, v := range postList {
page.MustNavigate(v.Link).MustWaitLoad()
page.MustWaitNavigation()
page.MustWaitLoad() // DOM 加载完成
page.MustWaitIdle() // 基本静止(减少早期误判)
page.MustActivate() // 前置
// 等待5-10秒
s := 5 + rand.Intn(5)
time.Sleep(time.Duration(s) * time.Second)
log.Println("浏览推文链接:", v.Link)
if v.ContentLink != "" {
page.MustNavigate(v.ContentLink).MustWaitLoad()
page.MustWaitNavigation()
page.MustWaitLoad() // DOM 加载完成
page.MustWaitIdle() // 基本静止(减少早期误判)
page.MustActivate() // 前置
// 等待5-10秒
s2 := 5 + rand.Intn(5)
time.Sleep(time.Duration(s2) * time.Second)
log.Println("浏览推文内容链接:", v.ContentLink)
}
}
return libs.ErrorCode["ViewSuccessful"]
}