Немного расстроенный я решил утешиться написанием десктоп-приложения, которое должно помочь каждому пользователю интернета с выразить свою благодарность любимому сайту, например, сайту Роскомнадзора (за то, что он блюдёт законы и защищает нашу безопасность).
Ну а что может быть более приятным, чем массовые посещения твоего сайта?
Что у меня получилось смотрите под катом.
Я решил пойти предельно честным путём — имитировать Хабраэффект (Представляете, сколько радости ждёт кого-то?). Для начала создадим в Visual Studio пустой проект и в настройках проекта укажем его тип: Windows Application.
Наше приложение будет просто подгружать каждые 15-20 секунд случайную страницу с сайта и выбирать из неё ссылку для следующей загрузки. Если, скажем около ста тысяч человек пожелает отблагодарить Роскомнадзор, Хабраэффект неминуем. С мыслями о добром деле приступим к реализации.
Я старался описывать действия программы и поэтому часть статьи находится в комментариях к коду.
Всю основную работу будет выполнять экземпляр класса RandomBrowser с помощью нескольких внешних расширяющих методов класса String:
class RandomBrowser
{
private readonly WebClient Downoader = new WebClient();
private readonly Random Randomizer = new Random();
// Имя, стартовая страница
public readonly String DomainName;
public readonly String DomainPage;
// Выбранная ссылка для следующего запроса,
// свойство планируется в будущем использовать для логгирования
public String NextUrl { private set; get; }
// Метод осуществляет закачку страницы по ссылке NextUrl
public void Request()
{
try
{
// Скачиваем страницу и парсим из неё все ссылки
// Тут мы используем расширяющий метод String.GetHtmlLinks
List<String> links = Downoader.DownloadString(NextUrl).GetHtmlLinks(DomainName);
// Если есть ссылки, то выбираем случайную для следующего запроса,
// иначе снова выбираем стартовую страницу
NextUrl = links.Count > 0 ? links[Randomizer.Next(links.Count)] : DomainPage;
}
// В случае ошибки парсинга или загрузки страницы
// сбрасываем следующую ссылку до начальной страницы
catch (Exception)
{
NextUrl = DomainPage;
}
}
// Принимаем стартовую страницу
public RandomBrowser(String startPage)
{
// Устанавливаем имя домена и его стартовую страницу
// Тут мы используем расширяющий метод String.GetDomainName
DomainName = startPage?.GetDomainName();
DomainPage = @"http://www." + DomainName;
NextUrl = startPage;
}
}
Так как мы пишем приложение для как можно большего числа пользователей, то собирать его придётся под .NET Framework 4, так как этот вариант гарантированно запустится на большинстве машин с Windows 7, 8, 10. Поэтому для всех операций закачки придётся использовать класс WebClient.
А вот и наши расширяющие класс String методы:
static class Extensions
{
// Порядок префиксов важен
private static readonly String[] Prefixes = new String[] { "https://", "http://", "www." };
// Метод возвращает имя домена из строки
public static String GetDomainName(this String url)
{
foreach (String i in Prefixes)
{
if (url.IndexOf(i) == 0)
{
url = url.Remove(0, i.Length);
}
}
Int32 subdomain = url.IndexOf('/');
return subdomain == -1 ? url : url.Remove(subdomain);
}
// Метод парсит html-страницу в виде строки и возвращает все ссылки
// Принимает строку и доменное имя для фильтрации
public static List<String> GetHtmlLinks(this String page, String domainName = null)
{
// Тут я использую позаимствованную на просторах Хабра регулярку
List<String> result = new List<String>();
Regex reHref = new Regex(@"(?inx)
<a \s [^>]*
href \s* = \s*
(?<q> ['""] )
(?<url> [^""]+ )
\k<q>
[^>]* >");
foreach (Match i in reHref.Matches(page))
{
result.Add(i.Groups["url"].ToString());
}
// Если было установлено доменное имя для фильтрации ссылок, то отсеиваем все лишние
return domainName == null
? result
: new List<String>(result.Where(i => i.GetDomainName() == domainName));
}
}
И наконец, завершим создание нашего приложения, я назвал его Reward (награда в виде подобия Хабраэффекта), написанием точки входа:
class Program
{
static void Main()
{
// Думаю комментировать имена переменных излишне
const String appName = "Reward";
String appDirectory =
$@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\{appName}";
const String fileName = appName + ".exe";
String filePath = $@"{appDirectory}\{fileName}";
// Что бы пользователю было удобнее, запишем наше приложение в автозагрузку в реестр
RegistryKey autorun =
Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run\", true);
String regValue = autorun.GetValue(appName) as String;
// Если ключ реестра не найден
// или параметром ключа не является строка (из-за действия оператора as)
// или строка не является правильным путем
if (regValue == null || regValue != filePath)
{
// Значит приложение ещё не запускалось
// Выводим приветствие для первого раза:
MessageBox.Show("Теперь вы сможете поддерживать любимый сайт круглосуточно!", "Там-парарам");
// Проверяем существование директории для приложения
if (!File.Exists(filePath))
{
// И создаём её в случае необходимости
if (!Directory.Exists(appDirectory))
{
Directory.CreateDirectory(appDirectory);
}
// Проверяем содержание текущего пути до экземпляра
// в аргументах командной строки,
// если не находим,
// то используем предполагаемый путь по умолчанию.
// Затем, скопируем наше приложение в "AppData/Roaming",
// дабы исполняемый файл на рабочем столе не мозолил глаза
String[] args = Environment.GetCommandLineArgs();
File.Copy(
args.Length > 0 ? args[0] : $@"{Environment.CurrentDirectory}\{fileName}",
filePath);
}
// Прописываемся в реестре
autorun.SetValue(appName, filePath);
// И запускаем наш новый экземпляр из "AppData/Roaming"
Process.Start(filePath);
// Завершаем работу текущего экземпляра,
// теперь пользователь может его спокойно удалить
return;
}
// Собственно основной цикл работы приложения:
RandomBrowser browser = new RandomBrowser(@"http://www.ПримерСайтаДляБлагодарности.рф");
Random randomizer = new Random();
while (true)
{
// Для того что бы наше приложение вело себя более похожим образом
// на пользователя,
// и "кликало" по ссылкам через разные промежутки времени от 15 секунд,
// добавим элемент случайности
Thread.Sleep(TimeSpan.FromSeconds(15 + randomizer.Next(10)));
browser.Request();
}
}
}
Итак, у нас получилось незаметное в таскбаре, постоянно висящее в процессах и потребляющее на моем десктопе 3 мб оперативной памяти приложение. Его основные недостатки состоят в том, что для получения ощутимых результатов его должно использовать как можно большее количество людей, сложности распространения, и, возможно, проблемах с UAC.
Не зарабатываю на хлеб программированием, это скорее моё хобби под настроение в свободное время.
Жду шквала
Эта статья не является призывом идти и благодарить таким способом какие-нибудь сайты, а весь код был написан исключительно для развлечения.
Комментарии (31)
Suvitruf
01.02.2017 22:49+4Его основные недостатки состоят в том, что для получения ощутимых результатов его должно использовать как можно большее количество людей, сложности распространения, и, возможно, проблемах с UAC.
Ботнет прям.
dimaaan
01.02.2017 23:15Вместо консольного приложения под windows надо было сделать кроссплатформенный демон. Посмотрите в сторону Topshelf: Ссылка
Daniro_San
01.02.2017 23:16Это не консольное приложение, это Windows Application, т. е. окошко консоли даже выскакивать не будет
MonkAlex
01.02.2017 23:19+1Да ладно, обычного CLI хватило бы, который под mono легко заведется. Зачем лишние извращения?
ColdPhoenix
02.02.2017 00:10если выкинуть MessageBox поидее должен завестить и под Mono.
ChALkeRx
02.02.2017 01:23А реестр в Mono есть? Я давно не смотрел.
Обратите внимание, что это поделие на реестр завязано и прописывается в автозагрузку.
webirus
01.02.2017 23:20+8Честно, мне иногда кажется, что некоторым людям просто нечего делать. Хотя во вступлении так и написано. Но все же, пускайте свою энергию на какие-нибудь полезные вещи.
samodum
01.02.2017 23:57+10Детский сад какой-то. Тот же Cloudflare легко справится с этим DDoS (называйте уже вещи своими именами, а не каким-то там мистическим хабраэффектом)
Monoroch
02.02.2017 00:03+7DDoS'ить государственный сайт, который содержится за государственные деньги, которые идут с твоих налогов?
Нуу, дофига логично…Daniro_San
02.02.2017 00:13-3Налоги я плачу отнюдь не по своему желанию.
Тем более на проекты по контролю интернета.
И не мне решать куда пойдут мои деньги с налогов.
Но лично для меня это гос. учреждение ничего хорошего не сделало, кроме пакостей с блокированием безобидных торрентов.
kogot
02.02.2017 13:48+1Автор же ранее писал, что он школьник, следовательно налоги не платит, а только ест их по возможности. Карманные деньги, на которые можно было бы купить фильм с легальных торрентов потрачены на более важные вещи.
В целом молодец конечно, что попытался решить проблему своей головой. Но лучше твори добро, присесть ты всегда успеешь.Daniro_San
02.02.2017 13:56С тех пор прошло немало времени и я уже полгода работаю на благо общества, со всеми налогами и отчислениями)
kogot
02.02.2017 14:03Пардоньте. Ну тем более, не пристало сознательному гражданину ddos писать и призывать к этому почетных жителей хабратании(ст. 33 УК РФ) :)
Да и еще карму себе подпортил как хабравскую, так жизненную…
yarosroman
02.02.2017 01:49+7Обиделся, что не дали скачать пиратский контент? А дальше, что? Отморожу уши всем назло?
ahnyava
02.02.2017 04:56+1для тех же целей прекрасно подошёл бы jmeter или яндекс.танк. танк эффективнее ибо "пушка" на С)
MRomaV
02.02.2017 04:56так это простой DDoS, для которого существует много кросплатформенних аппликух
Gradarius
02.02.2017 09:24+1Понятно, что делать нечего. Понятно, что «Не зарабатываю на хлеб программированием». Но не ясно зачем статью на хабре делать под это добро, обычно такое пишется в стол сразу, то есть только для себя.
В целом молодец конечно, творить это хорошо, но показывать всем свои творения уж слишком рано.
ikbrain
02.02.2017 14:22Ждём новых статей от автора:
«Не дали выйти из магазина с неоплаченными покупками. Автоматизируем выбор продуктов, вставание в очередь, и потом отмену купленного, чтобы наказать кассира.»
«Не дали уехать на работу на машине соседей. Автоматизируем приём „постучать по колесу, чтобы сигналка заорала“»
«Не дали съесть еду, которую заказали люди с другого столика. Отблагодарим жмотов или как выбрать электронный испаритель»
alff31
Ну windows only, скрипт linux тоже не помешает