[PHP] Пишем бота для браузерки Небоскрёбы

в 13:55, , рубрики: php, метки: , ,

Доброго времени суток, из интереса к созданию чего-то нового начал играть в 'Небоскрёбы', конечно чтобы создать своего первого игрового бота.

С чем нам предстоит работать?


Итак вот мы залогинились и прошли обучение…

Страница, на которой мы находимся: nebo.mobi/home (далее все ссылки типа /home)

Начинаем изучать. Наш бот должен уметь:

  1. Отрабатывать посетителей в лифте на странице /lift
  2. Собирать деньги
  3. Закупать и выкладывать товар

Я не стану делать чтобы он строил этажи и распределял жителей по работам, так как это сейчас не нужно для понимания процесса создания бота.

Структура игры впринцепе простая.

С технологиями мы не будем заморачиваться…
Возьмём связку PHP + cURL + любую библиотеку для парсинга (я взял Simple HTML DOM)

Пишем основу


Начнём писать основу. Инициализируем и настраиваем cURl:

$url = 'http://nebo.mobi/';
$connect = curl_init($url);
$cookie = 'cookie.txt';

$header = explode("n", trim(' 
   User-Agent: Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.00    
   Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
   Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
   Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1
   Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0
   Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers '));
   array_walk($header, create_function('&$header', '$header = trim($header);'));
      
curl_setopt_array($connect, array (
   CURLOPT_HTTPHEADER => $header, 
   CURLOPT_COOKIEFILE => $cookie, //cookie 
   CURLOPT_COOKIEJAR => $cookie,  //cookie 
   CURLOPT_AUTOREFERER => true,
   CURLOPT_RETURNTRANSFER => true,
   CURLOPT_ENCODING => true,   //игра данные сжимает, а здесь их декодируют
   CURLOPT_FOLLOWLOCATION => true ));

Вроде настроили! Теперь надо сделать основную функцию выполнения действий назовём её action:

function action($action, $method, $postdata = NULL){
   $ch = $connect; //делаем копию cURL
   $action = $url . $action; 
   curl_setopt($ch, CURLOPT_URL, $action); //изменяем url
   curl_setopt($ch, CURLOPT_HEADER, 0); //чтобы заголовки не отображались
   curl_setopt($ch, CURLINFO_HEADER_OUT, true);
   switch($method) { // настраиваем cURL на определённый метод
      case 'GET': {
         curl_setopt($connect, CURLOPT_HTTPGET, true); 
         break;
      }
      case 'POST': {
         curl_setopt($ch, CURLOPT_POST, true);
         curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
         break;
      }
   }
   $html = curl_exec($ch); //выполняем запрос
   curl_setopt($ch, CURLOPT_REFERER, $info['url']); //рефёр чтобы бота не обнаружили
   $timeout = mt_rand(1,3); // Рандромное время для задержки
   sleep($timeout); // задержка
   return $html; //возвращаем то, что получили от игры
}
function login($user, $pass) { //функция логин
   if( ! realpath($cookie) ) { //проверка существования cookie если их нет то:
      action('login?wicket:interface=:893:loginForm:loginForm::IFormSubmitListener::', 'POST', 'nick='. $user .'&password='. $pass); //логинимся
   }
}

Признаюсь, функцию action и login взял отсюда: zhyk.ru

Пишем дополнительные функции


Дальше нам надо реализовать функции действий бота, вспомним список задач для бота:

  1. Отрабатывать посетителей в лифте на странице /lift
  2. Собирать деньги
  3. Закупать и выкладывать товар

Давайте сделаем отработку лифта:

1. Анализируем страницу /lift ->
(Это сокращение до нужного нам дива)

<div class="lift">
...
<span class="ctrl">
...
<span class="">Посетитель</span>: <b class="white nwr"><span>11</span> этаж!</b><br/>
...
<a class="tdu" href="../../lift/wicket:interface/:0:liftState:upLink::ILinkListener::">Поднять лифт на <span>5</span> этаж</a>
</span>
...
</div>

То есть нам нужна ссылка 'Поднять лифт на 5 этаж'. Смотрим на код и придумываем как эту ссылку достать. Ссылка у нас с class=tdu находиться в span с class=ctrl который в свою очередь находиться в div с class=lift. И вот у нас готов код для парсинга из кода и перехода по полученной ссылке:

$html1 = str_get_html(action('lift', 'GET'));//выполняем действие и берем в объект Simple html dom
$liftSsulka = $html1->find('div[class="lift"] span[class="ctrl"] a[class="tdu"]');
action($liftSsulka->href, 'GET');

Но этот код делает всё один раз, а в лифте может находиться несколько посетителей!
Первое что пришло мне на ум — запихнуть всё в рекурсивную функцию с остановкой когда ссылки нет. Готово:

function liftExec(){
   $htmlL = str_get_html(action('lift', 'GET'));
   $a = $htmlL->find('div[class="lift"] span[class="ctrl"] a[class="tdu"]');
   $c = $a[0]->href;
   if($c != NULL){
      action($c, 'GET');
      liftExec();
   }
}

Следующие функции выполняются также только без рекурсии из-за того что на страницах все ссылки лежат списком:

Функция сборки выручки

function money(){
   $fl2 = str_get_html(action('floors/0/5', 'GET')); // floors/0/5 - страница сборки выручки
   $li = $fl2->find('div[class="flst"] span a'); //ищем ссылку 'собрать монеты'
   foreach($li as $l){
      $ll = $l->href;
      action($ll, 'GET']); // выполняем переход по ссылке
   }
}

Функция выкладывания товара

function vulojitTowar(){
   $fl2 = str_get_html(action('floors/0/3', 'GET'));
   $li = $fl2->find('div[class="flst"] span a');
   foreach($li as $l){
      $ll = $l->href;
      action($ll, 'GET']);
   }
}

Две функции выше простые, но следующая более сложная, так как при закупке товара надо ещё выбрать какой вид товара надо закупить на каждом этаже, что добавляет ещё один вложенный цикл.

Функция закупки товара

function zackypitTowar(){
   $fl2 = str_get_html(action('floors/0/2', 'GET')); // получаем страницу закупки
   $li = $fl2->find('div[class="flst"] span a'); // ищем ссылки 'закупить товар'
   foreach($li as $l){
      $ll = $l->href;                    // немного непонятной химии со ссылкой
      $ll = explode('/',$ll);            // ещё немного
      $ll = $ll[2].'/'.$ll[3].'/'.$ll[4];// и ещё 
      $htmlll = str_get_html(action($ll, 'GET'));
      $aaa = $htmlll->find('span[class="action"] a a'); // берём ссылки выбора что закупить
      $aaa = $aaa[0]->href; // берём из них только первую - самую не дорогую
      $bbb = substr($aaa, strrpos($aaa, '/')+1); // химичим
      action($bbb, 'GET'); // выполняем запрос
   }
}

Итоги


Получилась средняя библиотека функций для создания бота. Тоесть чтобы создать бота надо придумать и реализовать ещё какой-то программный цикл. Все эти функции тоже сырые.
Что ещё хочу сказать — каждая из этих функций не защищена от различных 'непредвиденных ситуаций' типа ошибок сервера, бана аккаунта или обычного 'нет этажей для сбора монет' ну вообщем вы поняли.

Автор: авторитет

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js