Ежедневник IT-ка
130 subscribers
24 photos
4 videos
1 file
44 links
Программируем на практике!!
По вопросам по поводу проектов: @vladimir_dzen
Download Telegram
👆Иногда есть необходимость получить данные, которые находятся довольно глубоко. Для этого лучше использовать XPath запросы.

#ZennoPoster,#Xpath
👆 Очередной xpath запрос для нахождения нужной информации.

#ZennoPoster,#Xpath
👆 Одна из ситуаций, когда при парсинге Json , получили ❗️исключение❗️. Поэтому, как выход, скрипт пытается найти необходимое значение и заменить его самостоятельно.

#ZennoPoster,#Xpath,#Json
​​В группе будут публиковаться различные посты, которые будут связаны с программным комплексом ZennoPoster.
Он используется мною очень часто т.к. помогает решить, большое кол-во задач связанных с автоматизацией, которые ведутся через браузер.
Самое главное его преимущество, что у него очень большое сообщество и его постоянно совершенствуют.

#ZennoPoster
​​После того, как нашли необходимый тег, получаем более детальную информацию в свойствах элемента.
В своей практике использую очень часто Xpath и Linq запросы, которые помогают более точно найти и обработать необходимые элементы.

#ZennoPoster
​​Продолжаем знакомство с программным комплексом ZennoPoster.

В примере показано:
- работа в многопоточном режиме
- чтение *.txt файлов
- сохранение содержимого *.txt файла в таблицу
- чтение и запись данных в таблицу
- конвертирование таблицы в список
- сохранение списка в *.txt файл

1. Получаем таблицу по имени созданную в проекте ZennoProject используя интерфейс IZennoTable

var sourceTable = project.Tables["Accounts"];

2. Инициализируем новый список класса List<T>

var sourceListFromTask = new List<string>();

3. Сохраняем в переменную "путь нашего файла", с которым работаем

string pathFile = Path.Combine(project.Directory, "account.txt");

4. FileLocker - это созданный нами объект синхронизации в общем коде ZennoProject, расположенный в классе CommonCode.

public static object FileLocker = new object();

4.1. Обязательно лочим наш поток(для того, чтобы другие
потоки не имели доступа к файлу),

lock (CommonCode.FileLocker)
{
4.2. Проверяем существование нашего файла, чистим таблицу
и инициализируем переменные.

if (File.Exists(pathFile))
{
sourceTable.Clear();
String line;
bool insertLine = true;

4.3. Читаем файл используя класс StreamReader,который
позволяет работать с файлом как хранилищем символов, и
такой подход более эффективен.

using (StreamReader sr = new StreamReader(@pathFile, Encoding.UTF8))
while ((line = sr.ReadLine()) != null)

4.4. Добавляем наши строки из файла в таблицу.

sourceTable.AddRow(line);

4.5. В цикле проверяем строки из таблицы и если выполняются необходимые условия, то сохраняем значения в переменные проекта.

for (int indexOfRow = 0; indexOfRow < sourceTable.RowCount; indexOfRow++)
{
string value = sourceTable.GetCell("C", indexOfRow).Trim();
if (string.IsNullOrEmpty(value) && insertLine)
{
project.Variables["emailAcc"].Value = sourceTable.GetCell("A", indexOfRow).Trim();
project.Variables["passAcc"].Value = sourceTable.GetCell("B", indexOfRow).Trim();
sourceTable.SetCell("C", indexOfRow, "Checking");
insertLine = false;
}
}

4.6. Переносим строки из таблицы в список, для того, чтобы
сохранить их в файл(использую  Linq запрос).

int column = 0;
Enumerable.Range(0, sourceTable.RowCount).ToList().ForEach(i => sourceListFromTask.Add(String.Join(":", sourceTable.GetRow(i))));

4.7. Сохраняем строки списка в файл используя класс
StreamWriter

using (StreamWriter sw = new StreamWriter(pathFile, false, Encoding.UTF8))
{
sw.WriteLine(string.Join("\r\n", sourceListFromTask));
}
}
}

Скриншот кода в проекте.

#ZennoPoster, #Сниппеты
​​Работа со временем и датами - это одна из тех задач, которую необходимо делать в программирование очень часто. Ведь актуальность данных это, то на чём держится современный мир(ушёл от темы).
Мы также не будем отставать и будем работать со временем.

Задача: рассчитать среднее кол-во времени размещение постов в группе(наш случай) согласно сервиса telemetr.me .

Работаем в программном комплексе ZennoPoster, который отлично справляется с анализом структурой страницы.

1. Для того, чтобы получить все "времена длительности"(назовём это так), то мы должны понять в каком из тегов они находятся т.е. подготовить предварительные данные.
Из структуры страница сайта, мы понимаем, что вся нужная информация находится в одном главном для нас теге "tr". Находим его.

1.1. Обращаемся к свойству('ActiveTab') объекта('instance') и передаём полученную информацию в класс('Tab').

Tab tab = instance.ActiveTab;

instance - это объект, который позволяет получать информацию, которая находится в запущенном браузере(это очень грубое сравнение), но можно рассматривать и так.
Tab - это класс, который имеет свойства для работы с текущей вкладкой нашего браузера.

1.2. Получаем Все необходимые элементы, которые находятся в текущей вкладке нашего браузера, с помощью XPath запроса и передаём в класс('HtmlElementCollection' - который работает с группой элементов).

HtmlElementCollection entries = tab.FindElementsByXPath("//tr");

1.3. Если кол-во найденных элементов ('tr'), больше 0, то идём дальше.

1.4. Инициализируем переменные.

var lstTemp = new List<string>();
var totalTimePublicPostAdvertise = string.Empty;
var content = string.Empty;

if (entries.Count > 0)
{

1.5. Проходим в цикле по всем свойствам('InnerHtml'), полученных тегов tr, в которых и расположена нужная информация.

for (int x = 0; x < entries.Count; x++)
{
content = entries.Elements[x].InnerHtml;

1.6. ОБЯЗАТЕЛЬНО весь наш последующий
код должен быть расположен в
конструкции(try..catch), для того, чтобы при
возникновение ошибок, код понимал,
что делать в этом случае.

try{

1.7. Получаем информацию с необходимого тега('span' с названием класса 'kt-font-brand'), с помощью XPath запроса, используя метод ParseByXpath и сохраняем полученные данные в список.

lstTemp =
ZennoPoster.Parser.ParseByXpath(content,
"//span[contains(@class,'kt-font-brand')]",
"innerText").ToList();

totalTimePublicPostAdvertise =
lstTemp[0].Trim().Replace("'", @"''");

}catch (Exception ex){

1.8. Отправляем ошибку в лог ZennoPoster.

project.SendErrorToLog(ex.Message, true);
}
}

Продолжение следует...

#ZennoPoster, #Дата
This media is not supported in your browser
VIEW IN TELEGRAM
Вот пример одного из скриптов, который помогает анализировать группы из ТГ и сокращает большое кол-во ручного труда.

Преимущества:

- Многопоточность
.

- Работа с СУБД - SQLite(
как писал выше, один файл, путь к Б.Д. и всё).

- Выборка групп(из сервиса и нашей Б.Д.), согласно критериям, которые были заданы в настройках программы.

- Сохранения данных в
docs.google.com

-
Подсчёт
средней величины размещения рекламных постов в днях и по времени на площадке.

-
Создание скриншотов, тех постов, которые принесли больше всего кол-во подписчиков, согласно выбранной тематике.

- Кол-во новых подписчиков(минимум, максимум, среднее) от тех рекламных постов, которые были размещены на площадке раньше.

- и др. фишки, которые
помогают делать анализ площадки.

Недостатки:

- Плата за использования
программного комплекса ZennoPoster.

- Плата за использование сервиса с которого берутся данные.

- Ограниченное кол-во потоков.

Часть вещей, которые реализовал в этом скрипте, буду описывать в дальнейших постах.

#ZennoPoster
​​Как и обещал ранее, буду рассматривать некоторые примеры, которые были реализованы мною в этом скрипте (если будет интересна одноразовая услуга по сбору площадок, используя этот скрипт, пишите).

Очень часто при вёрстки макетов сайта, похожая информация находится в в одинаковых тегах(div,tr,td,span и т.д.), которые для удобства отображения находятся в отдельных классах. Для того, чтобы получить всю эту информацию, необходимо это учесть.

Поэтому в данном примере это учту и покажу xPath запрос, который помог справится с этим.

Работаю с программным комплексом ZennoPoster

1. Обращаемся к свойству('ActiveTab') объекта('instance') и передаём полученную информацию в класс('Tab') (более подробнее писал выше).

Tab tab = instance.ActiveTab;

2. С помощью XPath запроса передаём найденные элементы в класс 'HtmlElementCollection'

HtmlElementCollection entries = tab.FindElementsByXPath("//tr[starts-with(@class,'tr_even')] | //tr[starts-with(@class,'tr_odd')]");

Интересный момент, на который стоит обратить внимание. 

а) Тело самого запроса использует логический оператор "или (|)", это позволяет нам собирать информацию с одинаковых тегов, но у которых разное оформление( "class")

"//tr[starts-with(@class,'tr_even')] | //tr[starts-with(@class,'tr_odd')]"

3. Основную информацию об элементах получил, дальше необходимо её обрабатывать.

#ZennoPoster, #Xpath
​​Продолжаю работать с ZennoPoster - ом. На этот раз задача состоит в том, чтобы отсылать сообщения в Telegram используя бота.

В начале, для того чтобы пользоваться им, необходимо получить токен доступа для него в telegram.

Наши действия:

1. Находим и добавляем в телеграм контакт @BotFather.
2. Заходим к нему в чат. Вызываем команду:  /start
далее:  /newbot.
3. Печатаем имя нашего бота(например имя моего бота "vkbotanswer").
4. Далее username(обязательно с окончанием "bot")
5. В ответном сообщение получаем токен нашего бота.
6. Дальше добавляем нашего бота(как "администратора") в необходимый канал и одновременно получаем id этого канала, перейдя по ссылке.

https://api.telegram.org/bot1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO/getUpdates

где: 1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO(полученный токен доступа).

Внимание: id канала имеет всегда знак "-" т.е. такой вид: -1005758311 .

7. На этом бот наш готов и мы можем отсылать наше сообщение(пример запроса):

https://api.telegram.org/bot1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO/sendMessage?chat_id=-1005758311&text=Приветствую!Меня зовут vkbotanswer и я готов к вашим командам.

Продолжение следует.....

#ZennoPoster
Forwarded from vladimir
Сегодня продолжю работать с ZennoPoster и Telegram, но уже в видео формате.

Основные шаги.
1.
Создание проекта.
2. Создание переменных.
3. Отправка сообщения в ТГ, 2-мя способами.

#ZennoPoster, #Telegram
Media is too big
VIEW IN TELEGRAM
Отправление фото и видео в Telegram используя ZennoPoster и библиотеку "Telegram.Bot"

#ZennoPoster, #Telegram
// Получаем время из переменной с указанием часовго пояса: 15.02.2022 12:00 +00:00
string capDateAndTimeRunRegistrationInSeil = project.Variables["capDateAndTimeRunRegistrationInSeil"].Value;

/* 1. Вариат с использованием struct DateTimeOffset .*/

// Парсим и сохраняем значение времени в struct DateTimeOffset.
var dtOffset_forSeil = DateTimeOffset.Parse(capDateAndTimeRunRegistrationInSeil);

// Преобразуем struct DateTimeOffset в struct DateTime(для дальнейшей работы).
var time_forSeil_DtOff = dtOffset_forSeil.DateTime;

// Выводим сообщение в лог.
project.SendToLog("ВРЕМЯ РЕГИСТРАЦИИ С ПОМОЩЬЮ DateTimeOffset: " + time_forSeil_DtOff.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Yellow);


/* 2. Вариат без использования struct DateTimeOffset .*/

// Конвертируем в struct DateTime.
var time_forSeil_Dt = Convert.ToDateTime(capDateAndTimeRunRegistrationInSeil);

// Выводим сообщение в лог.
project.SendToLog("ВРЕМЯ РЕГИСТРАЦИИ С ПОМОЩЬЮ БЕЗ DateTimeOffset: " + time_forSeil_Dt.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Yellow);


/* 3. Получение кол-во времени до события исходя из текущего согласно нашего часового пояса и времени начало самого события.*/

// Получение текущего времени согласно нашего часового пояса.
DateTime dtNow = DateTime.Now;

// Выводим сообщение в лог.
project.SendToLog("ТЕКУЩЕЕ ВРЕМЯ СОГЛАСНО НАШЕГО ЧАСОВОГО ПОЯСА: " + dtNow.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Green);

// Преобразование текущего времени согласно нашего часового пояса в UTC.
var utcTime_forNow = dtNow.ToUniversalTime();

// Выводим сообщение в лог.
project.SendToLog("ТЕКУЩЕЕ ВРЕМЯ СОГЛАСНО UTC: " + utcTime_forNow.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Green);

// Подсчёт кол-во времени до события.
TimeSpan diff = time_forSeil_DtOff.Subtract(utcTime_forNow);

// Выводим сообщение в лог.
project.SendToLog("ОСТАЛОСЬ ВРЕМЕНИ ДО РЕГИСТРАЦИИ СОГЛАСНО UTC(ЗАДАННОГО ВРЕМЕНИ) И НАШЕГО ВРЕМЕНИ(СКОНВЕРТИРОВАННОЕ В UTC): " + diff.Days.ToString("0") + " дн. " + diff.Hours.ToString("0") + " час. " + diff.Minutes.ToString("0") + " мин.", ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Orange);


 #ZennoPoster, #DateTime
Рассматриваю интересные моменты для получения информации используя метод из API Zennoposter: GetChildren.

1. Кол-во блоков с которых необходимо получить информацию из списка.

HtmlElementCollection entries = instance.ActiveTab.FindElementsByXPath("//div[contains(@class,'postlist') and contains(@id,'postsList')]/div");
int countBlocks = entries.Count;

2. Получение блоков в которых содержаться две необходимые части(текст и фото).

HtmlElement entry = instance.ActiveTab.FindElementByXPath("//div[contains(@class,'postlist') and contains(@id,'postsList')]/div", numRow);

numRow
- номер блока для парсинга.

HtmlElementCollection entries_m = entry.GetChildren(false);

Рекомендую посмотреть на этот метод:

GetChildren(false);

Позволяет получить элементы(детей) от главного элемента(родителя). С ним можно "творить" настоящие чудеса т.к. идёт упрощение кода и нет необходимости писать доп.-ые xpath запросы, чтобы обратиться к нужному элементу.

for (p = 0; p < entries_m.Count; p++)
{
HtmlElementCollection entries = entries_m.Elements[p].GetChildren(false);
for (s = 0; s < entries.Count; s++)
{
HtmlElementCollection entries_ = entries.Elements[s].GetChildren(false);
for (m = 0; m < entries_.Count; m++)
{
if (string.IsNullOrEmpty(postTitle))
{
postTitle = entries_.Elements[m].InnerHtml;
project.SendInfoToLog(postTitle);
break;
}
}
}
}

entries_m.Count
- полученное кол-во блоков, которое равно 2(т.е. текстовая и фото).

HtmlElementCollection entries = entries_m.Elements[p].GetChildren(false);

entries_m.Elements[p].GetChildren(false)
- здесь обращаемся к нужному элементу согласно индекса(т.е. 0), из которого также получаем "детей" элемента.

Итог: Метод GetChildren очень мощный метод, который даёт возможность обращаться к нижестоящим элементам без Xpath запросов.

#ZennoPoster, #Xpath
Сам код:

string about = string.Empty;

try
{
about = ZennoPoster.Parser.ParseByXpath(tab.DomText, "//div", "innerHtml").ToList().Where(s => s == "About").First();

foreach (string about_ in ZennoPoster.Parser.ParseByXpath(tab.DomText, "//div", "outerHtml").ToList())
{
try
{
about = ZennoPoster.Parser.ParseByXpath(about_, "//div", "innerHtml").ToList().Where(s => s == "About").First();
about = ZennoPoster.Parser.ParseByXpath(about_, "//div", "outerHtml").ToList().Where(s => s.Contains(">About<")).First();
about = Regex.Match(tab.DomText, about + ".*?</span>").Value;
about = about.Replace(">About<", "><");
about = Regex.Replace(about, "<.*?>", "");
}catch
{
//
}

}
}catch
{
//
}

#zennoposter, #парсинг
​​Многие из вас уже знакомы с chatgpt. Не так давно, необходимо было реализовать задачу, по распознаванию фото Локально.

Работаем через API.
1.) Обращаемся к официальной документации по ссылке:
https://platform.openai.com/docs/api-reference/chat/create
( create chat completion )
2.) Выбираем необходимое меню(как на картинке).
3.) Копируем и корректируем код(т.к. там, только через URL, распознаётся фото), нам же надо, если фото находится локально.
Пример моего Кода(Будьте очень Внимательны при его Использование):

string access_token_chatGpt = project.Variables["access_token_chatGpt"].Value;

//СТАРТ. Чтение файла в котором находится задание для ChatGPT
string pathToFileTaskForDescreptionPicture = project.Variables["pathToFileTaskForDescreptionPicture"].Value;
var taskForDescreptionPicture = string.Join(Environment.NewLine, File.ReadAllLines(pathToFileTaskForDescreptionPicture).ToList().Where(s => !string.IsNullOrEmpty(s)).ToList());
//ФИНИШ.

project.Variables["descreption"].Value = string.Empty;

string url = "https://api.openai.com/v1/chat/completions";

string imagePath = project.Variables["imageFilepath"].Value;

string image_url = imagePath;

string taskFrom = string.Empty;

base64Image = string.Empty;

/*Конвертация локального фото в
необходимую строку для распознавания, вместо адреса URL*/
string base64Image = Convert.ToBase64String(File.ReadAllBytes(imagePath));
image_url = $"data:image/jpeg;base64,{base64Image}";


HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", access_token_chatGpt);
client.DefaultRequestHeaders.Host = "api.openai.com";

var requestData = new
{
model = "gpt-4o",
messages = new []
{
new
{
role = "user",
content = new object[]
{
new
{
type = "text", text = taskForDescreptionPicture,
},
new
{
type = "image_url", 
image_url = new
{
url = image_url,
detail = "high"
}
}
}
}
},
max_tokens = 500
};

string jsonRequest = JsonConvert.SerializeObject(requestData);
var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(url, content).Result;
string responseData = response.Content.ReadAsStringAsync().Result;

if (response.IsSuccessStatusCode)
{
 project.Variables["descreption"].Value = responseData;
}
else
{
project.Variables["batch"].Value = responseData;
throw new Exception("");
}

4.) Получаем результат и радуемся.

P.S. Внимание!! Распознавание через API в разы хуже, чем через WEB.

#chatgpt, #Csharp, #zennoposter