Урок 5 – продвинутый регер rambler.ru.

Урок 5 – продвинутый регер rambler.ru.

На этот раз мы будем учиться на примере более серьезной программы, которую, например, можно продать и на полученные деньги пойти купить себе сникерс :). Это будет усовершенствованный регер почты rambler.ru, быстрый, многопоточный, с поддержкой антигейта и всех видов проксей. Программа эта более длинная чем предыдущие, поэтому я не буду объяснять как работает весь исходник, а расскажу только про важные части. Остальное в основном связано с работой интерфейса и можно понять просто глядя на код.

Прокси

При работе с прокси-серверами нужно привыкнуть к тому, что при запросах может возникать куча ошибок. Например, многие прокси, когда у них запрашиваешь сайт, скажем www.ya.ru, выдают вместо него какую-то левую страницу типа «добро пожаловать на наш офигенный прокси». Естественно программа ничего не поймет в этом ответе. При этом зачастую на следующий запрос прокси отвечает нормально. Также часто бывает что прокси поддерживает GET-запросы, но не поддерживает POST. Самая частая ситуация, это когда прокси просто забивает на то, что его попросили скачать какую-то страницу, и программа просто зря ждет надеясь получить ответ. Кстати, для настройки, сколько времени ждать ответа от сервера используйте параметр VkRequest.Timeout.

Начнем с того, что напишем свой класс прокси, чтобы можно было учитывать количество ошибок в процессе работы программы и эффективно отсеивать нерабочие сервера.

class MyProxy : Proxy{public const int StartErrors = 3;public const int MaxErrors = 5; public int ErrorsCount { get; set; } // эти 2 конструктора просто повторяют конструкторы родительского классаpublic MyProxy(string addressAndPort, ProxyTypes type): base(addressAndPort, type){ErrorsCount = StartErrors;} public MyProxy(string address, int port, ProxyTypes type, string login = null, string password = null): base(address, port, type, login, password){ErrorsCount = StartErrors;}}

Этот класс наследуется от класса Proxy, поэтому умеет все то же самое, что и основной класс + еще пару мелочей. У него появился параметр ErrorsCount, с помощью которого мы будем отслеживать, сколько ошибок подряд произошло при использовании данного прокси. Если их произошло больше 5 подряд прокси можно выкинуть. При этом если через прокси удалось успешно зарегистрировать аккаунт, будем скидывать счетчик на 0 — может быть получится еще один зарегистрировать. Чтобы отфильтровать совсем нерабочие прокси сразу, будем изначально устанавливать счетчик ошибок на 3. То есть, если мы взяли новый прокси, и он выдает 2 ошибки подряд, то выкинем его.

Еще одна немаловажная деталь о прокси-серверах: они как правило очень медленные. Поэтому нужно позаботиться о том, чтобы через них проходило как можно меньше трафика. Если можно сделать какой-то запрос мимо прокси-сервера, нужно так и делать. Помните мы в первой версии регера вытаскивали uniq_id из страницы регистрации? При этом нашли мы его в 3-х местах, и одно из этих мест — это куки rrc, которое выдает нам страница регистрации. А помните в прошлом уроке я рассказывал про метод HEAD? Так вот, мы можем не качать всю форму регистрации, а только попросить ее заголовки:

CookieCollection cook = new CookieCollection();// более подробно о том, как использоать куки я объясню в следующем урокеVkRequest.Request("http://id.rambler.ru/script/newuser.cgi", cookies: cook, method: "HEAD");string id = cook["rrc"];

Таким образом мы сэкономим довольно много прокси-трафика. Страница регистрации весит 30кб, в сжатом виде (движок делает это автоматически) 9кб, одни заголовки — <1кб. Получается экономия почти в 10 раз.

Дальше у нас идет скачивание капчи. Для большинства серверов (почти для всех) неважно качаете вы капчу через прокси или со своего компа. При этом скачать ее без прокси гораздо быстрее и сильно понижает вероятность ошибок, связанных с прокси (он должен успешно выполнить 2 запроса подряд вместо 3-х). Так что при скачивании капчи прокси использовать ненужно.
Благодаря этим оптимизациям, для прокси вместо 3-х запросов на 15кб данных (9кб форма регистрации, 5кб капча, 1кб POST) получается всего 2 запроса по 1кб каждый (даже меньше). К тому же мы в 2 раза уменьшили общий трафик, убрав лишние 8кб для формы регистрации.

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

Дальше у нас идет POST запрос на регистрацию. Поскольку определенный процент проксей не поддерживает POST запросы, желательно пытаться преобразовать их в GET с параметрами:

VkRequest.Request("http://id.rambler.ru/script/newuser.cgi", post);VkRequest.Request("http://id.rambler.ru/script/newuser.cgi?" + post);

Вы наверное часто видели в адресной строке браузера, что после адреса стоит знак «?» и после него идут параметры, такие же как и в POST запросах. Некоторые сервера не различают параметры переданные этими двумя способами (например vkontakte.ru), поэтому следует попробовать преобразовать POST запрос в GET и посмотреть, будет ли так работать. Если получится, то мы сможем более эффективно использовать прокси серверы. Оказывается, что для rambler.ru GET вместо POST не подходит, поэтому оставим эту строку как есть.

Antigate

Теперь о том, как пользоваться антигейтом. Все очень просто, устанавливаете переменную в VkRequest.AntigateKey ваш ключ антикапчи, и разгадываете капчу от так:

string captchaAnswer = VkRequest.PostCaptcha(captchaImage);

Эта функция подождет пока антигейт разгадает капчу и вернет результат разгадывания. Почти так же как и CaptchaWindow.

Комментарии по исходнику

Теперь как в прошлом уроке выделяем процедуру регистрации в отдельную функцию:

private void Register(){MyProxy p = null;try{// выбираем случайный проксиlock (proxies)if (proxies.Count == 0) { manager.StopJob("Готово!"); return; }else p = proxies[r.Next(proxies.Count)]; // генерируем случайные мыло и парольstring email = Path.GetRandomFileName().Replace(".", "");string pass = Path.GetRandomFileName().Replace(".", ""); // получаем уникальный id регистрацииCookieCollection cook = new CookieCollection();VkRequest.Request("http://id.rambler.ru/script/newuser.cgi", proxy: p, cookies: cook, method: "HEAD");string id = cook["rrc"];if (id == null) throw new Exception("Неверная страница регистрации"); // скачиваем и разгадыаем капчуImage captchaImage = VkRequest.Request("http://id.rambler.ru/captcha/" + id + ".jpg").GetImage();string captchaAnswer = VkRequest.PostCaptcha(captchaImage); // регистрируемся в почтеstring post = string.Format("uniq_id={0}&user.login={1}&user.captcha={3}&user.password1={2}&user.password2={2}&skin=id&back=&back_immediate=&action=register&user.fname=firstname&user.lname=lastname&user.gender=1&user.bday=1&user.bmonth=1&user.byear=1950&user.domain=rambler.ru&x.emailfree=mail1245%40rambler.ru&user.question=own.question&user.own_question=question&user.answer=answer&user.email2=",id, email, pass, captchaAnswer);var result = VkRequest.Request("http://id.rambler.ru/script/newuser.cgi", post, proxy: p); // обработка возможных ошибок регистрации}catch (Exception e){// опять обработка ошибок}}

и создаем для нее JobManager:

manager = new JobManager(Register);manager.PreferredThreadCount = (int)threads.Value;manager.Start();

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

  • Если вы хотите взаимодействовать с интерфейсом из рабочего потока (функции Register()), то вам придется использовать метод BeginInvoke, который поставит вашу функцию в очередь на выполнение для потока интерфейса (только он может изменить что-то в окне): private void log(string s){BeginInvoke(new Action(() => { logBox.AppendText(s + "\r\n"); }));} Здесь использоано lambda-выражение () => { ... }, если хотите узнать о них подробнее, читайте гугл.
  • У вас наверное бывало так, что при возникновении ошибки программа выдала сообщение о ней и сразу закрылась, хотя ошибка была незначительная? Чтобы иметь возможность продолжить работу, можно просто добавить в конструктор формы следующюю строку Application.ThreadException += (obj, e) => ExceptionDialog.Show(e.Exception);
  • В программе, которую я написал зарегистрированные аккаунты сразу же записываются в файл. Чтобы не обращаться к файлу слишком часто, реализован следующий механизм:
    • все зарегистрированные акки заносятся в список akksToWrite
    • таймер каждую секунду проверяет, есть ли что-то в списке, и если есть дописывает акки в файл и чистит список
    Таким образом получается, что все акки сохраняются и нет большой нагрузки на жесткий диск
  • Количество потоков можно менять прямо в процессе работы.

На сегодня все. Дальше изучайте исходник программы: RamblerReger.v2.0. Если что-то непонятно, задавайте вопросы в комментариях. Также интересны ваши комментарии по поводу понятности изложения. Возможно стоит больше внимания уделить более простым урокам?

Comments are closed.