Авторизация на сайте при помощи библиотеки cUrl Продолжая цикл статей посвященный парсерам и всем, что с ними связано. В этой статье расскажу про то, как легко можно авторизоваться на любом сайте при помощи библиотеку cUrl php. Для примера я взял один Украинский портал, к которому я собственно и буду подбирать ключики. Для работы нам также понадобится библиотека simple_html_dom 

Авторизацию будем проходить на сайте http://tender.me.gov.ua , не буду создавать лишних ссылок, чтобы не накрыть нашу лавочку. 

Для начала зарегистрируйтесь на сайте, чтобы иметь тестовые логин-пароль для входа на сайт. 

На сайте мы видим ничем не примечательную форму авторизации.

Форма авторизации на сайте

"Внутренности" у нее тоже ничем не примечательны

<form id="login" name="login" method="post" action="/EDZFrontOffice/menu/uk/;jsessionid=c4651e96f5c2b9afb08776cbd1a5" enctype="application/x-www-form-urlencoded">
 <input type="hidden" name="login" value="login" />
 <input id="login:login" type="text" name="login:login" class="login" maxlength="80" />
 <input id="login:password" type="password" name="login:password" value="" maxlength="80" class="login" />
 <input type="image" src="images/t_login_button.png;jsessionid=c4651e96f5c2b9afb08776cbd1a5" name="login:j_id_id254" alt="&#1042;&#1093;&#1110;&#1076;" />
 <input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id1:j_id2" autocomplete="off" />
</form>

Итак смотрим, что форма авторизации отправляет при аутентификации. Для этого возпользуемся  Google Chrome, открываем в нем сайт, затем Инструменты->Инструменты разработчика. Далее переходим на вкладку Network. Для браузера Opera Меню->Страница->Средства Разработки->Open Opera DragOnFly и вкладка Сеть. Хоть я и фанат Оперы, но на мой взгляд продукт от компании Google немного удобнее. Я конечно не про браузер =)

Теперь авторизуемся на сайте, смотрим, что посылает форма при сабмите. 

Просмотр отправляемых данных в Google Chrome

Видим, что форма посылает следующие параметры

login:login
login:login:{loginmail}
login:password:{password}
login:j_id_id254.x:8
login:j_id_id254.y:7
javax.faces.ViewState:j_id1:j_id2

Попробуем решить задачу в лоб и отправить эти данные простым массивом. Сразу учтем, что данные отправляются на защищенный ssl url, по протоколу https. Это следует учитывать при отправке данных в cUrl. Рассказывать, как работает SSL в рамках данной статьи я не стану, скажу лишь, что сертификаты, которыми обмениваются две стороны, сами по себе ничего не говорят о его обладателе. Они нужны лишь для того, чтобы передать открытый ключ, обеих сторон и служат для шифрования канала связи. Т.е. мы можем проверять наличие ssl, и подключать сертификат в cUrl, но это будет служить пользу только нам, сервер не может узнать пользуемся ли мы сертификатом, или используем незащищенный канал связи.

//О том, что мы авторизовались будем судить по наличию формы logout
function isAuth( $data ){
	return preg_match('#<form[^>]+id="logout"#Usi',$data);
}
$ch = curl_init();
$url = 'https://tender.me.gov.ua/EDZFrontOffice/menu/uk/';
curl_setopt($ch, CURLOPT_URL, $url ); // отправляем на 
curl_setopt($ch, CURLOPT_HEADER, 0); // пустые заголовки
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возвратить то что вернул сервер
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // следовать за редиректами
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);// таймаут4
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);// просто отключаем проверку сертификата 
curl_setopt($ch, CURLOPT_POST, 1); // использовать данные в post
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
	'login'=>'login',
	'login:login'=>'mylogin@sitename.ru',
	'login:password'=>'password',
	'login:j_id_id254.x'=>8,
	'login:j_id_id254.y'=>7,
	'javax.faces.ViewState'=>'j_id1:j_id2',
));
echo isAuth($data = curl_exec($ch))?'Success':'Failed';
curl_close($ch);

Запускаем и видим, что ничего не получилось. Сайт просто так не сдался. Мы не учли одну вещь, данные об авторизации должны быть сохранены в cookie. Для этого добавим две строчки в код, к примеру после curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

...
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_COOKIEJAR, dirname(__FILE__).'/cookie.txt'); // сохранять куки в файл 
curl_setopt($ch, CURLOPT_COOKIEFILE,  dirname(__FILE__).'/cookie.txt');
...

И снова мимо. Обратим внимание, что форма помимо стандартных логина-пароля, отправляет еще 3 динамических поля. Данные в них все время разные и генерируются при обновлении страницы. Значит, нужно загрузить страницу, скопировать эти данные и проходить аутентификацию уже с ними. Для этого немного "облагородим" код, заключив запрос данных с сервера cUrl'ом в отдельную функцию. Все отличие get запроса от post, заключается в том, что при пост запросе отправляются данные CURLOPT_POSTFIELDS

function request($url,$post = 0){
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url ); // отправляем на 
	curl_setopt($ch, CURLOPT_HEADER, 0); // пустые заголовки
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возвратить то что вернул сервер
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // следовать за редиректами
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);// таймаут4
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($ch, CURLOPT_COOKIEJAR, dirname(__FILE__).'/cookie.txt'); // сохранять куки в файл 
	curl_setopt($ch, CURLOPT_COOKIEFILE,  dirname(__FILE__).'/cookie.txt');
	curl_setopt($ch, CURLOPT_POST, $post!==0 ); // использовать данные в post
	if($post)
		curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
	$data = curl_exec($ch);
	curl_close($ch);
	return $data;
}

Попытаемся выдернуть значения переменных полей 

$data = request('https://tender.me.gov.ua/EDZFrontOffice/');
include 'simple_html_dom.php';
$data = str_get_html($data);
$auth = array(
		'login'=>'login',
		'login:login'=>'***************',
		'login:password'=>'************l',
		'login:j_id_id254.x'=>$data->find('input[name="login:j_id_id254.x"]',0)->value,
		'login:j_id_id254.y'=>$data->find('input[name="login:j_id_id254.y"]',0)->value,
		'javax.faces.ViewState'=>$data->find('input[name="javax.faces.ViewState"]',0)->value,
);
$data->clear();
unset($data);
print_r($auth);

Оказывается, что поле login:j_id_id254.x и поле login:j_id_id254.y создаются и заполняются js скриптом. Попробуем оставить их как были 

$url = 'https://tender.me.gov.ua/EDZFrontOffice/menu/uk/';
$data = request('https://tender.me.gov.ua/EDZFrontOffice/');
include 'simple_html_dom.php';
$data = str_get_html($data);
$auth = array(
		'login'=>'login',
		'login:login'=>'site@sitename.ru',
		'login:password'=>'password',
		'login:j_id_id254.x'=>10,
		'login:j_id_id254.y'=>11,
		'javax.faces.ViewState'=>$data->find('input[name="javax.faces.ViewState"]',0)->value,
);
$data->clear();
unset($data);
echo isAuth(request($url,$auth))?'Success':'Failed';;

Вот  и все, сайт побежден. Далее работаем с ним, как с обычным сайтом. Данные о том, что Ваш скрипт никто иной, как авторизованный пользователь бережно хранятся в cookie.   

Скрипт работает, но в более сложных случаях, приходиться эмулировать выполнение js скриптов, либо просто выяснять механизм их работы, чтобы заполнить те самые динамически заполняемые поля. К сожалению, этому не научишь, все зависит от конкретной задачи и изобретательности программиста. За примерами далеко ходить не надо, попробуйте для интереса создать скрипт, который бы отправлял автоматически, комментарии на xdan.ru. Желаю удачи =)

 

Рассказать друзьям

Добавить комментарий


Защитный код
Обновить

Комментарии   

+3
Евгени
# Евгени 20.07.2012 18:03
Спасибо за статью, как раз её и ждал ;)
+3
Сергей
# Сергей 18.09.2012 17:39
Спасибо очень помогло
+2
Leroy
# Leroy 19.09.2012 11:38
все для вас)
+3
Сергей
# Сергей 19.09.2012 22:57
пробовал сюда отправить сообщение с curl но не получилось), не смог вернуть значение из поля js_key
+2
Leroy
# Leroy 20.09.2012 12:51
свой сайт я привел, как сайт защищенный от подобного рода деятельности. в том и фишка, у меня стоит js защита от спама. на стороне сервера генерируется js скрипт, проводиться его обфуския а затем он выполняется в браузере выдавая некий ключ, аналог которого есть на сервере. при парсинге сайта через php вы не можете выполнить js. в народе называется js капча, Очень примитивная защита, обойти которую достаточно сложно без разбора алгоритма генерации и деобфускации кода, однако и ее можно обойти. код там не сложный) Поставил ее, как только посыпались автоматические посты на сайт со всякой рекламой
+3
Василий
# Василий 20.09.2012 21:35
А как можно выдернуть значение, которое было сгенерированно с помощью js? И вообще реально ли это сделать с помощью чистого php, или надо использовать для этих целей javascript?
0
Leroy
# Leroy 20.09.2012 21:58
либо писать изначально на парсер js либо разбираем ручками алгоритм, уверяю вас это не так сложно как кажется, делал такое и не раз. К примеру можно запустить сайт в браузере, и посмотреть в инспекторе распакованный js, что уже сильно облегчит задачу по генерации своего key
+3
Герман
# Герман 08.01.2013 21:32
Огромное спасибо! Задумал сделать один сервис, без этой статьи было бы не реализовать!
0
Владимир
# Владимир 24.01.2013 19:39
Здравствуйте, очень полезная статься, но я все же не смог сделать авторизацию на betonmarkets.com, там все данные формы передаются на cgi скрипт, но ни dragonfly ни chrome почему-то не выводят список отправленных данных формы. Подскажите пожалуйста куда копать
-1
Leroy
# Leroy 24.01.2013 20:31
копать в сторону функций set_login_url_for_loginid и get_brokercode_from_loginid в исходниках compressed_base.js
-1
Yurant
# Yurant 03.04.2013 12:22
Подскажите пожалуйста по какому принципу была построена строка preg_match() а конкретнее вот этот сегмент, то что после формы:



#]+id="logout"#Usi
0
Leroy
# Leroy 03.04.2013 12:54
По принципу регулярных выражений
 preg_match('#<form[^>]+id="logout"#Usi',$data);
где
#<form[^>]+id="logout"#Usi
это регулярка, по которой находится тег form с id="logout" с флагами Usi - где U - выключаем жадность, s - игнорим пробелы, i- игнорируем регистр

В результате если в строке $data есть форма с id="logout" то preg_match вернет true, значит на странице есть форма с выходом. На вашем сайте все может быть гораздо иначе, но принцип тот же - ищем на странице то, что на ней нет до авторизации
0
Yurant
# Yurant 03.04.2013 15:55
Благодарю, Leroy. Просто пытаюсь по аналогии с данной статьей собрать парсер к сайту, однако не могу понять почему авторизация якобы не проходит... =/

т.е. если взять логин/пасс из кода и зайти под браузером, вбить поиск по артикулу, мало того что результаты будут отличаться так еще и вываливается сообщение о необходимости регистрации для получения актуальных данных.

Голову ломаю 2й день =/
0
Антон
# Антон 03.04.2013 16:02
function isAuth( $data )

{

return preg_match('#]+id="Authorization"#Usi',$data);

}

$ch = curl_init();

$url = 'http://www.autodoc.ru/';

curl_setopt($ch, CURLOPT_URL, $url ); // отправляем на

curl_setopt($ch, CURLOPT_HEADER, 0); // пустые заголовки

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возвратить то что вернул сервер

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // следовать за редиректами

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);// таймаут4

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)');

curl_setopt($ch, CURLOPT_COOKIEJAR, dirname(__FILE__).'/cookie.txt'); // сохранять куки в файл

curl_setopt($ch, CURLOPT_COOKIEFILE, dirname(__FILE__).'/cookie.txt');

curl_setopt($ch, CURLOPT_POST, 1); // использовать данные в post

curl_setopt($ch, CURLOPT_POSTFIELDS, array(

'returnUrl'=>'/',

'UserName'=>'MANGO-1344',

'RememberMe'=>'true',

'RememberMe'=>'false',

'Password'=>'QWEASDQWE',

));



isAuth($data = curl_exec($ch))?($Success=1):($Success=0);

if ($Success == 1)

{

curl_setopt($ch, CURLOPT_URL, 'http://www.autodoc.ru/Web/price/art/95659676?analog=on&access=2');

curl_setopt($ch, CURLOPT_HEADER, 0); // пустые заголовки

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возвратить то что вернул сервер

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // следовать за редиректами

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);// таймаут4

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)');

curl_setopt($ch, CURLOPT_COOKIEJAR, dirname(__FILE__).'/cookie.txt'); // сохранять куки в файл

curl_setopt($ch, CURLOPT_COOKIEFILE, dirname(__FILE__).'/cookie.txt');



$out = curl_exec($ch);

echo $out;

}

curl_close($ch);
0
Yurant
# Yurant 03.04.2013 16:07
Собственно вот сам код... В Google/.../network насколько понимаю только гет-запросы, при попытке отправить такой же гет-запрос, возвращает не совсем то.
0
Yurant
# Yurant 08.04.2013 16:20
Спасибо большое за статью, всё очень наглядно!)
0
matissko
# matissko 01.07.2013 11:31
Статья хорошая, я как новенький в этом деле узнал много полезного для себя)



Но однако у меня не получается пройти авторизацию mail.arenda-gold.ru

Делал вроде всё по статье, но не выходит, поможет кто?
0
Roman
# Roman 14.07.2013 16:45
Добрый день! А вы не пробовали с этого же сайта качать сами тендеры?))) там табличка с записями и есть пагинация! вот никак не могу ее победить! не хочет переходить по ней всегда на первой странице находиться(
0
Leroy
# Leroy 15.07.2013 03:05
статья написана в ознакомительных целях, ни в коем случае не претендует на руководство по парсенгу одного конкретного ресурса. Все совпадения с реальными сайтами чисто случайные.
0
strongest
# strongest 31.07.2013 22:51
Вот сайт на котором хочу авторизоваться. Судя по POST требует кроме логина и пароля еще и значение csrfmiddlewaretoken а он находится в скрытом div. Подскажите, как вытянуть значение csrfmiddlewaretoken из скрытого div ?



И заодно на сайте Сландо не понятно каким образом происходит авторизация.

Если не затруднит вас, подскажите как разобраться с этим?
+3
Иванbbbffffff
# Иванbbbffffff 23.02.2014 03:10
А можете скрипт автопостинга на авито на php написать? С подключением антигате...
0
weq
# weq 18.01.2015 23:16
Не надо спамить, нехороший вы человек.
-1
stdqin
# stdqin 11.03.2014 06:01
Сейчас 'login:j_id_id254.x' и 'login:j_id_id254.y' нет в коде страницы. Как тогда отправить cookies?
0
Оlеg
# Оlеg 28.08.2014 15:15
Вместо этого там теперь 'login:loginButton.x' и 'login:loginButton.y'.
0
Alex
# Alex 12.07.2014 18:17
интересует такой момент

//О том, что мы авторизовались будем судить по наличию формы logout
function isAuth( $data ){
return preg_match('#<form[^>]+id="logout"#Usi',$data);



у меня после авторизации нету формы, таблицами все выстроено, как правильно написать, что бы судить по наличию этого кода на странице, что авторизация успешна

<a href="/index.php?module=SYS_users&amp;func=logout" title="Выход пользователя из системы">Выход</a>
-1
Alex
# Alex 12.07.2014 18:20
'#<a[^>]+title="Выход пользователя из системы"#Usi'



так будет правильно?
0
ooo-palaris
# ooo-palaris 17.07.2014 21:08
Добрый день, спасибо большое за качественный и наглядный пошаговый пример.

Делаю по вашему образцу авторизацию на др. сайте, только одно поле меняется с name="rnd", его значение вытаскиваю при помощи регулярки.. вроде все правильно, а авторизоваться не получается.. не подскажите, что не так?



Вот код:

$url4 = 'http://www.palaris-nn.ru/shop/1559331/edit';

$ch = curl_init();

@curl_setopt($ch, CURLOPT_URL, $url4);

curl_setopt($ch, CURLOPT_FAILONERROR, 1);

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

curl_setopt($ch, CURLOPT_TIMEOUT, 3);

$resultnew = curl_exec($ch);

preg_match_all("/name=\"rnd\" value=\"(.*)\"/isU", $resultnew, $masnew);

$perem_rnd = $masnew[1][0];

$data = array ('user' => '***', 'password' => '***', 'rem' => '1', 'a' => '2', 'ajax' => '1', 'rnd' => $perem_rnd, '_tp_' => 'xml');

curl_setopt($ch, CURLOPT_HEADER, 0);

curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_POST, 1);

curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

curl_setopt ($ch, CURLOPT_COOKIEFILE, '/var/www/u38746/data/www/new.palaris-nn.ru/massur lphp/cooki.txt'); // Сюда будем записывать cookies, файл в той же папке, что и сам скрипт

curl_setopt ($ch, CURLOPT_COOKIEJAR, '/var/www/u38746/data/www/new.palaris-nn.ru/massur lphp/cooki.txt');

$html = curl_exec($ch);

echo $html;

curl_close($ch);
0
Василий
# Василий 02.09.2014 03:58
Здравствуйте. Не могли бы вы поделиться конечным исходником? Просто не очень понял после всяких замен и т.п. Буду очень благодарен! Заранее спасибо :)
-1
Радик
# Радик 26.11.2014 23:50
А как пройти двухфакторную аутентификацию с подтверждением номера через смс?



Встал в ступор просто.
0
Leroy
# Leroy 27.11.2014 10:32
вероятно надо найти какой-то сервис который будет принимать смс. Иначе никак
0
Настульчик
# Настульчик 12.12.2014 17:59
При отправке заполненной формы на движке ВордПресс плагин HttpFox к файерфоксу указал на необычный параметр с именем Y3JQMTEFTYCr со значением o0uX8RxQZA9I. Что это за имя необычное? Правильным ли будет его оформление в массиве как 'Y3JQMTEFTYCr' => 'o0uX8RxQZA9I'?
0
Leroy
# Leroy 13.12.2014 14:43
похоже на какую-то динамическую переменную, защита. Надо изучать и обходить.
-2
murzer
# murzer 14.12.2014 17:41
Пытаюсь авторизоваться по Вашей программе на одном сайте. Мне показывается, что данные отправляются GETом, а не POSTом. В чём может быть причина этого? И отправляемый заголовок Host не такой как я прописал в $url, а 127.0.0.1. Я с апачи на своём компе запускаю.