發(fā)布時間:2023-11-27 15:55:06 瀏覽量:189次
本文為技術(shù)文章,閱讀對象為對Golang感興趣的朋友。
游戲:XX農(nóng)場(H5)。
功能:使用Golang模擬登陸,并自動完成“收茶”和“澆水”操作。
游戲界面
這是一個H5的農(nóng)場游戲,很常見的一個游戲。
游戲需要讓玩家先收茶然后再澆水。
做一次收茶澆水操作之后,需要等一定的時間后,再做重復(fù)做這個動作。
我們在這里不討論這個游戲項目,或者游戲體驗等問題。
我們只關(guān)于如何使用Golang自動完成這些操作。
要模擬登錄,就需要先分析這個游戲登錄需要哪些條件。
H5游戲,那當然使用Chrome這個神器咯。
登錄界面
我們從登錄界面可以看到,這個表單主要有三個控件:登錄賬戶、登錄密碼和記住賬號密碼。
我們使用Chrome來看看這個表單的具體情況。
從HTML代碼中,我們可以發(fā)現(xiàn),有兩個隱藏域,這個表單控件的具體情況如下:
登錄表單是使用Post方式提交,提交地址為:http://www.toutiao.com/a7056967701902295559/login.aspx。
換句話說,我們模擬登錄時,需要向?qū)Ψ椒?wù)器提交這些數(shù)據(jù)。
用戶名和密碼這兩個參數(shù),是我們自己填寫的。
__VIEWSTATE和__VIEWSTATEGENERATOR這兩個參數(shù)是服務(wù)器提供的,那么怎么處理呢?
方式倒也簡單。先直接使用Golang訪問這個登錄頁面,然后從頁面中獲取上面說的兩個參數(shù)的值。
獲取頁面參數(shù),我們使用goquery這個庫,很酷的一個庫,Golang仿jQuery的一個庫,很好用。
goquery源碼地址:
github.com/PuerkitoBio/goquery
本程序,除了goquery這個庫以外,其他的都使用標準庫。
然后我們?yōu)榱瞬蛔岋L控系統(tǒng)(如果有多話)那么容易發(fā)現(xiàn)我們是模擬登錄,那么我們就把瀏覽器相關(guān)的參數(shù)都給到服務(wù)器。
登錄之后,我使用標準庫中的cookiejar來維護Cookie。
游戲主頁地址做了隱藏。
廢話不多說,上代碼:
const HomePageURL = "http://www.xxxxxxx.cn/wap/" // 首頁
const LoginURL = HomePageURL + "login.aspx" // 登錄頁面
const UserHome = HomePageURL + "userindex.aspx" // 用戶中心
const TianYuanURL = HomePageURL + "tea.aspx" // 田園頁面
const UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
const Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
const AcceptLanguage = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,ja;q=0.6,mt;q=0.5,zh-TW;q=0.4,la;q=0.3,da;q=0.2,pl;q=0.1,lb;q=0.1,de;q=0.1"
const ContentType = "application/x-www-form-urlencoded"
// 請求客戶端
type HttpClient struct {
// 公共頁面參數(shù)
ViewState string
ViewStateGenerator string
gCurCookies []*http.Cookie
gCurCookieJar *cookiejar.Jar
myHttpClient *http.Client // 請求客戶端
}
// 登錄,獲取Cookie
func (h *HttpClient) Login(userName, password string) error {
h.GetPageParams()
params := url.Values{}
params.Add("__VIEWSTATE", h.ViewState)
params.Add("__VIEWSTATEGENERATOR", h.ViewStateGenerator)
params.Add("tb_loguid", userName)
params.Add("tb_pwd", password)
params.Add("checkboxDefault", "0")
params.Add("Button1", "確認登錄")
postParams := ioutil.NopCloser(strings.NewReader(params.Encode()))
req, err := http.NewRequest("POST", LoginURL, postParams)
if err != nil {
return err
}
req.Header.Add("Content-Type", ContentType)
req.Header.Add("Accept", Accept)
req.Header.Add("Accept-Encoding", "gzip, deflate")
req.Header.Add("Accept-Language", AcceptLanguage)
req.Header.Add("Cache-Control", "max-age=0")
req.Header.Add("Connection", "keep-alive")
req.Header.Add("Content-Length", "217")
req.Header.Add("DNT", "1")
req.Header.Add("Origin", "http://www.xxxxxxx.cn")
req.Header.Add("Referer", LoginURL)
req.Header.Add("Upgrade-Insecure-Requests", "1")
req.Header.Add("User-Agent", UserAgent)
resp, err := h.myHttpClient.Do(req)
if err != nil {
return err
}
h.gCurCookies = h.gCurCookieJar.Cookies(req.URL)
defer resp.Body.Close()
return nil
}
// 獲取頁面及Cookie參數(shù)
func (h *HttpClient) GetPageParams() error {
_myCookieJar, _ := cookiejar.New(nil)
h.gCurCookieJar = _myCookieJar
h.myHttpClient = &http.Client{
CheckRedirect: nil,
Jar: h.gCurCookieJar,
}
if err := h.getViewState(LoginURL); err != nil {
return err
}
return nil
}
// 獲取頁面參數(shù)
func (h *HttpClient) getViewState(url string) error {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
res, err := h.myHttpClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
return err
}
doc.Find("#__VIEWSTATE").Each(func(i int, s *goquery.Selection) {
h.ViewState = s.AttrOr("value", "")
})
doc.Find("#__VIEWSTATEGENERATOR").Each(func(i int, s *goquery.Selection) {
h.ViewStateGenerator = s.AttrOr("value", "")
})
if url == LoginURL {
h.gCurCookies = h.gCurCookieJar.Cookies(req.URL)
}
return nil
}
為了可以支持多賬戶,我們將用戶名和密碼作為參數(shù)傳遞給登錄方法(Login)。
GetPageParams這個方法,用來初始化cookiejar這個對象。
getViewState這個方法,用來獲取頁面的公共參數(shù)。
這幾行代碼,可以完成模擬登錄的操作。
golang發(fā)起http請求,使用的是標準庫:net/http。
如果對這個庫還不屬性的朋友,可以查閱一下官方的文檔。
大家可以使用單元測試進行嘗試。
如果做單元測試,這里就不展開了,搜索一下,網(wǎng)上相關(guān)的資料很多。
因為要支持多賬戶模擬,所以我們的程序中需要支持退出功能。
還是使用Chrome來分析這個游戲如何處理退出的。
從個人中心,拉到底部,我們發(fā)現(xiàn)了“退出登錄”的按鈕。查看源碼,發(fā)現(xiàn)退出使用的Get方法。地址為:userindex.aspx?act=out。
那就更簡單了,代碼如下:
// 退出登錄
func (h *HttpClient) Logout() error {
req, err := http.NewRequest("GET", UserHome+"?act=out", nil)
if err != nil {
return err
}
res, err := h.myHttpClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return errors.New("退出登錄失敗,請檢查后重新操作")
}
return nil
}
登錄和退出完成了,我們現(xiàn)在開始干正事。
對于這個游戲,主要的游戲操作有收茶和澆水。
說明:當前使用的這個賬戶,還沒有種茶,當然界面上看不到茶樹。
在收茶之前,我們需要先檢查,是否有茶可收。
還是老規(guī)矩,分析頁面代碼。我們需要搞清楚收茶的動作是如何提交到服務(wù)器的。
我們在導(dǎo)航中點擊“田園”按鈕,進入游戲主界面。使用Chrome的開發(fā)者工具查看源碼。
我們從源碼中可以看到,這個游戲的開發(fā)者將整個頁面都放到了一個表單中。
表單提交方法還是Post,表單提交地址為:http://www.toutiao.com/a7056967701902295559/tea.aspx。
這個頁面也存在著幾個隱藏域,而且有的還有值。
我們不要管這幾個隱藏域的參數(shù)做什么用,但是有一點我們很清楚:
在對游戲進行操作時,服務(wù)器需要這些參數(shù)。
你需要我給你就好了。
換句話說,我們可以這樣理解:
這個游戲的任何操作,都是使用Post方法,向服務(wù)器提交相應(yīng)的數(shù)據(jù)。
有了這個基礎(chǔ)了解,那么我們就知道要怎么操作了。
還是使用getViewState這個方法獲取頁面的隱藏域參數(shù)。
其他操作也是如此。
檢查是否可以收茶
我們前面提到過,要收茶,也需要有茶可收。
我們測試賬號現(xiàn)在沒有可收的茶葉。
如果有茶可以收的時候,服務(wù)器會在頁面中加入一個HTML節(jié)點。這個節(jié)點有個Class屬性,屬性值為“qipao”。
那么我們就在頁面中查找,如果出現(xiàn)了這個class值為qipao的節(jié)點,那么就可以操作收茶動作。
// 檢查是否可以收茶
func (h *HttpClient) checkCanTakeTea() (bool, error) {
if err := h.getViewState(TianYuanURL); err != nil {
return false, err
}
req, err := http.NewRequest("GET", TianYuanURL, nil)
if err != nil {
return false, err
}
res, err := h.myHttpClient.Do(req)
if err != nil {
return false, err
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
return false, err
}
// 如果可以收茶,則頁面會有 .qipao 這個節(jié)點
if len(doc.Find(".qipao").Nodes) >= 1 {
return true, nil
}
return false, nil
}
這個方法還是使用net/http這個庫。
模擬收茶操作
我們查看頁面中的JS代碼,JS代碼也不多,作用也比較簡單。
主要是頁面倒計時處理和游戲動作的操作。
我們分析JS代碼,可以知道,收茶動作其實就是向服務(wù)器提交這個頁面的參數(shù)。
有茶可收的情況下,會有一個__EVENTTARGET這個參數(shù)的值為LinkButton10。
那么收茶操作的代碼如下:
// 收茶操作
func (h *HttpClient) TakeTea() error {
if err := h.getViewState(TianYuanURL); err != nil {
return err
}
params := url.Values{}
params.Add("__VIEWSTATE", h.ViewState)
params.Add("__VIEWSTATEGENERATOR", h.ViewStateGenerator)
params.Add("__EVENTTARGET", "LinkButton10")
params.Add("__EVENTARGUMENT", "")
postParams := ioutil.NopCloser(strings.NewReader(params.Encode()))
req, err := http.NewRequest("POST", TianYuanURL, postParams)
if err != nil {
return err
}
req.Header.Add("Content-Type", ContentType)
resp, err := h.myHttpClient.Do(req)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return errors.New("收茶操作失??!請檢查并重新操作")
}
defer resp.Body.Close()
return nil
}
模擬澆水操作
這個游戲的規(guī)則為,收茶之后,還需要向茶樹澆水。
澆水操作的原理和收茶類似,只是參數(shù)值不同。
這樣的話,那么事情就簡單了。
// 澆水操作
func (h *HttpClient) Watering() error {
if err := h.getViewState(TianYuanURL); err != nil {
return err
}
params := url.Values{}
params.Add("__VIEWSTATE", h.ViewState)
params.Add("__VIEWSTATEGENERATOR", h.ViewStateGenerator)
params.Add("__EVENTTARGET", "")
params.Add("__EVENTARGUMENT", "")
params.Add("Button1", "確認澆水")
postParams := ioutil.NopCloser(strings.NewReader(params.Encode()))
req, err := http.NewRequest("POST", TianYuanURL, postParams)
if err != nil {
return err
}
req.Header.Add("Content-Type", ContentType)
resp, err := h.myHttpClient.Do(req)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return errors.New("澆水操作失?。≌垯z查并重新操作")
}
defer resp.Body.Close()
return nil
}
到這里,對這個游戲的主要的操作的模擬都有了。
接下來就是把這幾個動作串聯(lián)起來。
登錄->檢查是否可以收茶->收茶->澆水->退出登錄
這一系列的動作,我們把它看成一個任務(wù)。放到一個方法中。
// 執(zhí)行任務(wù)
func (h *HttpClient) TaskRun() error {
for _, item := range users {
// 1.登錄
fmt.Println(tools.Timetostr(0), " 登錄...")
if err := h.Login(item["userName"], item["password"]); err != nil {
return err
}
// 2.檢查是否可以收茶
fmt.Println(Timetostr(0), " 檢查...")
status, err := h.checkCanTakeTea()
if err != nil {
return err
}
// 3.如果可以收茶,則收茶和澆水
if status {
if err := h.TakeTea(); err != nil {
return err
}
fmt.Println(Timetostr(0), item["userName"]+" 收茶成功...")
// 延時2分鐘
time.Sleep(time.Duration(120) * time.Second)
if err := h.Watering(); err != nil {
return err
}
fmt.Println(Timetostr(0), item["userName"]+" 澆水成功...")
}
// 延時50秒
time.Sleep(time.Duration(50) * time.Second)
// 4.操作完畢,退出登錄
fmt.Println(Timetostr(0), " 退出...")
if err := h.Logout(); err != nil {
return err
}
}
return nil
}
// 獲取當前日期時間
func Timetostr(unixTime int64) string {
if unixTime == 0 {
unixTime = time.Now().Unix()
}
timer := time.Unix(unixTime, 0)
return timer.Format(TimeLayoutLong)
}
為了能更好地模擬人工操作,我們在執(zhí)行完一個操作之后,加了一個延時。
同時將程序執(zhí)行的情況輸出到屏幕。
是用Golang做開發(fā),有個很方便的地方就是有強大的標準庫。
讓Golang定時執(zhí)行也是很方便的。
代碼如下:
// 需要監(jiān)控的賬戶
var users []map[string]string = []map[string]string{
{
"userName": "18*******44",
"password": "********",
},
{
"userName": "18*******20",
"password": "********",
},
}
func main() {
fmt.Println("開始定時任務(wù)...")
// 10分鐘執(zhí)行一次
for range time.Tick(time.Duration(600) * time.Second) {
httpClient := new(HttpClient)
if err := httpClient.TaskRun(); err != nil {
fmt.Println(err.Error())
}
}
}
這樣,多個賬戶,定時執(zhí)行就完成了。
更多精彩內(nèi)容發(fā)布于公眾號:代碼乾坤 (CoderLand)
熱門資訊
探討游戲引擎的文章,介紹了10款游戲引擎及其代表作品,涵蓋了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戲設(shè)計領(lǐng)域和數(shù)字藝術(shù)教育的重要性,歡迎點擊咨詢報名。
2. 手機游戲如何開發(fā)(如何制作傳奇手游,都需要準備些什么?)
?如何制作傳奇手游,都需要準備些什么?提到傳奇手游相信大家都不陌生,他是許多80、90后的回憶;從起初的端游到現(xiàn)在的手游,說明時代在進步游戲在更新,更趨于方便化移動化。而如果我們想要制作一款傳奇手游的
3. B站視頻剪輯軟件「必剪」:免費、炫酷特效,小白必備工具
B站視頻剪輯軟件「必剪」,完全免費、一鍵制作炫酷特效,適合新手小白。快來試試!
游戲中玩家將面臨武俠人生的掙扎抉擇,戰(zhàn)或降?殺或放?每個抉定都將觸發(fā)更多愛恨糾葛的精彩奇遇?!短烀嬗肪哂卸嗑€劇情多結(jié)局,不限主線發(fā)展,高自由...
5. Bigtime加密游戲經(jīng)濟體系揭秘,不同玩家角色的經(jīng)濟活動
Bigtime加密游戲經(jīng)濟模型分析,探討游戲經(jīng)濟特點,幫助玩家更全面了解這款GameFi產(chǎn)品。
6. 3D動漫建模全過程,不是一般人能學(xué)的會的,會的多不是人?
步驟01:面部,頸部,身體在一起這次我不準備設(shè)計圖片,我從雕刻進入。這一次,它將是一種純粹關(guān)注建模而非整體繪畫的形式。像往常一樣,我從Sphere創(chuàng)建它...
7. 3D動畫軟件你知道幾個?3ds Max、Blender、Maya、Houdini大比拼
當提到3D動畫軟件或動畫工具時,指的是數(shù)字內(nèi)容創(chuàng)建工具。它是用于造型、建模以及繪制3D美術(shù)動畫的軟件程序。但是,在3D動畫軟件中還包含了其他類型的...
?三昧動漫對于著名ARPG游戲《巫師》系列,最近CD Projekt 的高層回應(yīng)并不會推出《巫師4》。因為《巫師》系列在策劃的時候一直定位在“三部曲”的故事框架,所以在游戲的出品上不可能出現(xiàn)《巫師4》
9. 3D打印技巧揭秘!Cura設(shè)置讓你的模型更堅固
想讓你的3D打印模型更堅固?不妨嘗試一下Cura參數(shù)設(shè)置和設(shè)計技巧,讓你輕松掌握!
10. Unity3D入門:手把手帶你開發(fā)一款坦克大戰(zhàn)的游戲
Unity工程創(chuàng)建完成后如圖所示: 接下來應(yīng)該導(dǎo)入此項目所需的Unity Package文件,要用到的Unity package文件大家可以去Unity3D的官方網(wǎng)站下載(地址:ht...
最新文章
同學(xué)您好!