怒っているペットブラウザーのボット

警告 :ボットは簡単に不名誉になります。 何か新しいことを学ぶことはまずありません。 楽しみのための記事。



1年後、VKontakteの友達が楽しんでいるものを見ることができると決めました。 従来の大量の政治、子猫やその他のわいせつ物の写真に加えて、私はAngry Petsブラウザへのリンクを見つけました。 私はブラウザをプレイしたことがないので、どんな種類の獣なのかを見ることにしました。 最もかわいい写真(かわいい猫、ペンギン、リスがお互いの顔を打ちます)、肛門を寄付する(お金が収入を8倍にします)、プロット、戦略、絶望、マニュアル、その他の通常のアメニティが欠けています。



ゲームは、建物を建てる、10分待つ、ユニットを建てる、10分待つ、被害者を見つける、攻撃するユニットを送る、10分待つ、被害者を見つける、攻撃するユニットを送る、10分待つ、という単純な操作で構成されています。 ...(高レベルでの10分間は指数関数的に増加します。加速のため-有料です。)



そのようなゲームをどうするか? そうです、ボットを書いてください。 正直なところ、 これをプレイしないでください。







タスクを設定します。





ボットがすぐに燃えないように、まず、長い間オンラインになっていない農場の 赤ちゃんbeる犠牲者を選択し、私たちがどこに行くべきかについて不平を言わないようにします。 第二に、ユーザーのアクションをシミュレートし、裸のAJAXリクエストを送信しません。 第三に、アクション間の遅延はランダムではなく、ゼロです。



ボットの作成者が喜ぶように、サイト上のスクリプトは難読化されていません。 パッケージ化されたスクリプトはjQueryとその他のみです。 そして、はい、jQueryがあるので、文明のすべての利点を使用します。



ゲーム内のほとんどのアクションは、AJAXリクエストにつながります。 アイテムをクリックすると、リクエストはなくなり、ほぼ全画面または別のウィンドウが表示されます。 デバッガーでリンクを調べると、次のようになっていることがわかります。
<a href="/10193192/city/view/10009466" data-link-handled="1" onclick="Main.goToUrl(this);return false;"></a>
      
      



Main.goToUrlメソッドは、文字列またはリンク要素を受け入れます。 ほとんどのゲームリンクの先頭には、プレーヤープロファイル識別子が付いたプレフィックスがあります。 保存してください。



  profilePath: window.location.pathname.match(/^\/\d+\//)[0],
      
      





AJAXリクエストを待機させる方法は? JQueryには素敵な関数$ .ajaxSuccessがあり、リクエストが成功するたびにコールバックを渡すことができます。 イベント、XMLHttpRequestオブジェクト、および$ .ajax呼び出しへの引数がそこにダンプされます。 したがって、特定のURLを受信すると、コールバックを呼び出します。



  ajaxCallbacks: {}, run: function () { ... $('html').ajaxSuccess(Bot.ajaxSuccess); ... }, ajaxSuccess: function (e, xhr, settings) { var ajaxUrl = null, ajaxCallback = null; $.each(Bot.ajaxCallbacks, function (url, callback) { var fullUrl = Bot.profilePath + url; if (settings.url.substr(0, fullUrl.length) == fullUrl) { ajaxUrl = url; ajaxCallback = callback; } }); if (ajaxCallback) { Bot.ajaxCallbacks[ajaxUrl] = null; setTimeout(ajaxCallback, Bot.getClickDelay()); } }, waitForAjax: function (pageUrl, gotoPage, success) { Bot.ajaxCallbacks[pageUrl] = success; gotoPage(); },
      
      





まあ、純粋にwaitForAjaxの均一性のために、AJAXを待つのではなく、単に遅延を作る必要がある場合にwaitForActionを追加します。



  waitForAction: function (action, success) { action(); setTimeout(success, Bot.getClickDelay()); },
      
      





単純な人間の人間はしばしばどのように農業をしますか? 彼はメールボタンを押し、ログに行き、最近攻撃された都市を選択し、「攻撃」をクリックし、ユニットを選択し、「顔を塗りつぶす」をクリックします。







したがって、この操作を円で繰り返します。 もちろん、ログでは適切なページの適切な都市は常にそうとは限りませんが、特別な動機なしで裏返しの複雑なロジックを記述することは率直に言って怠です。



被害者を選択し、リンクを形成します...

  attackNext: function () { if (Bot.targetCities.length == 0) return; if (!Bot.targetCities[Bot.currentTargetCity]) Bot.currentTargetCity = 0; var targetCity = Bot.targetCities[Bot.currentTargetCity++], targetCityUrl = 'city/view/' + targetCity, attackCityUrl = 'attack/' + targetCity;
      
      





リンクをたどってボタンをクリックして......

  Bot.waitForAjax('pm/inbox', function () { Main.goToUrl(Bot.profilePath + 'pm/inbox'); }, function () { Bot.waitForAjax('pm/logs', function () { Main.goToUrl(Bot.profilePath + 'pm/logs'); }, function () { Bot.waitForAjax(targetCityUrl, function () { Main.goToUrl(Bot.profilePath + targetCityUrl); }, function () { Bot.waitForAjax(attackCityUrl, function () { $('button[onclick^="Attack.showAttackAlert"]').click(); }, function () {
      
      





特定の単位を選択するか(利用可能な数量は最大入力属性にあります)、すべてを選択し(別のボタン)、最も重要なこと:「攻撃」をクリックします。

  Bot.waitForAction(function () { var count = 0; $.each(Bot.attackUnits, function (unitType, unitNum) { var ctl = $('input[name="units[' + unitType + ']"]'); ctl.val(Math.min(ctl.attr('max'), unitNum)).change(); count++; }); if (count == 0) { $('span[onclick^="Attack.ChooseEveryone"]').click(); } }, function () { $('button[type=submit]').click(); setTimeout(Bot.attackNext, Bot.getAttackInterval()); })
      
      





AJAXページをクリックすると、Popapレイヤーが閉じます。気にすることはできません。



実際には、それだけです。 誰が濡れているかを見るために、攻撃された都市の美しいリストのみを固定できます。



完全なコード:

 window.Bot = { attackInterval: /*5.5*/8 * 60 * 1000, // 8 min attackIntervalRandom: 1.2 * 60 * 1000, // 1.2 min clickDelay: 3 * 1000, // 3 sec clickDelayRandom: 4 * 1000, // 4 sec targetCities: [ //12345678 ], attackUnits: { //101: 99 }, profilePath: window.location.pathname.match(/^\/\d+\//)[0], currentTargetCity: 0, ajaxCallbacks: {}, run: function () { var box = '<div style="position: absolute; background: #fff; padding: 10px; border-radius: 10px; left: 20px; top: 20px; z-index: 666666">'; $.each(Bot.targetCities, function (_, cityId) { box += '<a class="bot-target-city" data-link-handled="1" onclick="Main.goToUrl(this);return false;"' + ' id="bot-target-city-' + cityId + '"' + ' href="' + Bot.profilePath + 'city/view/' + cityId + '">' + cityId + '</a><br>'; }); box += '</div>'; $('body').append(box); $('html').ajaxSuccess(Bot.ajaxSuccess); Bot.attackNext(); }, ajaxSuccess: function (e, xhr, settings) { var ajaxUrl = null, ajaxCallback = null; $.each(Bot.ajaxCallbacks, function (url, callback) { var fullUrl = Bot.profilePath + url; if (settings.url.substr(0, fullUrl.length) == fullUrl) { ajaxUrl = url; ajaxCallback = callback; } }); if (ajaxCallback) { Bot.ajaxCallbacks[ajaxUrl] = null; setTimeout(ajaxCallback, Bot.getClickDelay()); } else { console.log('Not recognized ' + settings.url); } }, waitForAjax: function (pageUrl, gotoPage, success) { Bot.ajaxCallbacks[pageUrl] = success; gotoPage(); }, waitForAction: function (action, success) { action(); setTimeout(success, Bot.getClickDelay()); }, getAttackInterval: function () { return parseInt(Bot.attackInterval + Math.random() * Bot.attackIntervalRandom); }, getClickDelay: function () { return parseInt(Bot.clickDelay + Math.random() * Bot.clickDelayRandom); }, attackNext: function () { if (Bot.targetCities.length == 0) return; if (!Bot.targetCities[Bot.currentTargetCity]) Bot.currentTargetCity = 0; var targetCity = Bot.targetCities[Bot.currentTargetCity++], targetCityUrl = 'city/view/' + targetCity, attackCityUrl = 'attack/' + targetCity; $('a.bot-target-city').css({ fontWeight: 'normal' }); $('a#bot-target-city-' + targetCity).css({ fontWeight: 'bold' }); Bot.waitForAjax('pm/inbox', function () { Main.goToUrl(Bot.profilePath + 'pm/inbox'); }, function () { Bot.waitForAjax('pm/logs', function () { Main.goToUrl(Bot.profilePath + 'pm/logs'); }, function () { Bot.waitForAjax(targetCityUrl, function () { Main.goToUrl(Bot.profilePath + targetCityUrl); }, function () { Bot.waitForAjax(attackCityUrl, function () { $('button[onclick^="Attack.showAttackAlert"]').click(); }, function () { Bot.waitForAction(function () { var count = 0; $.each(Bot.attackUnits, function (unitType, unitNum) { var ctl = $('input[name="units[' + unitType + ']"]'); ctl.val(Math.min(ctl.attr('max'), unitNum)).change(); count++; }); if (count == 0) { $('span[onclick^="Attack.ChooseEveryone"]').click(); } }, function () { $('button[type=submit]').click(); setTimeout(Bot.attackNext, Bot.getAttackInterval()); }) }); }); }); }); } }; Bot.run();
      
      







使用説明書:





一般的に、ゲームの所有者の慢さは私を楽しませる。 オズベリンの形での「サブスクリプション料金」(それよりもさらに憂鬱にプレーするために)は180ルーブル/月です(このゲームにはないすべてを持っているWoWは、わずか2倍の費用がかかります)。 リソースは最大120ルーブル/日(1日!)で購入でき、リソースの抽出速度が8倍になります(ウォレットの競合、非支払いは一般に森に行きます)。 加速器への寄付を強要するための空きスペース、ロケット用の部品、攻撃のためのボーナス、クエストの完了(そう、私は300ルーブルを支払いました-クエストは合格しました)および他の些細な事は一般に無制限です。 リソースの交換、クランへの参加など-お金だけで。 彼らは「プレイヤーの選択」を支払わなければなりません-これらは1,500ルーブルのコインです。 そして、これらはすべて鉄の議論によってカバーされています。 あなたはかわいいふわふわの動物を救います! あなたはdします-ナフィグを禁止します!」



そして結局のところ、人々は支払います。 私は間抜けです。



All Articles