Пользователь
0,0
рейтинг
21 августа 2013 в 12:37

Разработка → Скрипт проверки наличия свободных дат в посольстве из песочницы

Предисловие:

В Беларуси стоит острая проблема с получением виз в Еврозону (т.е. Шенген). Все из-за того, что Польское посольство предоставляет так называемые мульти-визы за покупками (т.е. многократные). Регистрация производится на сайте посольства онлайн. Но вся проблема состоит в том, что свободных дат не словить. Единственный вариант — круглосуточно чекать страницу, и если появится дата — быстро «ловить» ее и заканчивать регистрацию. Т.к. свободного времени для круглосуточного чека нет, было принято решение об автоматизации данного процесса.
Сразу оговорюсь, что существуют различные скрипты, которые вылавливают свободные даты и за которые люди получают деньги. Мой скрипт не претендует на их место по быстроте, качеству и т.д. Данный скрипт был сделан только для себя, никакой коммерческой и иной выгоды я не преследовал.

Постановка задачи и входные данные:

Для начала необходимо было изучить то, как проходит процесс регистрации.
Линк на сайт посольства: by.e-konsulat.gov.pl
На главной странице видим два селекта, с выбором страны и города. Выбрав необходимые параметры нас редиректит на by.e-konsulat.gov.pl/Informacyjne/Placowka.aspx?IDPlacowki=94.
Потом выбираем из меню «Шенгенская виза — Зарегистрируйте бланк» и переходим на by.e-konsulat.gov.pl/Uslugi/RejestracjaTerminu.aspx?IDUSLUGI=8&IDPlacowki=94 — данный урл я и брал за входную точку, т.к. нет смысла в автоматизации предыдущих страниц (конечно, перед этим я проверил возможность входа по данному урлу с чистыми куками)
Далее мы видим капчу. Введя ее, нам дается результат — Отсутствие свободных дат.
Исходя из этих данных, мы можем сделать набросок плана нашего будущего скрипта:
image

Выбор инструмента

После того, как я определился с тем, что необходимо делать — стал вопрос о подходящем инструменте. Сразу хочу оговориться, я не являюсь программистом, я тестироващик. Но некоторые знания языков присутствуют.
В самом начале я хотел автоматизировать данный процесс на TestComplete. После автоматизации я столкнулся с некоторыми проблемами, основная из которых была скорость отработки скрипта, да и плюс ко всему я юзал старую версию тесткомплита 7.5, которая работает максимум с браузером Mozzila 3.5. Сами понимаете, что в таком старом браузере отображение элементов хромает, да и верстка местами едет. Поэтому на данный инструмент я забил и присмотрелся к Selenium WebDriver.
Языком написания скрипта был выбран Python. Выбор пал на него по одной только причине, я был немного знаком с данным скриптовым языком, а лезть в Java, например и изучать его не было ни времени, ни желания.

Работа с капчей

На самом деле автоматизировать данные действия не составляет особого труда, но все портит ненавистная капча. Вся проблема заключалась в том, что капчи с периодичность раз в один-два месяца менялись и поэтому не было смысла продумывать технологию разгадывания капчи (создания шаблонов, масок и т.д.). По этой причине я решил заюзать antigate.
Зарегистрировавшись там и закинув 3 доллара, я получил ресурсов на 3000 капч.
Но теперь необходимо было продумать алгоритм обработки данной капчи, отправки ее на антигейт и получения значения капчи. Выглядело это примерно так:
image
Для работы с антигейтом я использовал API данного сервиса. Пришлось развернуть на локальной машине PHP server, не заморачиваясь выбор пал на Denwer. Создал локальный сайт test1.ru и закинул туда php страницу для работы с API сервиса.
Листинг данной страницы
<?php
function recognize(
    $filename,
    $apikey,
    $is_verbose = true,
    $sendhost = "antigate.com",
    $rtimeout = 10,
    $is_phrase = 0,
    $is_regsense = 1,
    $is_numeric = 0,
    $min_len = 4,
    $max_len = 4,
    $is_russian = 1)
{
    if (!file_exists($filename))
    {
        if ($is_verbose) echo "<b>file $filename not found</b>";
        return false;
    }
    $fp=fopen($filename,"r");
    if ($fp!=false)
    {
        $body="";
        while (!feof($fp)) $body.=fgets($fp,1024);
        fclose($fp);
        $ext=strtolower(substr($filename,strpos($filename,".")+1));
    }
    else
    {
        if ($is_verbose) echo "<b>could not read file $filename<b>";
        return false;
    }

    if ($ext=="jpg") $conttype="image/pjpeg";
    if ($ext=="gif") $conttype="image/gif";
    if ($ext=="png") $conttype="image/png";


    $boundary="---------FGf4Fh3fdjGQ148fdh";

    $content="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"method\"\r\n";
    $content.="\r\n";
    $content.="post\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"key\"\r\n";
    $content.="\r\n";
    $content.="$apikey\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"phrase\"\r\n";
    $content.="\r\n";
    $content.="$is_phrase\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"regsense\"\r\n";
    $content.="\r\n";
    $content.="$is_regsense\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"numeric\"\r\n";
    $content.="\r\n";
    $content.="$is_numeric\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"min_len\"\r\n";
    $content.="\r\n";
    $content.="$min_len\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"max_len\"\r\n";
    $content.="\r\n";
    $content.="$max_len\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"is_russian\"\r\n";
    $content.="\r\n";
    $content.="$is_russian\r\n";
    $content.="--$boundary\r\n";
    $content.="Content-Disposition: form-data; name=\"file\"; filename=\"capcha.$ext\"\r\n";
    $content.="Content-Type: $conttype\r\n";
    $content.="\r\n";
    $content.=$body."\r\n";
    $content.="--$boundary--";


    $poststr="POST http://$sendhost/in.php HTTP/1.0\r\n";
    $poststr.="Content-Type: multipart/form-data; boundary=$boundary\r\n";
    $poststr.="Host: $sendhost\r\n";
    $poststr.="Content-Length: ".strlen($content)."\r\n\r\n";
    $poststr.=$content;


    $fp=fsockopen($sendhost,80,$errno,$errstr,30);
    if ($fp!=false)
    {
        fputs($fp,$poststr);
        $resp="";
        while (!feof($fp)) $resp.=fgets($fp,1024);
        fclose($fp);
        $result=substr($resp,strpos($resp,"\r\n\r\n")+4);
    }
    else
    {
        if ($is_verbose) echo "<b>could not connect to anti-captcha</b>";
        if ($is_verbose) echo "<b>socket error: $errno ( $errstr )</b>";
        return false;
    }

    if (strpos($result, "ERROR")!==false or strpos($result, "<HTML>")!==false)
    {
        if ($is_verbose) echo "<b>server returned error: $result</b>";
        return false;
    }
    else
    {
        $ex = explode("|", $result);
        $captcha_id = $ex[1];
        if ($is_verbose) echo "<b>$captcha_id</b>";
    }
}

$text=recognize("captcha.png","Здесь должен быть ключ для работы с сервисом",true,"antigate.com");
?>

Я не стал досконально разбираться, что к чему, но единственное, что я выставил — это следующие настройки:
    $is_phrase = 0, //является ли ваша капча фразой
    $is_regsense = 1, //регистро зависимая или нет?
    $is_numeric = 0, //Состоит из цифр?
    $min_len = 4, //минимальная длинна
    $max_len = 4, //максимальная длинна
    $is_russian = 1 //есть ли русские символы

В итоге нам необходимо поместить изображение captcha.png в директорию, где находится index.php и перейти по урлу test1.ru
В итоге капча полетит на сервис, когда она разгадается нам придет ее id, обрамленный в тег b, либо придет какая-нибудь ошибка, которая отобразиться.
Останется дело за малым, только забрать значение капчи со страницы по ее id.

Создание скрипта

Т.к. все предварительные подготовки сделаны, то можем приступать непосредственно к написанию скрипта.
Работать мы будем с двумя открытыми окнами Firefox. Т.к. в одном окне у нас будет происходить чек дат, а во втором все работы относительно капчи. Для отображения капчи в новом окне, мы просто будем находить сам элемент на странице по id и считывать урл текущей капчи. При обращении на данный урл, мы получим только изображение капчи, без лишних элементов.
image

Теперь листинг скрипта, с комментариями:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
import time

driver = webdriver.Firefox() #запускаем первое окно (основное)
add_driver = webdriver.Firefox() #запускаем дополнительное окно для работы с капчей
driver.get("https://by.e-konsulat.gov.pl/Uslugi/RejestracjaTerminu.aspx?IDUSLUGI=8&IDPlacowki=94") #переходим на наш урл
captcha_url = driver.find_element_by_id('c_uslugi_rejestracjaterminu_ctl00_cp_botdetectcaptcha_CaptchaImage').get_attribute('src') #Находим элемент капчи по его id и считываем урл, по которому будет доступно изображение

add_driver.get(captcha_url) #во втором окошке открываем нашу капчу
add_driver.set_window_size(50,200) #делаем ресайз окна браузера, чтобы сделать скриншот именно капчи, без лишних серых полей
add_driver.get_screenshot_as_file('captcha.png') #делаем скриншот окна, в итоге на нашем скриншоте будет только капча и сохраняем его в директорию локального сайта test1.ru, т.к. у меня скрипт лежит тамже, то путь не писал
add_driver.get(http://test1.ru) #переходим на урл нашей странички, для работы с антигейтом
captcha_id = add_driver.find_element_by_xpatch('//b') #находим элемент, который обрамлен в тег b, подразумевая ,что там хранится значение id капчи
count = false
while (count == false)
    add_driver.get('http://antigate.com/res.php?key=Ключ для работы с антигейтом&action=get&id=" + captcha_id)
    captcha_complete = add_driver.find_element_by_xpatch('//pre').text # находим наше значение (на антигейте оно обрамлено в тег pre)
    if (captcha_complete.find('ERROR') >= 0) #проверяем, выскочила ли ошибка
        time.sleep(5) #спим 5 секунд
    else
        count = true #выходим из цикла проверки
# теперь значение нашей капчи содержится в переменной  captcha_complete, его и вводим в инпут

driver.find_element_by_id('ctl00_cp_BotDetectCaptchaCodeTextBox').send_keys(captcha_complete) #находим наш инпут и вводим значение капчи
driver.find_element_by_id('ctl00_cp_btnDalej').click() #находим кнопку далее и кликаем на нее
result = driver.find_element_by_id('ctl00_cp_lblBrakTerminow').text
if (result.find('Отсутствие') >= 0)
    print('Нет даты')
else
    print('Дата есть')


Будущие улучшения

Основа готова, наш скрипт переходит на страницу, получает капчу, распознает ее через сервис распознавания, вводит капчу, кликает далее и проверяет наличие даты. Для себя я сделал следующее — загнал все это действие в цикл while (true) и чекал сайт, пока не словилась дата (также я добавил отправку письма на мыло, в случае положительного результата). Доработок по скрипту конечно же можно произвести много, например:
1) поставить проверку на ошибки и исходя из ошибок предпринимать различные действия
2) поставить проверку на неправильную капчу и отправку репорта на антигейт (пожаловаться на плохого работника)
3) дописать авторегистратор, а не просто чекер даты
и т.д.

Послесловие

Еще раз хочу оговориться, что данный скрипт слабоват, но результат от него был. Также стоит заметить, что в посольстве далеко не дураки сидят и часто меняют капчу, поэтому необходимо будет переписывать скрипт под новые условия.
Олег Коледа @dgu_minsk
карма
7,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (22)

  • +4
    Лучше бы сотрудники посольства напряглись и обслужили всех желающих. :-(
  • 0
    В польском посольстве в Минске некто автоматически расхватывают места, и потом продают их втридорога dengi.onliner.by/2013/08/08/polskoe-konsulstvo
  • 0
    Вопрос почему националка, а не шенген? :)
    • 0
      Да, Вы правы, прошу прощения. Когда писал пост не ту ссылку заюзал. Но для регистрации шенгена поменяется только урл ссылки, остальной алгоритм такой же. Сейчас поправлю
  • 0
    А когда был результат? В этом году вроде бы проблема была не с быстрым расхватом всех свободных дат авторегистраторами, а блокировка сайта посольства белтелекомом во время выбрасывания новых дат.
    • 0
      Результат был в начале лета, точную дату не скажу. Проблемы с доступом к сайту были, но скрипт запускался с не беларуского «облачного сервера»
  • 0
    Не пытались получить капчу как-нибудь почище, чем скриншотом?
    • 0
      Делалось все на скорую руку. Данный метод — первое, что пришло в голову
  • –1
    На мой взгляд неразумно выкладывать подобные вещи в открытый доступ. Тот, кому очень надо и умеет — сделает сам. Если же число пользующихся «случайных» лиц станет чрезмерным — кислород перекроют. Капчу там какую прикрутят злую и т.п. Я подобное делал для записи ребенка в поликлинику ну и еще для пары вещей, которые не хотел бы оглашать.
    • +1
      таким же образом пишется любой другой нехороший софт: чекеры, парсеры, регеры, накрутчики…
      тем более испытания проводились на сайте посольства…
    • +1
      Есть две мысли на этот счет.
      Во-первых, для совершенно случайных лиц даже запустить эти скрипты будет проблематично.
      Во-вторых, а есть ли что-то плохое в том, что система может стать менее доступной для ботов?
      По-моему, кардинально против могут быть только те, кто занимается этим в промышленных масштабах и имеет с этого деньги (нет, я Вас не обвиняю, это исключительно мои рассуждения для общего случая). А если качественно отсечь ботов, то одну-две-три анкеты для своей семьи зарегистрировать будет не так уж и трудно, разве нет?
      • 0
        Если система уже оккупирована ботами, то это как раз повод кислород перекрыть, поскольку основная функция все равно не выполняется. Ну типа «запись по паспортным данным» или еще как. Я исходил из предположения, что ресурс просто пользуется большой популярностью у добронамеренных пользователей.
  • +2
    Использование этого скрипта начиная с августа в 99% случаев будет приводить к блокировке по IP. В самом деле, если всё было бы настолько просто, люди бы не висели по полгода в очередях на регистрацию.

    Большинство изменений, вносимых в процесс регистрации, запускаются в продакшн за 10-15 минут до начала реги. В этот раз была звуковая капча, например. Три ошибочных капчи — пермобан. Поэтому, как и ожидалось, результат у регистраторов был нулевой.

    Что же касается простых смертных — до июля включительно Белтелеком, как единственный магистрал для физиков в нашей стране, блокировал весь трафик из AS6697 на TCP\443 для в подсетки польского МИДа в момент регистрации. Исключительный доступ имели пользователи AS21274, которые имели пиринг с Польшей (AS8501) в обход Белтелекома.

    Данная блокировка была обнаружена мною при помощи простой тулзы tcptraceroute, и опубликована на пастебине. pastebin.com/8P98tMC8
    После того, как эта информация распространилась — блокировка была снята, и больше мною не наблюдалась. Поэтому с июля 2013 года практически любой человек может зарегистрироваться самостоятельно, без использования скриптов.
  • 0
    Надо заметить, что у Польского посольства в Украине тоже препоршивейший сайт. И да, мне тоже во Львове предлогали такую услугу за 50$, поскольку свободных дат нет на три месяца вперед. Это очень печалит, что у таких сайтов все так плохо с безопастностью.
    • 0
      ну, у вас 50$, у нас (Брест) по стольнику просят :) Зимой по 200-250 было)
  • 0
    >закинув 3 доллара, я получил ресурсов на 3000 капч

    Не совсем так. На антигейте довольно-таки плавающая цена, зависящая от нагруженности сервиса.
    Фактически получается стоимость 1,5-2 доллара за тысячу, таким образом 3 доллара хватит на 1000-2000 капч, но никак не на 3000!
    Есть же другой сервис со стабильной ценой в 1$ за 1000 капч — это pixodrom.com вот там уже не получится уйти в минус
    • 0
      Наверное разные антигейты юзаем. Вот например текущий скриншот с моего аккаунта image
      Исходя из этих цифр, делался вывод о стоимости 1 доллар за 1000.
      Насчет того, что ценник плавающий, я в курсе, но я считал, что он может плавать только ниже 1 доллара, при, скажем, большой активности аккаунта (т.е. так сказать скидки антигейт раздает)
      • 0
        Согласен с предыдущим автором — антигейт часто завышает ставку — достаточно посмотреть их статистику на главной странице.

        Вот моя выписка:

        капч за последние 24 часа 792
        денег потрачено за последние 24 часа $0.93
        капч сегодня 701
        денег потрачено сегодня $0.803

        А вы попали в редкие моменты, когда ставка и в самом деле может быть 1$ за тысячу, но это бывает редко и В СРЕДНЕМ(!) капча выходит в два раз дороже.
        Проверено на практике.
      • 0
        Да, действительно, наверное разные:
        853 капч => $1.376
        813 капч => $1.327
        Получается в среднем $1.6 за 1000 капч.

        habrastorage.org/storage3/92f/dd3/96a/92fdd396a812c279f21c196f001bcc9a.png

        Так зачем платить больше, если есть более дешёвые альтернативы?

        • 0
          На самом деле, использовал антигейт, как первое попавшееся средство. Спасибо за наводку на альтернативу.
  • 0
    Жду продолжения ) Но вообще в последне время даже у «профи» регистраций на сайте даже за деньги перестало что-то получаться. То даты з 6 минут разбирают, то все айпишники польские заблочены, то еще что-то.
  • 0
    Скажите, вы уже сделали авторегистратор?

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.