Пишем бота для браузерной игры при помощи cURL (PHP)

Играли ли вы когда нибудь в браузерную игру? А часто ли вы наблюдали, что разработчики игр часто ставят пользователей в такую ситуацию, когда "прокачка" вашего чара (персонажа) становится настолько уныла, что для того, чтобы ускорить этот процесс вам предлогают платить реальные деньги, за получение всяких плюшек. Цель разработчиков игры - максимальная прибыль с "хомячков", которые "клюнули на крючок". Те, у кого толстые кошельки, платят денюжку и радуются жизни. Другие, т.н "задроты" или "школота" упорно не сдаются и продолжают тупо монотонно зарабатывать игровые деньги или другие игровые ресурсы. Но эти два способа нам не подходят! Потому что игра то в браузере! И все действия проходят по стандартному HTTP протоколу, создавая от пользователя GET или POST запросы. Поэтому-то мы и напишем бота, который будет висеть в кроне (планировщик задач) и добывать ценные игровые ресурсы за нас :) Для этой цели нам хорошо подойдет библиотека cURL в PHP. Итак, приступим.

Для тех, кто незнаком с cURL (Client URL Library), объясню как происходит работа:
  1. Инициализируем новую сессию через функцию curl_init
  2. Навешиваем кучу опций для нашего дальнешего запроса к серверу, через curl_setopt или curl_setopt_array
  3. Выполняем сформированный запрос через curl_exec
  4. Получаем ответ, обрабатываем данные, меняем опции cURL-сессии, снова выполняем, итд.

CURL — это удобная библиотека, позволяющая автоматически логинится на сайте, сохранять данные сессии (куки) в файл с последующем их использованием, автоматически следовать по ссылке при серверном редиректе (301, 302), автоматически подставлять реферер страницы, итд.

Итак, напишем класс, который будет создавать новую CURL сессию, и будет иметь метод, позволяющий менять основные опции в рамках одной CURL-сессии, чтобы управлять процессом грабинга страницы :) Это будут в основном 2 параметра: метод запроса страницы (GET или POST) и данные для отправки (для POST-а).

Вот список основных опций для curl_setopt, которые нам понадобятся:
  • CURLOPT_HTTPHEADER - опция нужна для формирования дополнительных заголовков в HEAD, отправляемых серверу. она будет нужна в основном для эмуляции захода пользователя "через браузер".
  • CURLOPT_COOKIEFILE - абсолютный путь до файла куков (путь для сохранения)
  • CURLOPT_COOKIEJAR - абсолютный путь до файла куков (путь использования уже созданного файла, должен быть такой же как и CURLOPT_COOKIEFILE)
  • CURLOPT_AUTOREFERER - с этой опцией cURL будет автоматически подменять заголовок HTTP_REFERER при всяких редиректах
  • CURLOPT_RETURNTRANSFER - включение этой опции отключает автоматически вывод результата в браузер (print, echo) после curl_exec, таким образом он будет возвращатся нам через return.
  • CURLOPT_FOLLOWLOCATION - автоматическое следование при редиректах (301). внимание: эта опция не работает при включенном безопасном режиме safe_mode или установленном значении open_basedir, до php 5.3 эти опции можно отключить только или в php.ini или в httpd.conf файлах
  • CURLOPT_URL - задаем адрес для последующего вызова curl_exec
  • CURLOPT_POST - флаг, отвечающий за то, будет ли следующее выполнение curl_exec идти методом POST.
  • CURLOPT_POSTFIELDS - данные для отправки методом POST в формате param1=value1&param2=value2
  • CURLOPT_REFERER - опция для установки Referer-заголовка (для тех кто в танке, это URL-страницы с которой мы пришли на текущую)
Вот, впринципе и всё:
class MyOnlineBrowserGameBot
{
	private $user, $pass, $cookie;
	public 
		$url, $referer, $connect, 
		$html, $xml, $error, $info;
	
	public function __construct($user, $pass)
	{
		$this->url = 'http://www.адрес-онлайн-игры.ru/';
		$this->connect 	= curl_init();
		$this->user = $user;
		$this->pass = $pass;
		$this->cookie = getcwd() ."/cookie.txt";
		
		$header = explode("\n", trim('
			User-Agent: Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.00
			Host: www.moswar.ru
			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($this->connect, array
		(
			CURLOPT_HTTPHEADER 		=> $header,
			CURLOPT_COOKIEFILE 		=> $this->cookie,
			CURLOPT_COOKIEJAR		=> $this->cookie,
			CURLOPT_AUTOREFERER 	=> true,
			CURLOPT_RETURNTRANSFER 	=> true,
			CURLOPT_FOLLOWLOCATION => true
		));
	}
	
	public function __destruct()
	{
		curl_close($this->connect);
	}
	
	/** Делаем запрос и меняем реферер **/
	protected function action( $params = array() )
	{
		$ch 		= $this->connect;
		$params 	= (array) $params;
		$timeout 	= isset($params['timeout']) ? $params['timeout'] : mt_rand(1,3); // sec
		$action		= $this->url . ($params[0] ? $params[0] : $params['action']);
		$method 	= strtoupper( isset($params['method']) ? $params['method'] : 'GET' );
		$postdata	= $params['data'];
		
		curl_setopt($ch, CURLOPT_URL, $action);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLINFO_HEADER_OUT, true);
		
		switch( $method )
		{
			case 'GET': {
				curl_setopt($this->connect, CURLOPT_HTTPGET, true); 
				break;
			}
			case 'POST': {
				curl_setopt($ch, CURLOPT_POST, true);
				curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
				break;
			}
		}
		
		$this->html = curl_exec($ch);
		$this->error = curl_error($ch);
		$this->info = curl_getinfo($ch);
		
		// получаем DOM страницы для поиска элементов
		if( $this->html )
		{
			@$this->xml = new DomDocument;
			@$this->xml->loadHTML( $this->html );
			@$this->xpath = new DomXPath( $this->xml );
		
			/* тут также можно получить и сохранить некоторые параметры игры (например количество денег персонажа) */
			// пример:
			$this->money = $this->xpath->query('//div[@id="money"]/span[@class="count"]')->item(0)->nodeValue;
		}

		curl_setopt($ch, CURLOPT_REFERER, $this->info['url']); // выставляем реферер после exec
		sleep($timeout); // делаем задержку в секундах между запросами
		
		return $this;
	}
	
	/** Первый заход на страницу, если файл куков еще не существует логинемся через POST **/
	public function login()
	{
		if( ! realpath($this->cookie) ) // файл еще не создан, логинемся
		{
			$params = array(
				'method' => 'POST',
				'data' => 'user='. $this->user .'&password='. $this->pass .'&remember=1'
			);
		}
		$this->action($params);
		
		return $this;
	}
}

Основа класса уже готова. Остается только дописать еще игровые методы для конкретной игры, симулирующие "хождение" по сайту и игровой процесс. Также отмечу то, что после того, как мы получили ответ от сервера (данные страницы), нам конечно-же нужно из этой страницы что-то получить. Для этой цели идеально подходят стандартные классы PHP 5 для работы с DOM (Document Object Model) - DomDocument и DomXPath. Для тех кто мало знаком с xpath, можно почитать основную информацию на википедии.

После того, как вы дополните класс методами для конкретной игры, то следующим этапом будет создание файла с режимом работы бота, на основне написанного класса, который в последствии будет вызываться на нашем хостинге планировщиком задач (cron) в нужные нам промежутки времени. Солдат спит, служба идет.

27.09.2010 / php, games, кодинг
Похожие статьи:
Оценка статьи: проголосовало - 4, средняя оценка - 3,5
Комментарии к статье (1):
[ 03.02.2011 - 00:01 ] - Сережа
Спасибо!!! Наконецто разобрался с сURL!
Добавить комментарий
АНТИСПАМ: Выберите улыбающийся смайл: yep! nope! nope!
Оформление заявки
Файл>>