Showroomでの自動星集めの試み (4) 星集めツール
なおあらためて書きますが、これは技術的にこうすればできるというだけの記事です。こういう方法がShowroomのルール上問題ないのかとか、こういうことをしたとき配信者にどういう印象を与えるかはまだ考えていません。実際に使うのであればそういうところをよく検討した上でお願いします(「Showroomでの自動星集めの試み (2) 配信ルームの一覧を作る」に「SHOWROOM 会員規約」の内容についてちょっと触れています)
追記 星集め、種集めの目的は言うまでもなく星投げ、種投げでしょう。そういうことでしたら次の記事が参考になると思います。
「Showroom - 自動星集め・星投げ・カウントツール)」 (使用法とソースつき)
------
次のような“仕様”です。仕様と言っても概要です。詳細はプログラムとそこに書かれたコメントを参考にしてください。
それからこのプログラムではログイン操作は行っておらず、ログイン操作を行った環境で起動すれば環境を受け継ぐことができる、ことを利用しています。これについては例えば「Qiita @0829 - Goではじめてみたブラウザの自動操作」 に説明があります。
1. 「アイドル」枠~「お笑い・トーク」枠について以下を繰り返す。
1.1 「まいにち○○」と「ONLIVE」について以下を繰り返す。
1.1.1 配信ルーム数を取得する
1.1.2 配信ルームの数の分以下を繰り返す
1.1.2.2 配信開始時刻が一定の範囲にあるものだけ名前、URLをリストに格納する。
1.1.3 リストに格納されたルームの数の分以下を繰り返す。
1.1.3.1 ルームを開く
1.1.3.2 自動カウントを開始する(Showroom Toolboxを使います)
1.1.3.3 30秒ウエイトします。
1.1.3.4 獲得ポイントを取得します。
1.1.3.5 獲得ポイントが99ptになったとき、あるいは獲得ポイントが3回続けて同じ値のときはすべてのループをブレークします。
1.1.2.2で配信時刻をチェックしているのは特定のルームの一回の配信中に2回訪問しないようにするためです。一定の範囲は現在“40分前~現時点”としています。今後いわゆる“三周”を行ったりすることを考えると、
ルームを配信開始時刻の古い順に開いていき
99ptになったときのルームの配信開始時刻を記録する
次の巡回ではその時刻以後開始したルームを探索する
というような方法が妥当かもしれません。
また三周時の短時間での星集めではTwitter投稿による“ボーナス”を利用すべきかも。
実行結果の例(部分)
“<× 5>”というような表示が獲得ポイントです。ほんとうは5ずつ増えていくはずですが、
・リストを取得してからルームを開く前に配信が終了していた。
・表示のタイムラグで一つ前の状態の獲得ポイントが取得された
などあって獲得ポイント数の表示に乱れが生じることがあります。
また、
[2740:11996:0103/081342.970:ERROR:process_metrics.cc(105)] NOT IMPLEMENTED
というエラーメッセージが表示されることがありました。動作に問題はなさそうですが原因・理由はまだわかりません。
21003,<× 5>,<https://www.showroom-live.com/48_ISHIDA_CHIHO>,<石田 千穂(STU48)>
21004,<>,<https://www.showroom-live.com/tps_0430>,<【SOS】高3あやのんののんびりお天気お姉さん>
21006,<× 10>,<https://www.showroom-live.com/kazchi22>,<【新アバ配布中】PKMあかりのふわふわるーむ>
21007,<× 15>,<https://www.showroom-live.com/komugisrf>,<SRF AWARD 2017★@秋田県産小麦>
21008,<× 20>,<https://www.showroom-live.com/miyamae>,<イベント参加中!宮前優花の わらいまSHOWROOM!!!>
21009,<× 20>,<https://www.showroom-live.com/comet_mikuru>,<SOS!ガチイベ!♡みくる♡【J&M】>
21010,<× 30>,<https://www.showroom-live.com/harajukumate_riri1>,<☆りりRooM☆ハラ塾メイト市村梨里>
21011,<× 30>,<https://www.showroom-live.com/0122_tps>,<金井千咲のチータイガーがおがおroom♡>
-------------------------
参考
「Showroom - 自動星集め・星投げ・カウントツール)」 (使用法とソースつき)
「Showroom - 自動三周ツール(もう一つの自動星集め・星投げ・カウントツール)」
「Showroom - イベントの獲得ポイント数を取得して記録するツール」
「Showroom - 福引するプログラムとその結果 (1)」
「Showroom - イベント結果データ」
「Showroomの複数アカウント(複アカ、複垢)について考えてみた(1)」
「Showroom - 複数アカウント(複垢)問題の真実 - 実験計画」
「Showroomの重複アカウント(複垢)減算はこうして起きる」
「Showroomでの自動星集めの試み (3) ガチイベ、最後の5分間
「Showroom ラスカルイベの最後の5分間」
「Showroomでの自動星集めの試み (1)」
「Showroomでの自動星集めの試み (2) 配信ルームの一覧を作る」
「Showroomでの自動星集めの試み (4) 星集めツール」
「Showroomでひたすらリスナーレベルを上げるための星集めツール(Go/Agouti)」
「超初心者のGo言語/agouti - ブラウザ操作の基本の基本」
「超初心者のGo言語 - 複数の戻り値をもつ関数」
「超初心者のGo言語 - もっとも簡単なGoroutine(並列処理)」
---------------------
「GoDoc - package agouti」
「Qiita @0829 - Goではじめてみたブラウザの自動操作」
「Qiita @tenten0213 - agoutiというWebDriverクライアントを使って面倒な作業を自動化する」
「Qiita @masaru_b_cl - Windows上でGo言語初心者向け学習環境を作る」
「はじめてのGo言語」
「天才まくまくノート - まくまく Hugo/Go ノート - 関数を定義する (func)」
「Qiita @TakaakiFuruse - Golang Goの並列処理を学ぶ(goroutine, channel)」
「Qiita @To_BB - Rubyエンジニアがゴルーチン(Go言語)を学んでみた【初心者向け】」
「Qiita @fukumone - goroutine 使い方まとめ」
package main
import "github.com/sclevine/agouti"
import "fmt"
import "time"
import "strings"
import "os"
func main() {
var hht int
var mmt int
var URL [40]string
var Stat [40]int
var RName [40]string
var StartJ, StopJ int
FmtFrame := "#js-categorymenu-list > li:nth-child(%d)"
FmtNumberOfListner := "#js-onlive-collection > div > section:nth-child(%d) > ul > li:nth-child(%d) > div > div > div.listcard-image > div.listcard-label > div.label-room.is-onlive"
FmtStartTime := "#js-onlive-collection > div > section:nth-child(%d) > ul > li:nth-child(%d) > div > div > div.listcard-image > div.listcard-label > div.label-room.is-start-time"
FmtName := "#js-onlive-collection > div > section:nth-child(%d) > ul > li:nth-child(%d) > div > div > div.listcard-info > h4"
FmtURL := "#js-onlive-collection > div > section:nth-child(%d) > ul > li:nth-child(%d) > div > div > div.listcard-image > div.listcard-overview > div > a.js-room-link.listcard-join-btn"
// FmtURL := "#js-onlive-collection > div > section:nth-child(%d) > ul > li:nth-child(%d)"
FmtNoRoom := "#js-onlive-collection > div > section:nth-child(%d)"
fmt.Println(time.Now())
fmt.Sscanf(os.Args[1], "%d%", &StartJ)
fmt.Sscanf(os.Args[2], "%d%", &StopJ)
// if StartJ == 0 {StartJ = 2 }
// if StopJ == 0 {StopJ = 7 }
fmt.Println("from ", StartJ, " to ", StopJ)
// Chromeを利用することを宣言
agoutiDriver := agouti.ChromeDriver()
agoutiDriver.Start()
defer agoutiDriver.Stop()
// Showroomにログインし、Showroom Toolboxが使える環境を作っておき
// その環境を引き継げるようにShowroomを起動する。
page, _ := agoutiDriver.NewPage(agouti.Desired(agouti.Capabilities{
"chromeOptions": map[string][]string{
"args": []string{
"user-data-dir=C:\\Tmp\\Chrome",
},
},
}),
)
// 時刻を表示します。
t := time.Now()
hh, mm, ss := t.Clock()
yr, mt, dy := t.Date()
LogTime := fmt.Sprintf("%02d:%02d:%02d", hh, mm, ss)
LogDate := fmt.Sprintf("%04d:%02d:%02d", yr, mt, dy)
fmt.Print(LogDate, "-", LogTime, " ")
// ログファイル名には日付時刻を使う。
FileName := fmt.Sprintf("%1d%1d_%4d%02d%02d_%02d%02d%02d.txt", StartJ, StopJ, yr, mt, dy, hh, mm, ss)
f, _ := os.OpenFile(FileName, os.O_CREATE|os.O_WRONLY, 0644)
hhmm := hh*60 + mm
// 3重ループを一気にブレークするときに使うラベルです
OuterLoop:
// アイドル枠からお笑い・トーク枠まで巡回するときは2~7、アマチュア枠は8~8
for k := StartJ; k < StopJ+1; k++ {
// 「まいにち○○」と「ONLIVE」を巡回する
// あるいは「初配信(始めて間もないルーム)」と「ONLIVE」を巡回する
for j := 1; j < 3; j++ {
// Showroomオンライブ画面を開く
page.Navigate("https://www.showroom-live.com/onlive")
// 枠を選ぶ
SelectorFrame := fmt.Sprintf(FmtFrame, k)
page.Find(SelectorFrame).Click()
page.Screenshot("Screenshot02.png")
SelectorNoRoom := fmt.Sprintf(FmtNoRoom, j)
NoRoom, _ := page.First(SelectorNoRoom).AllByClass("js-room-link").Count()
// ルームの数だけ繰り返す。
n := 0
for i := 1; i < NoRoom+1; i++ {
SelectorNumberOfListner := fmt.Sprintf(FmtNumberOfListner, j, i)
NumberOfListner, _ := page.Find(SelectorNumberOfListner).Text()
SelectorRoomName := fmt.Sprintf(FmtName, j, i)
// 配信開始時刻を求め、分単位にする
SelectorStartTime := fmt.Sprintf(FmtStartTime, j, i)
StartTime, _ := page.Find(SelectorStartTime).Text()
fmt.Sscanf(StartTime, "%2d:%2d", &hht, &mmt)
hhmmt := hht*60 + mmt
// 前日の配信開始は1日分の分数を引いておきます。
if hhmmt > hhmm+1 {
hhmmt = hhmmt - 1440
}
RoomName, _ := page.Find(SelectorRoomName).Text()
fmt.Printf("%4d%4d %6s %d %d %s", j, i, NumberOfListner, hht, mmt, RoomName)
// 配信開始時刻が一定の範囲にあるルームだけを星集めの対象とする。
if hhmmt > hhmm-40 {
// 配信者画面のURLのリストを作る
SelectorURL := fmt.Sprintf(FmtURL, j, i)
tURL, _ := page.Find(SelectorURL).Attribute("href")
fmt.Println("<", tURL, ">")
URL[n] = tURL
Stat[n] = (k*10+j)*1000 + i
RName[n] = RoomName
n++
// 巡回対象は(運が良ければ)最低20で済むので、40も対象を集めておけばじゅうぶんです。
// 時間帯によってはアイドル枠だけで完了となります。
if n == 40 {
break
}
} else {
fmt.Println("\r\n")
}
}
NoSamePoint := 1
LastValue := " "
for i := 0; i < n; i++ {
// for i := n - 1; i > -1; i-- {
// 配信者の画面を開く(ふつうここでエラーが起きることはないですが....
err := page.Navigate(URL[i])
if err != nil {
fmt.Fprintf(f, "Error!\n")
fmt.Printf("Error!\n")
continue
}
// 配信中でない場合はスキップする。
// 獲得ポイントは配信中であれば"× 80"のような、配信中でなければ""という文字列が得られます。
// 99ポイントのチェックもここでやるほうが合理的だが....
MyPoint, _ := page.Find("#room-gift-item-list > li:nth-child(12) > div").Text()
if strings.Compare(MyPoint, "") == 0 {
continue
}
// 処理開始時刻を取得しログファイルに書き出します。
tti := time.Now()
hhi, mmi, ssi := tti.Clock()
fmt.Fprintf(f, "%02d%02d%02d%4d,", hhi, mmi, ssi, i)
// Showroom Toolboxの機能を使って自動カウントを行う
page.FindByButton("自動カウント").Click()
// 星、種をもらえるまで30秒ウェイトする。
// 30秒ではカウントは15回程度しかできないことに留意する
time.Sleep(30 * time.Second)
// 累計ポイントを取得する。
MyPoint, _ = page.Find("#room-gift-item-list > li:nth-child(12) > div").Text()
fmt.Fprintf(f, "%6d,<%s>,<%s>,<%s>\n", Stat[i], MyPoint, URL[i], RName[i])
fmt.Printf("%6d,<%s>,<%s>,<%s>\n", Stat[i], MyPoint, URL[i], RName[i])
// 99ポイント集まったら処理を終了する。
// 実際には99ポイント集まってから99と表示されるまでタイムラグがあり
// ループの先頭で判断した方がいいかも
// ただそうすると訪問しながらカウントしない配信者さんが出てしまうわけで....
if strings.Compare(MyPoint, "× 99") == 0 {
break OuterLoop
}
// 同じポイントが3回続いたら処理を打ち切る
// 星集めが順調に進んでいても同じポイントが2回続くことはよくあります
if strings.Compare(MyPoint, LastValue) == 0 {
NoSamePoint++
} else {
LastValue = MyPoint
NoSamePoint = 1
}
if NoSamePoint > 2 {
break OuterLoop
}
}
}
}
f.Close()
}
« Showroomでの自動星集めの試み (3) ガチイベ、最後の5分間 | トップページ | Showroom ラスカルイベの最後の5分間 »
「パソコン・インターネット」カテゴリの記事
- さくらインターネットのレンタルサーバーでGOで書いたCGIを動かした(苦労)話(2021.04.19)
- SHOWROOMのAPI - 「ライブ情報」の取得(GO言語のソースつき)(2019.10.26)
- SHOWROOM 星集め・星投げツール スケジュールの詳細化 BreakDownSchedule() (三周のやり方を例に)(2019.09.25)
- SHOWROOM 新・自動三周ツール -- GO言語によるブラウザ制御 (1) main()(2019.09.17)
コメント
この記事へのコメントは終了しました。
« Showroomでの自動星集めの試み (3) ガチイベ、最後の5分間 | トップページ | Showroom ラスカルイベの最後の5分間 »
こんにちは!!
はじめまして!
GO初心者なのですが
この場合、settings.jsonにはどのような設定をしていますか????
投稿: acenbla | 2018年2月26日 (月) 22時33分
設定は何もしていません (^^;;
この記事にあるプログラムの場合は"C:\Tmp\Chrome"をユーザーディレクトリとして使っていますが、プログラムを起動する前に一度だけユーザーディレクトリを変更して( --user-data-dir=C:\tmp\chrome01)Chromeを起動し、普段使うように設定(ログインからウィンドーのサイズまでいろいろ)します。
あとはこの記事に書いてあるプログラムがすべてです。
投稿: セッピーナ | 2018年3月 1日 (木) 10時16分
toolboxのコメント投稿欄に「固定文」をGO言語を用いて入力したいのですが、もし記述方法をご存じであればご教示頂けないでしょうか?
よろしくお願いします。
投稿: 中央線大好き | 2018年4月14日 (土) 22時19分
中央線大好きさん、コメントありがとうございます。
コメントなどを入力して送信するのは以下のいずれかの方法でやれると思います。
ただ現在ChromeのVer.65ではどういうわけかFill()がうまく機能しないようです。しようがないので今はVer.64をインストールし直してやっています。
もしFill()を試みたがうまくいかなかったということでしたら、これが原因ではないかと思います。
----
二つ例をあげますが、どっちかでうまく行くと思います。
page.Find("#js-chat-input-comment").Fill("固定文")
....
page.Find("#js-chat-input-comment").Submit()
あるいは
page.Find("#room_url").Fill("固定文")
....
page.Find("#connectButton").Click()
以上Find()を使っていますが、これはもちろんFindByID()、FindByClass()などなんでもいいです。
なお書きかけですが、以下にまとめていくつもりです。
「超初心者のGo言語/agouti - ブラウザ操作の基本の基本」
http://seppina.cocolog-nifty.com/blog/2018/01/goagouti---59b7.html
投稿: セッピーナ | 2018年4月16日 (月) 09時50分
セッピーナさん
アドバイスいただきありがとうございました。
アドバイスどおり、Chrome のバージョン65や66だとうまく動かず、64だと無事動きました。
今後のバージョンでは動くようになるんですかね。。。
バージョン64にしたら起動が遅くなったような気がします。
今後の最新バージョンで、Fillが正しく動くようになるといいですね。
64で動くことを切り分けるのは大変だったんじゃないでしょうか?
ものすごい分析力にビックリしました。加えて丁寧なアドバスありがとうございました。
投稿: 中央線大好き | 2018年4月23日 (月) 01時20分
やっぱりChromeのバージョンが原因でしたか。
困ったもんですよね。
Chromeのバージョンというよりagoutiのバージョンアップで対応されるんだと期待してるんですが...
少しはお役に立てたようで安心しました (^^)
投稿: セッピーナ | 2018年4月23日 (月) 13時00分
最新版(Ver.240)のchromedriverを使えば最新のChrome(Ver.67)でもFill()が正しく機能することが確認できました(2018.07.18)
投稿: セッピーナ | 2018年7月18日 (水) 13時15分