C# клик по случайному элементу в пределах видимой области

orka13

Client
Регистрация
07.05.2015
Сообщения
2 040
Благодарностей
2 065
Баллы
113
Часто это постоянно поднимают на форуме. Вроде задание на 1 сниппет, но есть свои подводные камни. Здесь в коде максимально напичкано выводов в лог и комментирования чтобы можно было понять как в зенке формируется «видимая область». К конкурсам тема не относится, просто в раздел "Внеконкурсные статьи" вроде подобные мини-мануалы сбрасывают.

Я не гуру C#, и часть костылей в коде может надо по-другому делать. За основу бралась полноценная конкурсная статья от LaGir:
Сниппеты эмуляции мыши: FullEmulationMouse
Если накосячил, то указывайте что исправить.
JS-кубики надо обязательно отдельно выполнять перед каждым запуском рабочих C#-кубиков, интегрировать их в C# не рекомендую. А то будет беда.
Если элемент хоть немного выходить краями за пределы задаваемой области, то по нему не кликнет, так как в расчётах учитывается вся площадь элемента, а не его одна точка. Наглядно это видно на видео и скрине (сопоставьте из лога список подходящих элементов с теми, что на странице). В лог выводятся подходящие элементы, чтобы потом не было вопросов почему по этому кликает, а по этому нет…
Вот код основных кубиков (весь шаблон прикреплен в конце топика):
#4 JS window.innerWidth - обязательно перед C# выполнять!:
JavaScript:
return window.innerWidth;
#5 JS window.innerHeight - обязательно перед C# выполнять!:
JavaScript:
return window.innerHeight;
#6 Задаем свои параметры:
C#:
//Делаем отступы в пикселях от краёв видимой части страницы чтобы не кликать по элементам, близко расположенным к краю:
project.Variables["margin_left"].Value = "50"; // отступ от левого края
project.Variables["margin_top"].Value = "50"; // отступ сверху
project.Variables["margin_right"].Value = "150"; // отступ от правого края
project.Variables["margin_bottom"].Value = "220"; // отступ снизу
//Задаем минимальную ширину и высоту интересующего нас элемента в пикселях (у невидимых элементов это обычно "0", значит пропишем хотя бы "1"):
project.Variables["Width_Min"].Value = "1";
project.Variables["Height_Min"].Value = "1";
//Задаем максимальную ширину и высоту элемента в пикселях (ну, вдруг вы не захотите кликать по крупным баннерам и т.д., а пока "9999" равносильно "игнорированию" этой опции):
project.Variables["Width_Max"].Value = "9999";
project.Variables["Height_Max"].Value = "9999";
#7 просто в лог выводим что нашли (можно убрать):
C#:
// получаем документ из вкладки:
var tab = instance.ActiveTab;

//Высота и ширина главного документа страницы (https://zennolab.com/discussion/threads/navigacija-bota-na-web-stranicax.48679/#post-364240)
//Они, как правило - нижняя и правая конечные точки инстанса
int MainDocument_Width = tab.MainDocument.Width;
int MainDocument_Height = tab.MainDocument.Height;

int window_Width = Convert.ToInt32(project.Variables["windowinnerWidth"].Value); //парсим высоту видимого окна браузера из переменой JS.
int window_Height = Convert.ToInt32(project.Variables["windowinnerHeigth"].Value); //парсим ширину видимого окна браузера из переменой JS.

project.SendInfoToLog("Ширина и высота всего окна браузера в пикселях = " + MainDocument_Width.ToString() + "x" + MainDocument_Height.ToString(), true); // выводим в лог
project.SendInfoToLog("Ширина и высота видимого окна браузера из переменных JS = " + window_Width.ToString() + "x" + window_Height.ToString(), true); // выводим в лог

//Делаем отступы в пикселях от краёв видимой части страницы чтобы не кликать по элементам, близко расположенным к краю:
int margin_left = Int32.Parse(project.Variables["margin_left"].Value); // отступ от левого края
int margin_top = Int32.Parse(project.Variables["margin_top"].Value); // отступ сверху
int margin_right = Int32.Parse(project.Variables["margin_right"].Value); // отступ от правого края
int margin_bottom = Int32.Parse(project.Variables["margin_bottom"].Value); // отступ снизу

//Задаем минимальную ширину и высоту элемента в пикселях (у невидимых элементов это обычно "0", значит пропишем хотя бы "1"):
int Width_Min = Int32.Parse(project.Variables["Width_Min"].Value);
int Height_Min = Int32.Parse(project.Variables["Height_Min"].Value);
//Задаем максимальную ширину и высоту элемента в пикселях (ну, вдруг вы не захотите кликать по крупным баннерам и т.д., а пока "9999" равносильно "игнорированию" этой опции):
int Width_Max = Int32.Parse(project.Variables["Width_Max"].Value);
int Height_Max = Int32.Parse(project.Variables["Height_Max"].Value);

//Находим элементы (банально все ссылки по xPath):
HtmlElementCollection heCol  = tab.FindElementsByXPath("//a"); // все ссылки
project.SendInfoToLog("Столько элементов нашли по Xpath на всей странице: " + heCol.Count.ToString(), true); // выводим в лог
project.SendInfoToLog("Вот такой элемент полностью в зоне видимости окна с учетом полей:", true); // выводим в лог
project.SendInfoToLog("(Номер, Координаты начала элемента в видимом окне (x,y), конца, ширина, высота, текст, тег)", true); // выводим в лог
for (int i = 0; i < heCol.Count; i++) {  
    HtmlElement el = heCol.GetByNumber(i);  
    //Координаты начала элемента (его верхний левый угол) в видимом окне:
    int elX_1 = el.DisplacementInTabWindow.X;
    int elY_1 = el.DisplacementInTabWindow.Y;
    //Ширина и высота элемента:
    int elWidth = el.Width;
    int elHeight = el.Height;
    //Координаты конца элемента (его нижний правый угол) в видимом окне:
    int elX_2 = elX_1 + elWidth;
    int elY_2 = elY_1 + elHeight;
//Проверяем проходит ли наш элемент сразу по всем условиям:  
    if (
        elX_1 >= margin_left && // отступ слева
        elY_1 >= margin_top && // отступ сверху
        elX_2 <= window_Width-margin_right &&  // отступ справа
        elY_2 <= window_Height-margin_bottom && // отступ снизу
        elWidth >= Width_Min && // минимальная ширина
        elHeight >= Height_Min && // минимальная высота
        elWidth <= Width_Max && // максимальная ширина
        elHeight <= Height_Max // максимальная высота
        ) {
            string InnerText = el.InnerText;
            string FullTagName = el.FullTagName;
            project.SendInfoToLog("#"+ i.ToString() + ", " + elX_1.ToString() + ":" + elY_1.ToString() + ", " + elX_2.ToString() + ":" + elY_2.ToString() + ", " + elWidth.ToString() + ", " + elHeight.ToString() + ", " + InnerText + ", " + FullTagName, true); // выводим в лог
        }
}
project.SendInfoToLog("Для наглядности рисуем курсором границы зоны поиска, учитывая наши поля-отступы:", true); // выводим в лог
HtmlElement el_0  = tab.FindElementByXPath("//*", 0); //ищем нулевой тег вверху слева страницы
int el_0X_1 = el_0.DisplacementInTabWindow.X;
int el_0Y_1 = el_0.DisplacementInTabWindow.Y;
project.SendInfoToLog("На столько пикселей мы видимой областью отдалились от начала страница (x,y от нулевого тега вверху слева страницы): " + el_0X_1.ToString() + ", " +el_0Y_1.ToString(), true); // выводим в лог
project.SendInfoToLog("учитываем это при составлении координат нашей зоны", true); // выводим в лог

//Ведем к 1 точке прямоугольника:
instance.ActiveTab.FullEmulationMouseMove(-el_0X_1 + margin_left, -el_0Y_1 + margin_top);
System.Threading.Thread.Sleep(2 * 1000); // пауза 2 сек.
//Ведем к 2 точке прямоугольника:
instance.ActiveTab.FullEmulationMouseMove(-el_0X_1 + window_Width - margin_right, -el_0Y_1 + margin_top);
System.Threading.Thread.Sleep(2 * 1000); // пауза 2 сек.
//Ведем к 3 точке прямоугольника:
instance.ActiveTab.FullEmulationMouseMove(-el_0X_1 + window_Width - margin_right, -el_0Y_1 + window_Height - margin_bottom);
System.Threading.Thread.Sleep(2 * 1000); // пауза 2 сек.
//Ведем к 4 точке прямоугольника:
instance.ActiveTab.FullEmulationMouseMove(-el_0X_1 + margin_left, -el_0Y_1 + window_Height - margin_bottom);
System.Threading.Thread.Sleep(2 * 1000); // пауза 2 сек.
//Ведем к 1 точке прямоугольника обратно:
instance.ActiveTab.FullEmulationMouseMove(-el_0X_1 + margin_left, -el_0Y_1 + margin_top);
System.Threading.Thread.Sleep(2 * 1000); // пауза 2 сек.
#8 кликаем на рандомный элемент:
C#:
// получаем документ из вкладки:
var tab = instance.ActiveTab;

int window_Width = Convert.ToInt32(project.Variables["windowinnerWidth"].Value); //парсим высоту видимого окна браузера из переменой JS.
int window_Height = Convert.ToInt32(project.Variables["windowinnerHeigth"].Value); //парсим ширину видимого окна браузера из переменой JS.

//Делаем отступы в пикселях от краёв видимой части страницы чтобы не кликать по элементам, близко расположенным к краю:
int margin_left = Int32.Parse(project.Variables["margin_left"].Value); // отступ от левого края
int margin_top = Int32.Parse(project.Variables["margin_top"].Value); // отступ сверху
int margin_right = Int32.Parse(project.Variables["margin_right"].Value); // отступ от правого края
int margin_bottom = Int32.Parse(project.Variables["margin_bottom"].Value); // отступ снизу

//Задаем минимальную ширину и высоту элемента в пикселях (у невидимых элементов это обычно "0", значит пропишем хотя бы "1"):
int Width_Min = Int32.Parse(project.Variables["Width_Min"].Value);
int Height_Min = Int32.Parse(project.Variables["Height_Min"].Value);
//Задаем максимальную ширину и высоту элемента в пикселях (ну, вдруг вы не захотите кликать по крупным баннерам и т.д., а пока "9999" равносильно "игнорированию" этой опции):
int Width_Max = Int32.Parse(project.Variables["Width_Max"].Value);
int Height_Max = Int32.Parse(project.Variables["Height_Max"].Value);

//Находим элементы (банально все ссылки по xPath):
HtmlElementCollection heCol  = tab.FindElementsByXPath("//a"); // все ссылки
project.SendInfoToLog("Столько элементов нашли по Xpath на всей странице: " + heCol.Count.ToString(), true); // выводим в лог

//heCol.Shuffle(); // обычное перемешивание не проканало, будем городить костылями:
List <string> Indexes = new List <string>();
for (int i = heCol.Count-1; i >= 0 ; i--) {  
    int c = Global.Classes.rnd.Next(0, heCol.Count());
    HtmlElement el = heCol.ElementAt(c);
    //Координаты начала элемента (его верхний левый угол) в видимом окне:
    int elX_1 = el.DisplacementInTabWindow.X;
    int elY_1 = el.DisplacementInTabWindow.Y;
    //Ширина и высота элемента:
    int elWidth = el.Width;
    int elHeight = el.Height;
    //Координаты конца элемента (его нижний правый угол) в видимом окне:
    int elX_2 = elX_1 + elWidth;
    int elY_2 = elY_1 + elHeight;
//Проверяем проходит ли наш элемент сразу по всем условиям:  
    if (
        elX_1 >= margin_left && // отступ слева
        elY_1 >= margin_top && // отступ сверху
        elX_2 <= window_Width-margin_right &&  // отступ справа
        elY_2 <= window_Height-margin_bottom && // отступ снизу
        elWidth >= Width_Min && // минимальная ширина
        elHeight >= Height_Min && // минимальная высота
        elWidth <= Width_Max && // максимальная ширина
        elHeight <= Height_Max // максимальная высота
        ) {
            project.SendInfoToLog("Вот такой случайный элемент полностью в зоне видимости окна с учетом полей, его и кликаем:", true); // выводим в лог
            project.SendInfoToLog("(Координаты начала элемента в видимом окне (x,y), конца, ширина, высота, текст, тег)", true); // выводим в лог
            string InnerText = el.InnerText;
            string FullTagName = el.FullTagName;
            project.SendInfoToLog(elX_1.ToString() + ":" + elY_1.ToString() + ", " + elX_2.ToString() + ":" + elY_2.ToString() + ", " + elWidth.ToString() + ", " + elHeight.ToString() + ", " + InnerText + ", " + FullTagName, true); // выводим в лог
            instance.ActiveTab.FullEmulationMouseMoveToHtmlElement(el);
            System.Threading.Thread.Sleep(new Random().Next(1000,2000)); // пауза 1 - 2 сек.
            instance.ActiveTab.FullEmulationMouseClick("left", "click");
            return "успешно кликнули, и пофиг что страница потом стала 404";
        }
        heCol.Remove(c);
}
return "НЕ кликнули (видать нет видимых элементов в указанной зоне)";
//или вместо строки выше раскомментируйте и вставьте "выход по красной":
//throw new Exception("НЕ кликнули (видать нет видимых элементов в указанной зоне)");
Видео на 40 секунд с быстрой демонстрацией рисования границ видимой области:

Random.png

Варианты применения этих кубиков: нагуливание кук по сайтам, только измените xPath в коде на более сложный, чтобы по рекламе не кликать.
 

Вложения

Для запуска проектов требуется программа ZennoPoster.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...

Для того чтобы запустить шаблон, откройте программу ZennoPoster. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.

Последнее редактирование:

Iv1

Client
Регистрация
21.02.2016
Сообщения
1 644
Благодарностей
649
Баллы
113
Хорошая тема
Для себя что-то подобное реализовал сам и тоже мучался.
 

Fedor5588

Client
Регистрация
04.06.2017
Сообщения
264
Благодарностей
68
Баллы
28
Подскажите как правильно будет изменить код

C#:
HtmlElement he;
for(int i=0;i<20;i++)
{
    if(instance.ActiveTab.FindElementsByAttribute("a", "tagname", "a", "regexp").Count>0)
    {
        Random rnd = new Random();
        int x=rnd.Next(0,instance.ActiveTab.FindElementsByAttribute("a", "tagname", "a", "regexp").Count-1);

    he = instance.ActiveTab.FindElementByAttribute("a", "tagname", "a", "regexp",x);
    if(!he.IsVoid)
    {
        instance.ActiveTab.FullEmulationMouseMoveToHtmlElement(he);
        //he.RiseEvent("onclick","full");
        break;
    }

    }
    System.Threading.Thread.Sleep(2000);
}

return "";
на поиск по xpatch вот с такими параметрами

C#:
FindElementsByXPath("//a[@href][not(contains(@href, 'google')) and not(contains(@href, 'ad')) and not(contains(@href, 'yandex'))]")
 

Phoenix78

Client
Регистрация
06.11.2018
Сообщения
10 750
Благодарностей
5 129
Баллы
113

Fedor5588

Client
Регистрация
04.06.2017
Сообщения
264
Благодарностей
68
Баллы
28
FindElementsByAttribute менять на FindElementsByXPath
FindElementByAttribute менять на FindElementByXPath
это я понял, можете пожалуйста эту часть показать, у меня ошибка постоянно

C#:
    if(instance.ActiveTab.FindElementsByAttribute("a", "tagname", "a", "regexp").Count>0)
    {
        Random rnd = new Random();
        int x=rnd.Next(0,instance.ActiveTab.FindElementsByAttribute("a", "tagname", "a", "regexp").Count-1);

    he = instance.ActiveTab.FindElementByAttribute("a", "tagname", "a", "regexp",x);
 

Phoenix78

Client
Регистрация
06.11.2018
Сообщения
10 750
Благодарностей
5 129
Баллы
113
это я понял, можете пожалуйста эту часть показать, у меня ошибка постоянно
погонял приведенный код , ошибок не выдает.
заменил на xpath, тоже не выдает ошибок.
так то работает, но xpath наверно надо немного другой, так как постоянно пытается уехать к невидимым элементам.

блин, почему то сайт не дает код разместить. вот тогда скриншот.
65429
 

Fedor5588

Client
Регистрация
04.06.2017
Сообщения
264
Благодарностей
68
Баллы
28
погонял приведенный код , ошибок не выдает.
заменил на xpath, тоже не выдает ошибок.
так то работает, но xpath наверно надо немного другой, так как постоянно пытается уехать к невидимым элементам.

блин, почему то сайт не дает код разместить. вот тогда скриншот.
Посмотреть вложение 65429
блин/
ровно так же сделал, вываливается вот така ошибка
Компиляция кода Ошибка в действии "CS1501" "No overload for method 'FindElementsByXPath' takes 2 arguments". [Строка: 9; Cтолбец: 29]
 

Phoenix78

Client
Регистрация
06.11.2018
Сообщения
10 750
Благодарностей
5 129
Баллы
113
блин/
ровно так же сделал, вываливается вот така ошибка
Компиляция кода Ошибка в действии "CS1501" "No overload for method 'FindElementsByXPath' takes 2 arguments". [Строка: 9; Cтолбец: 29]
FindElementsByXPath имеет 1 аргумент
FindElementByXPath имеет 2 аргумента
 
  • Спасибо
Реакции: Fedor5588

Fedor5588

Client
Регистрация
04.06.2017
Сообщения
264
Благодарностей
68
Баллы
28
погонял приведенный код , ошибок не выдает.
заменил на xpath, тоже не выдает ошибок.
так то работает, но xpath наверно надо немного другой, так как постоянно пытается уехать к невидимым элементам.

блин, почему то сайт не дает код разместить. вот тогда скриншот.
Посмотреть вложение 65429
Заработал, не знал что есть два вида поиска по xpatch, обычный и с приставкой s. а По какому лучше элементу искать чтобы был случайный клик но при этом без клика по рекламе?
 

Phoenix78

Client
Регистрация
06.11.2018
Сообщения
10 750
Благодарностей
5 129
Баллы
113
Заработал, не знал что есть два вида поиска по xpatch, обычный и с приставкой s. а По какому лучше элементу искать чтобы был случайный клик но при этом без клика по рекламе?
они одинаковые. FindElementsByXPath возвращает коллекцию найденных элементов
FindElementByXPath возвращает один найденный элемент.
за поиск отвечает сам путь xpath, вот в нем и надо прописывать все условия и исключения в виде рекламы.
 
  • Спасибо
Реакции: smelka

Rus74

Client
Регистрация
09.01.2019
Сообщения
106
Благодарностей
40
Баллы
28
Спасибо большое за шаблон, прямо очень помог для имитации случайных кликов мышью по видимой области.
Подскажите, пожалуйста, как правильно исправить код, чтоб в логах вообще ничего не выводилось?
А то такую красоту в логах видеть нет необходимости.
https://prnt.sc/xg32ir
 

orka13

Client
Регистрация
07.05.2015
Сообщения
2 040
Благодарностей
2 065
Баллы
113
Спасибо большое за шаблон, прямо очень помог для имитации случайных кликов мышью по видимой области.
Подскажите, пожалуйста, как правильно исправить код, чтоб в логах вообще ничего не выводилось?
А то такую красоту в логах видеть нет необходимости.
https://prnt.sc/xg32ir
Заменить в строках с project.SendInfoToLog в конце параметр true на false. Типа сделать вот так, и они только в ProjectMaker будут видны:
C#:
project.SendInfoToLog("Для наглядности рисуем курсором границы зоны поиска, учитывая наши поля-отступы:", false);
Либо убрать их вообще.
UPD: подправил ошибку в слове false.
 
Последнее редактирование:
  • Спасибо
Реакции: userx и Rus74

daymos

Client
Регистрация
11.11.2009
Сообщения
804
Благодарностей
238
Баллы
43
Если работать с профиль папками, шаблон запускается без браузера и JS не отдает области, даже после запуска инстанса.
 

TheBoss

Client
Регистрация
30.03.2015
Сообщения
523
Благодарностей
182
Баллы
43
Если работать с профиль папками, шаблон запускается без браузера и JS не отдает области, даже после запуска инстанса.
Как решать, подскажешь?

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

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)