Сниппеты C# Zennoposter / Зеннопостер
322 subscribers
3 photos
14 links
Админы:
@cmvvo
@MrSHILY
Download Telegram
Сниппет для скачивания файла на компьютер с задаванием ему имени:

string url = "https://assets.foxtons.co.uk/w/2200/1608286244/nwhm4911510_floorplan.png"; // урл файла, который качаем.
string nameFile = "мой скаченный файл"; // имя файла.
string downloadPath = $@"{project.Directory}\image\"; // путь, куда будет скачен файл.

if (!Directory.Exists(downloadPath)) Directory.CreateDirectory(downloadPath); // проверяем папку на существование (создаем, если её нет).

using (var wc = new System.Net.WebClient()) File.WriteAllBytes($@"{downloadPath}\{nameFile}{Path.GetExtension(url)}", wc.DownloadData(url));
Сниппет для копирования файла в новую директорию:

string pathFile = @"C:\ZennoProjects\ShilyHelper\test.txt"; // путь к файлу.
string pathNewDirectory = @"C:\ZennoProjects\ShilyHelper\NewFolder"; // новая директория для файла.

var fileInfo = new FileInfo(pathFile);
var directoryInfo = new DirectoryInfo(pathNewDirectory);

string newPathFile = Path.Combine(directoryInfo.FullName, fileInfo.Name);

try
{
if (!fileInfo.Exists) throw new Exception($"Файла не существует: {fileInfo.FullName}"); // проверяем файл на существование.
if (!directoryInfo.Exists) Directory.CreateDirectory(directoryInfo.FullName); // проверяем директорию на существование, если её нет - создаем.

File.Copy(fileInfo.FullName, newPathFile); // перемещаем файл.

project.SendInfoToLog($"Новый путь файла: {newPathFile}");
}
catch(Exception ex)
{
project.SendWarningToLog(ex.Message); // вывод ошибки в лог.
}



Если нужно скопированный файл переименовать:

string pathFile = @"C:\ZennoProjects\ShilyHelper\test.txt"; // путь к файлу.
string pathNewDirectory = @"C:\ZennoProjects\ShilyHelper\NewFolder"; // новая директория для файла.
string newNameFile = "Мой перемещенный файл";

var fileInfo = new FileInfo(pathFile);
var directoryInfo = new DirectoryInfo(pathNewDirectory);

string newPathFile = Path.Combine(directoryInfo.FullName, newNameFile + fileInfo.Name);

try
{
if (!fileInfo.Exists) throw new Exception($"Файла не существует: {fileInfo.FullName}"); // проверяем файл на существование.
if (!directoryInfo.Exists) Directory.CreateDirectory(directoryInfo.FullName); // проверяем директорию на существование, если её нет - создаем.

File.Copy(fileInfo.FullName, newPathFile); // перемещаем файл.

project.SendInfoToLog($"Новый путь файла: {newPathFile}");
}
catch(Exception ex)
{
project.SendWarningToLog(ex.Message); // вывод ошибки в лог.
}
Добавление текста во все строки списка:

var sourceList = project.Lists["Список 1"]; //Название списка
{
for(int i=0; i < sourceList.Count; i++)
{
sourceList[i] = "что добавляем" + sourceList[i];
}
}


Чтобы управлять тем, куда будет добавлять текст, изменяйте следующую конструкцию:
sourceList[i] = "что добавляем" + sourceList[i]; //добавить в начало каждого элемента в списке
sourceList[i] = sourceList[i +] + "что добавляем"; //добавить в конец каждого элемента в списке
sourceList[i] = sourceList[i +] + " " + "что добавляем"; //добавить в конец каждого элемента в списке с пробелом
Округление чисел:

//До большего числа. В этом примере будет 16.
double myDouble = 15.4;
return (int)Math.Ceiling(myDouble); //В этой строке (int) это тип переменной, в которую будет преобразовано число. Можно ещё преобразовывать например в long, double, float.

//До ближайшего целого числа. В этом примере будет 15.
double myDouble = 15.4;
return (int)Math.Round(myDouble, 0);


Если же необходимо округлить до сотых:
double x = 1.64;
x = Math.Round(x, 1);
return x;
В настоящий момент функция Drag & Drop стандартными кубиками зеннопостера не работает должным образом. С помощью этого сниппета вы сможете их заменить:

instance.ActiveTab.FullEmulationMouseCurrentPosition = new Point(220,1000);
instance.ActiveTab.FullEmulationMouseClick("left","down");

instance.ActiveTab.FullEmulationMouseDragAndDrop(220,1000, 350, 1000);
instance.ActiveTab.FullEmulationMouseClick("left","up");


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

Загрузка профиля.
// Путь к профилю
string profilePath = Path.Combine(project.Path, "1.zpprofile");
// Создавать ли отстутствующие переменные
bool createVars = false;

#region Load
Action<string,bool> Load = (path, createVariables) =>
{
string oldUA = project.Profile.UserAgent;
string oldName = project.Profile.Name;
string oldEmail = project.Profile.Email;
int oldLength = project.Profile.ToString().Length;

project.Profile.Load(path, createVariables);

string newUA = project.Profile.UserAgent;
string newName = project.Profile.Name;
string newEmail = project.Profile.Email;
int newLength = project.Profile.ToString().Length;

if (oldUA == newUA && oldName == newName && oldLength == newLength && oldEmail == newEmail)
{
throw new Exception("Ошибка загрузки профиля. Путь: " + path);
}
};
#endregion

// Загрузка профиля
Load(profilePath, createVars);


Сохранение профиля.
// Путь к профилю
string profilePath = Path.Combine(project.Path, "2.zpprofile");
// Переменные проекта, которые нужно сохранить
var saveVars = new[] { "var1", "var2" };

#region Save
Action<string,string[]> Save = (path, saveVariables) =>
{
if (File.Exists(path))
{
string profilePathAlt = profilePath.Replace(".zpprofile", "_ForCheck.zpprofile");

// Сохранение копии профиля
project.Profile.Save(profilePathAlt, true, true, true, true, true, true, true, true, true, saveVariables);

var infoOld = new FileInfo(profilePath);
var infoNew = new FileInfo(profilePathAlt);
// Допустимая погрешность в байтах
long diff = 5 * 1024;

// Если новый файл тот же или больше, с учётом допустимой погрешности
if (infoNew.Length >= infoOld.Length - diff)
{
// Сохранение профиля и удаление копии
project.Profile.Save(profilePath, true, true, true, true, true, true, true, true, true, saveVariables);
File.Delete(profilePathAlt);
}
else
{
string text = String.Format("Обнаружено уменьшение размера профиля в байтах. Старый размер: {0} Новый размер: {1}. Путь: {2}",
infoOld.Length, infoNew.Length, profilePath);
throw new Exception(text);
}
}
else
{
project.Profile.Save(path, true, true, true, true, true, true, true, true, true, saveVariables);
}
};
#endregion

// Сохранение профиля
Save(profilePath, saveVars);
Так как я сейчас активно занимаюсь автоматизацией андроид эмуляторов, то некоторые посты со сниппетами буду посвящать этой теме. Первый пост: как получать ответ в переменную или лог из cmd таких инструментов как adb (средство связи между компьютером и андроид-устройством. Например смартфоном или эмулятором) и memuc (позволяет управлять эмулятором Memu из командной строки. Так как я использую Memu в качестве эмулятора)

Сниппет для ответа из adb. Данный сниппет покажет уровень заряда батареи. Чтобы вводить другие команды, меняйте значение здесь - p.StartInfo.Arguments. Чтобы узнать о других командах, вбейте в гугл "команды adb"

var sv = project.Variables["sv"].Value; //sv это серийник устройства для многопотока вида 127.0.0.1:21521
Process p = new Process();
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "adb.exe";
p.StartInfo.Arguments = @"-s "+sv+" shell dumpsys battery | grep 'level'";
p.StartInfo.CreateNoWindow = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
project.Variables["battery_level"].Value = output.Trim();


Сниппет для ответа из memuc.exe. Команды так же задаём здесь - p.StartInfo.Arguments. Список команд - https://www.memuplay.com/blog/memucommand-reference-manual.html

System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866);
p.StartInfo.FileName = @"D:\Program Files\Microvirt\MEmu\memuc.exe"; // путь к батнику или exe
p.StartInfo.Arguments = @" reboot -i 0"; // его параметры
p.Start();

string output = p.StandardOutput.ReadToEnd();
p.WaitForExit(); // ожидание завершения процесса

return output;
[Манипуляции с таблицей]

Пример затирания ячеек:
var table = project.Tables["Моя зенно таблица"]; // наша зенно таблица.
var searchText = "shily"; // текст по которому будем искать.

//Очистка таблицы перед работой.
table.Clear();

//Добавляю данные в пустую таблицу.
table.AddRow(new[]{"one","two","three","four"});
table.AddRow(new[]{"one","two","
shily
","four"});
table.AddRow(new[]{"one","two","three","four","five"});

var countColumn = table.ColCount; // подсчет столбцов в таблице.
var countRow = table.RowCount; // подсчет строк в таблице.

project.SendInfoToLog($"Количество строк: {countRow}"); // лог в pm.
project.SendInfoToLog($"Количество столбцов: {countColumn}"); // лог в pm.

lock (SyncObjects.TableSyncer)
{
for (int counterByRow = 0; counterByRow < countRow; counterByRow++)
{
for (int counterByColumn = 0; counterByColumn < countColumn; counterByColumn++)
{
if (table.GetCell(counterByColumn, counterByRow).Contains(searchText)) table.SetCell(counterByColumn, counterByRow, "");
}
}
}

Супер-костыльный вариант затирания ячеек со смещением данных по горизонтали, удалением пустых столбцов и строк:
var table = project.Tables["Моя зенно таблица"]; // наша зенно таблица.
var searchText = "shily"; // текст по которому будем искать.

//Очистка таблицы перед работой.
table.Clear();

//Добавляю данные в пустую таблицу.
table.AddRow(new[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"});
table.AddRow(new[]{"0", "1", "2", "shily", "3", "4", "shily", "5", "6", "7", "8", "9"});
table.AddRow(new[]{"shily", "0", "1", "shily", "shily", "2", "3", "4", "5", "shily", "6", "shily", "7", "8", "9", "shily", "shily"});
table.AddRow(new[]{"shily1", "shily2", "shily3", "shily4", "shily5", "shily6", "shily7", "shily8", "shily9"});
table.AddRow(new[]{"0", "1", "2", "shily", "3", "4", "shily", "5", "6", "7", "8", "9", "10"});
table.AddRow(new[]{"0", "1", "2", "shily", "3", "4", "shily", "5", "6", "7", "8", "9"});

var countRow = table.RowCount; // подсчет строк в таблице.
var countColumn = table.ColCount; // подсчет столбцов в таблице.

string cellValue;
bool textTrue;
int emptyPosition;

lock (SyncObjects.TableSyncer)
{
for (int counterByRow = 0; counterByRow < countRow; counterByRow++)
{
emptyPosition = -1;

for (int counterByColumn = 0; counterByColumn < countColumn; counterByColumn++)
{
cellValue = table.GetCell(counterByColumn, counterByRow);
textTrue = cellValue.Contains(searchText);

if (textTrue && emptyPosition == -1)
{
table.SetCell(counterByColumn, counterByRow, "");
emptyPosition = counterByColumn;
}
else if (!textTrue && emptyPosition != -1)
{
table.SetCell(counterByColumn, counterByRow, "");
table.SetCell(emptyPosition, counterByRow, cellValue);
emptyPosition++;
}
else if (textTrue && emptyPosition != -1) table.SetCell(counterByColumn, counterByRow, "");
}
}

for (int counter = 0; counter < table.RowCount;)
{
if (table.GetRow(counter).Any(x => !string.IsNullOrWhiteSpace(x)))
{
counter++;
continue;
}
else table.DeleteRow(counter);
}

for (int counter = 0; counter < table.ColCount;)
{
if (table.GetColumn(counter).Any(x => !string.IsNullOrWhiteSpace(x)))
{
counter++;
continue;
}
else table.DeleteColumn(counter);
}
}


[P.S.]
Затираются данные содержащие текст, если нужно затирать точные данные, то заменяем "textTrue = cellValue.Contains(searchText);" на "textTrue = cellValue.Equals(searchText, StringComparison.Ordinal);".
Сниппет для парсинга результата по DOM через xpath от @SH_ILY

var proxy = "";

var url = "https://korter.co.uk/the-claves-london/layouts?type=1BR";

var httpResponse = ZennoPoster.HTTP.Request
(
ZennoLab.InterfacesLibrary.Enums.Http.HttpMethod.GET, url, "", "", proxy, "UTF-8",
ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly, 30000, "", project.Profile.UserAgent, true, 5,
null, "", false, false, project.Profile.CookieContainer
);

try
{
//Сохранение результата в переменную (по порядку).
project.Variables["result1"].Value = string.Join("", ZennoPoster.Parser.ParseByXpath(httpResponse, "//a[contains(@class, 'StyledImage') and @href!='']/parent::div", "outerhtml"));

//Сохранение результата в переменную (с переносом на новую строку).
project.Variables["result2"].Value = string.Join("\n", ZennoPoster.Parser.ParseByXpath(httpResponse, "//a[contains(@class, 'StyledImage') and @href!='']/parent::div", "outerhtml"));

//Сохранение результата в список.
project.Lists["Result"].AddRange(ZennoPoster.Parser.ParseByXpath(httpResponse, "//a[contains(@class, 'StyledImage') and @href!='']/parent::div", "outerhtml"));
}
catch (Exception ex)
{
project.SendWarningToLog(ex.Message);
}


Подтянуть знания по составлению путей xpath можно тут - https://msiter.ru/tutorials/xpath/vvedenie
👍1
Обработать список из чисел (сначала здесь все строки списка преобразовываются из типа string в int):

var list = project.Lists["Список 2"];
var numbers = new List<int>();
foreach(var n in list){
numbers.Add(int.Parse(n));
}

//Пример преобразования чисел в массиве или списке типа string в массив или список типа int
var strArray = new[]{ "0042", "010", "9", "27" };
var numbArray = strArray.Select(s => int.Parse(s)).ToArray();

var matches = numbers.Select(n => n * 10); //Здесь запросом Linq задайте как именно будут обрабатываться строки

foreach(int n in matches){
project.SendInfoToLog(n + "|", true);
}

Код с теми-же функциями, но обрабатывает только числа, минуя строки, если таковые есть в списке:

var numbers = new List<int>();
project.Lists["Мой зенно список"].ToList().ForEach(x =>{if (int.TryParse(x, out int r)) numbers.Add(r * 10);});
foreach (var n in numbers) project.SendInfoToLog($"{n}|", true);


Если нужно обработать каждый символ в строке (в данном примере идёт удаление всех гласных из строки):

var query = "Not what you might expect";
string vowels = "aeiou";
foreach(char vowel in vowels){
query = query.Where(c = > с != vowel);
}
То же самое, но по другому методу:
var query = "Not what you might expect";
string vowels = "aeiou";
for(int i = 0; i < vowels.Length; i++){
char vowel = vowels[i];
query = query.Where(c => с != vowel);
}

Пройтись по каждой строке в списке и сделать замены если они там есть:

IZennoList list = project.Lists["Список 2"];
for (int i = 0; i < list.Count; i++){
list[i] = Regex.Replace(list[i], ",", ".");
}
👍2
Добавление данных из переменных в файл и изменение самого расширения файла по окончанию действия:
// Имя файла (без расширения)
var fileName = "мой файл";

var zennoVar = new List<ILocalVariable>();

// Добавляем наши переменные, данные из которых хотим вписать в файл (писать ".Value" не нужно)
zennoVar.Add(project.Variables["text1"]);
zennoVar.Add(project.Variables["text2"]);
zennoVar.Add(project.Variables["text3"]);

var numbVar = zennoVar.Count;

lock (CommonCode.SyncObject)
{
try
{
// Создаем экземпляр класса с информацией о нашем файле
var file = new FileInfo($@"{project.Directory}\files\{fileName}.txt");
var newFile = new FileInfo($@"{file.DirectoryName}\{Path.GetFileNameWithoutExtension(file.FullName)}.php");

if (newFile.Exists) throw new Exception($"Такой файл уже существует: {newFile.FullName}");

// Чекаем директорию на существование, если нет, то создаем
if (!file.Directory.Exists) file.Directory.Create();

// Проверяем наличие файла и есть ли в нем строки
if (file.Exists)
{
var numbLine = File.ReadAllLines(file.FullName, Encoding.UTF8).Count();

if (numbLine != 0 && !string.IsNullOrEmpty(File.ReadLines(file.FullName, Encoding.UTF8).Skip(numbLine - 1).First()))
File.AppendAllText(file.FullName, Environment.NewLine, Encoding.UTF8);
}

// Добавляем данные переменных в файл
for (int i = 0; i < numbVar; i++)
{
File.AppendAllText(file.FullName, zennoVar[i].Value, Encoding.UTF8);

if (i != numbVar - 1) File.AppendAllText(file.FullName, Environment.NewLine, Encoding.UTF8);
}

// Перемещаем файл с новым расширением
File.Move(file.FullName, newFile.FullName);
}
catch (Exception ex)
{
project.SendWarningToLog($"Что-то пошло не так.. | Exception message: {ex.Message}", true);
}
}
Очистка exif (метаданных) изображения:
// Файл для обработки
var sourceFile = new FileInfo(@"C:\Users\ILYA\Desktop\IMG_20200806_011145.jpg");

// Конечный результат обработки (можно не менять, файл будет рядом с исходником)
var modifiedFile = new FileInfo(Path.Combine(sourceFile.DirectoryName, $"{Path.GetFileNameWithoutExtension(sourceFile.FullName)}_modified_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}{sourceFile.Extension}"));

// Качество конечного изображения
var quality = 100;

// Обработка
ZennoPoster.ImageProcessingClearExifFromFile(sourceFile.FullName, modifiedFile.FullName, quality);
👍1🔥1
Узнать причину крайней ошибки по 4 критериям:

LastError lastError = project.GetLastError();

string projectName = lastError.ProjectName;
string actionGroupId = lastError.ActionGroupId;
string actionId = lastError.ActionId;
string actionComment = lastError.ActionComment;
Exception e = lastError.Exception;

project.SendErrorToLog("Проект: " + projectName + "\r\n" +
"id группы экшенов: " + actionGroupId + "\r\n" +
"id экшена: " + actionId + "\r\n" +
"Комментарий экшена: " + actionComment + "\r\n" +
"Текст ошибки: " + e.Message + "\r\n" + e.StackTrace);
👍4
Проверка содержит ли список какую-то конкретную строку:

// Добавить в OwnCode (Общий код) в конце:
/* namespace ZennoHelpers
{
public class Locker
{
public static object CustomListSyncer = new object();
}
} */

// берем из переменной текст, который надо искать
var textContains = project.Variables["listSearchTextContains"].Value;

// получаем список, в котором будем искать
var sourceList = project.Lists["SourceList"];

lock(ZennoHelpers.Locker.CustomListSyncer)
{
// ищем в каждой строчке в списке
for(int i=0; i < sourceList.Count; i++)
{
// читаем строку из списка
var str = sourceList[i];

// проверяем содержание текста в строке, если есть совпадение возвращаем "yes"
if (str.Contains(textContains))
{
return "yes";
}
}
}

// если ничего не нашли возвращаем "no"
return "no";
👍1
Копирует полностью содержимое Таблицы 1 в Таблицу 2
var table1 = project.Tables["Таблица 1"];
var table2 = project.Tables["Таблица 2"];
for(int i=0; i<table1.RowCount; i++) {
table2.AddRow(table1.GetRow(i).ToArray());
}
👍3
Раз на то пошло, от себя добавлю по таблицам:)

Копирует полностью содержимое из "Таблица 1" в "Таблица 2":
project.Tables["Таблица 1"].GetItems("all", false).ToList()
.ForEach(x => project.Tables["Таблица 2"].AddRow(x));

Перемещает полностью содержимое из "Таблица 1" в "Таблица 2":
project.Tables["Таблица 1"].GetItems("all", true).ToList()
.ForEach(x => project.Tables["Таблица 2"].AddRow(x));

Перемещает 5-ть случайных элемента из "Таблица 1" в "Таблица 2":
project.Tables["Таблица 1"].GetItems("random5", true).ToList()
.ForEach(x => project.Tables["Таблица 2"].AddRow(x));

...и т.д. можно использовать разные фильтры, что придает преимущество данному методу в виде гибкости.

GetItems:
Первый параметр: Фильтр
Второй параметр: Отвечает за удаление (true - удалять; иначе - false - он по умолчанию)

Информация по фильтрам:
https://zennolab.atlassian.net/wiki/spaces/RU/pages/488964137
👍6
Forwarded from SHILY PROJECT (SHILY)
[ #ZENNO_SNIPPET | VK AUTH ]

Мне тут нужно было написать авторизацию под ВК, но из-за кривых рук не завелось стандартными .NET средствами. Решил накидать на коленки в зенке - там всё ок. Хз, может кому-то пригодится.

P.S. Если что, сниффал запросы через Fiddler.

[ Source code on GitHub ]

👍8
Создание заданного числа случайных чисел в диапазоне и размещение их в переменные:

List<int> lstNumber = new List<int>();
int number = 0;

//Генерируем коллекцию случайных чисел, где "10" это количество переменных, в которые будут вложены созданные числа
while(lstNumber.Count<10){
number = Global.Classes.rnd.Next(0, 100);//Диапазон создаваемых случайных чисел
if(!lstNumber.Contains(number)) lstNumber.Add(number);
}

//Запись данных в переменные проекта
for(int i=0; lstNumber.Count>0 ;i++){
project.Variables["var"+i.ToString()].Value = lstNumber[0].ToString(); //"var" - это начало названия переменных, в которые будут сохраняться создаваемые числа
lstNumber.RemoveAt(0);
}

Взятие из списка случайных строк и размещение их в переменные без удаления из списка:

var list = project.Lists["list"];

Random rand = new Random();
int temp = rand.Next(0,19); //тут задаётся диапазон количества строк списка, которые будут взяты в переменные в случайном порядке

List<string> lstNumber = new List<string>();
int number = 0;

//Генерируем коллекцию случайных чисел
while(lstNumber.Count<3){ //"3" это количество переменных, которые будут заполнены взятыми в случайном порядке строками
string slstr = tegi_list.OrderBy(s => Guid.NewGuid()).First(); //взятие случайной строки из списка в переменную
if(!lstNumber.Contains(slstr)) lstNumber.Add(slstr); //проверка на уникальнось строки
}
//Запись данных в переменные проекта
for(int i=0; lstNumber.Count>0 ;i++){
project.Variables["teg"+i.ToString()].Value = lstNumber[0].ToString();
lstNumber.RemoveAt(0);
}
👍9
Forwarded from SHILY PROJECT (SHILY)
Я тут статью накидал на 17-й конкурс по использованию DI и IoC в Зенке. Если интересно, то ссылку прикрепил ниже.

[ Продолжаем кодить на C#. «Hello, world!» в контейнере. ]
👍12
Написал статью-обзор на Linq со своими сниппетами. Linq позволяет работать с массивами, списками, SQL, XML. https://teletype.in/@cmvvo/m4ZJ8McGYB2
👍11