Z-TehnOman Part3. Автоматическая установка и работа с NodeJS напрямую из проекта Zennoposter

semafor

Client
Регистрация
27.12.2016
Сообщения
289
Благодарностей
404
Баллы
63
Всем добра и мира!

Из названия статьи понятно, что мы будем прикручивать к шаблону ZP NodeJS — наш шаблон будет автоматически устанавливать ноду, автоматически устанавливать npm-пакет, с которым будем работать, ну и посылать данные на обработку и получать в ответах результаты. И все это — непосредственно из кода, без всяких батников.

91905


РАЗБОР ТЕМЫ ХОЧЕТСЯ НАЧАТЬ С БЛАГОДАРНОСТЕЙ:


  • @Astraport — за появление NodeJS в моем поле зрения (прочитав именно его статью, я сделал себе заметку о необходимости потыкать палочкой этот инструмент)
  • @Lord_Alfred за идею (Универсальный экстрактор контента) с использованием readability библиотеки, а так же за офигенные снипеты для очистки контента, проверки ответов на get-запросы, адские регулярки и все остальное, что присутствует в шаблоне, прикрепленном к указанной статье. Множество решений из нее не однажды использовал.
  • @marsht за замечательную статью о JS
НЕСКОЛЬКО СЛОВ О NODEJS, И ПОТЕНЦИАЛЕ ЕГО ИСПОЛЬЗОВАНИЯ В ПРОЕКТАХ ZP

NodeJS — это среда для выполнения JavaScript. Того самого js, который выполняется, пожалуй, на 99,9% страниц, загружаемых нами в браузере. А еще, того самого JS, с помощью которого владельцы сайтов и веб-сервисов получают информацию о браузере (и об ОС — fingerprint, timezone, язык системы, шрифты и т.п.), генерируют куки, определяют и отшивают ботов (тем самым нанося непоправимый вред тонкой душевной организации многих владельцев Zennoposter).

Хм... Есть JS, который мешает жить ботоводам, и есть среда для его запуска, с огромным количеством готовых к использованию инструментов, позволяющих всячески препарировать тот самый, злобный, JavaScript. Как по мне, потенциал у связки ноды с ZP огромен, и оценить его я не возьмусь, хотя бы потому, что я пока не знаю JavaScript.

Сразу напрашивается логичный вопрос — а как же пользовать такое богатство, если ключиков к нему нет?

Конечно же учить JS хотя бы на начальном уровне, учить NodeJS, чтобы понимать хотя бы примерно — что, куда и как. Но в принципе, можно обойтись — поиск пакетов по ключу cli выдает 4769 страниц. Омайнгот!!! 4769 страниц, содержащих пакеты под решение каких-то задач, с прикрученным к ним интерфейсом командной строки! Определенно, назначение многого из того, что находится на этих страницах будет пока абсолютно мутным, но, все же, я уверен, что в такой куче найдется несколько жемчужин для каждого владельца ZP.

Чтобы подтвердить утверждение о жемчужинах, я плавно перейду к шаблону, который будет прикреплен к статье. Мне понадобился функционал, который как я помнил, выкладывал @Lord_Alfred в одном из конкурсов, однако, найдя соотв. топик, оказалось, что обновилась библиотека, входящая в состав шаблона и написанная на Go, и карета превратилась в тыкву (без правок на неизвестном мне языке шаб не работал). Библиотека на C# с гитхаба с разбегу не запустилась, а нужно было срочно, и вот я нашел несколько разных вариантов библиотек под NodeJS — в том числе и та, которую интегрировал в шаблон.

Установить и запустить NodeJS вручную не сложнее чем поставить любой опенсорсный софт, еще часа-полтора проб, ошибок и чтения коротенького мануала к пакету с cli-интерфейсом и вуаля! Можно подключать к ZP.

ПАРА СЛОВ О NPM-ПЕКЕТЕ (БИБЛИОТЕКЕ) READABILITY-CLI, ИСПОЛЬЗУЕМОЙ В ПРИЛАГАЕМОМ ШАБЛОНЕ


Эта библиотека как раз и выполняет основную работу по извлечению статей из html-страниц, и делает это очень неплохо, а с учетом наработок от Lord_Alfred — отлично. Взаимодействие с пакетом происходит через командную строку (что немаловажно, с учетом нубства в js). К тому же, есть возможность получить не только очищенный текст, но и текст статьи в виде очищенного html, из которого замечательно извлекаются анкоры ссылок и информация об изображениях. Пакет не имеет никаких регалий на https://www.npmjs.com, у него совсем немного скачиваний, и к тому же, у последней версии что-то изменилось (после пары месяцев использования решил обновить либу), и часть работавшего функционала перестала работать — пришлось откатывать на предыдущий билд. Но тем не менее, я быстро получил готовое решение, которое смог интегрировать в шаблон, и после уже не спеша размышлять, оставить этот вариант или искать что-то поинтересней.

ИНФОРМАЦИЯ О ШАБЛОНЕ

Шаблон, прикрепленый к статье, представляет ценность скорее как обучающий, хотя весь заявленный функционал выполняет и работает в многопотоке. По-сути, это чуть расширенная версия «Универсального экстрактора» от Lord_Alfred, только с использованием NodeJS (и скорее всего, более медленнная версия). Итак, о функционале:

  • Автоматическая установка NodeJS и npm-пакетов
  • Парсинг материалов с сайтов и их очистка от безполезной инфы — реклама, менюхи, ссылки и прочие лишние данные.
  • Получение и сохранение форматированного, очищенного html статьи
  • Получение и сохранение текста статьи
  • Опционально — получение и сохранение анкоров и url ссылок, присутствующих в статьях
  • Опционально — получение и сохранение alt, title и href картинок статей
  • Опционально же — сохранение изображений, присутствующих в статье
  • Сохранение в SQLite информации о полученных материалах (можно было и сами материалы туда же, но решил не заморачиваться)
Шаб работает без использования браузера, внутри него крутится несколько внешних библиотек (будут прикреплены к шаблону):

  1. HtmlAgilityPack. Очень люблю эту либу за огромные возможности при парсинге (отдельно за отсутствие глюков при обработке всевозможных кастомных атрибутов, с которыми натерпелся при использовании штатных возможностей ZP). В принципе, она избыточна здесь, но выпиливать ее не стал.
  2. System.Data.SQLite - библиотека для работы с БД SQLite
  3. Dapper, Dapper.Contrib — либы, позволяющие пользовать ОРМ Dapper, о них я писал в прошлом конкурсе статей — MySQL, SQLite.
91906


Чтобы эти либы функционировали, нужно поместить их в папку ExternalAssemblies Zennoposter.

Нелишним будет и небольшой обзор директив using:
  • using System.Xml — для работы с HtmlAgilityPack,
  • using HtmlAgilityPack — собственно сам HtmlAgilityPack
  • using Dapper; using Dapper.Contrib; using Dapper.Contrib.Extensions — работа с Dapper
  • using System.Data.SQLite — работа с БД SQLite
  • using NodejsHelper; using Scrapping; using ZHelper — мои сборки, их внутренности подробно откомментированы в общем коде
  • System.Web — не смог вспомнить, для чего он тут, выпиливать не стал
  • И есть еще одно пространство имен, используя которое мы и будем автоматизировать установку ноды и общаться с ней через командную строку — using System.Diagnostics. Подробности далее.
91907



ОБЩЕНИЕ С КОМАНДНОЙ СТРОКОЙ ИЗ КОДА C#

Класс Process из сборки System.Diagnostics, позволяет запускать и останавливать любой процесс ОС (т.е. в том числе и исполняемый файл). Используя этот класс, мы будем запускать интерфейс командной строки cmd.exe и выполнять в нем команды, а также запустим инсталятор msi с аргументамми, позволяющими установить NodeJS. Код для вызова командной строки и выполнения команды (например, опредилить битность системы), выглядит вот так:

C#:
string request = string.Empty;
    using(System.Diagnostics.Process process = new System.Diagnostics.Process())
    {
        process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        process.StartInfo.FileName = "cmd.exe";
        process.StartInfo.Arguments = "/C wmic os get osarchitecture";
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardInput = true;
        process.Start();
           
        while(!process.HasExited)
        {
            //сохранили ответ cmd
            request += process.StandardOutput.ReadToEnd();    
        }              
    }
Данный код позволяет выполнить в cmd однострочную команду, и получить в переменную результат ее выполнения. Здесь в параметр process.StartInfo.FileName мы передаем имя процесса (в нашем случае cmd.exe), а параметру process.StartInfo.Arguments команду, которую нужно выполнить - "/C wmic os get osarchitecture" (вернуть битность ОС), где ключ /C обозначет, что после выполнени команды, процесс должен быть завершен. А как быть если нужно выполнить последовательность команд? Решение имеется:

C#:
//Здесь я пишу пустой список, но в реале в нем команды для выполнения
List<string> cmd = new List<string>();
    string request = string.Empty;
    using(System.Diagnostics.Process process = new System.Diagnostics.Process())
    {
        process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        process.StartInfo.FileName = "cmd.exe";
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardInput = true;              
        process.Start();
        using (StreamWriter sw = process.StandardInput)
        {
            if (sw.BaseStream.CanWrite)
            {
                foreach(string str in cmd)
                {
                    sw.WriteLine(str);
                }
            }
        }
               
        while(!process.HasExited)
        {
            //сохранили ответ cmd
            request += process.StandardOutput.ReadToEnd();  
        }
    }
Так как общения с cmd в шабе дофига, я создал в общем коде статический класс, и запихал все это хозяйство туда, см. сборку ZHelper. Там же добавлен метод, позволяющий запустить инсталлер msi(а в принципе, любой процесс Windows), и передать ему в качестве аргумента команду установить NodeJS из указанного url:

C#:
    /// <summary>
    /// Статический класс, содержащий методы для запуска соманд в командной строке windows
    /// </summary>
    public static class ZHelperExt
    {
        /// <summary>
        /// Метод запускает командную строку windows и выполняет однострочную команду, возвращает строку, в которую сохраняет результат выполнения (если команда которая выполняется имеет его)
        /// </summary>
        /// <param name="cmd">Команда, котороую надо выполнить в командной строке</param>
        /// <returns></returns>
        public static string RunSingleCmdReturnToString(string cmd)
        {
            string request = string.Empty;
            using(System.Diagnostics.Process process = new System.Diagnostics.Process())
            {
                process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                process.StartInfo.FileName = "cmd.exe";
                process.StartInfo.Arguments = cmd;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardInput = true;
                process.Start();
                   
                while(!process.HasExited)
                {
                    //сохранили ответ cmd
                    request += process.StandardOutput.ReadToEnd(); //русский язык кракозябрами, потом надо подумать    
                }              
                return request;
            }
        }
       
        /// <summary>
        /// Метод запускает командную строку windows и выполняет несколько команд в той последовательности, в которой они указаны во входном списке cmd
        /// </summary>
        /// <param name="cmd">Список команд для выполнения в командной строке</param>
        /// <returns>Строка, содержащая результаты исполнения команд</returns>
        public static string RunListCmdReturnToString(List<string> cmd)
        {
            string request = string.Empty;
            using(System.Diagnostics.Process process = new System.Diagnostics.Process())
            {
                process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                process.StartInfo.FileName = "cmd.exe";
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardInput = true;              
                process.Start();
                using (StreamWriter sw = process.StandardInput)
                {
                    if (sw.BaseStream.CanWrite)
                    {
                        foreach(string str in cmd)
                        {
                            sw.WriteLine(str);
                        }
                    }
                }
                       
                while(!process.HasExited)
                {
                    //сохранили ответ cmd
                    request += process.StandardOutput.ReadToEnd(); //русский язык кракозябрами, потом надо подумать    
                }
               
                return request;
            }
        }
        /// <summary>
        /// Метод позволяет запускать любые программы windows
        /// </summary>
        /// <param name="progName">Имя программы, которую надо запустить</param>
        /// <param name="workingDir">Рабочая директория для запуска процесса (НЕ директория где находится исполняемый файл!)</param>
        /// <param name="cmd">Аргументы запуска программы</param>
        public static void RunSomeProgramm(string progName, string workingDir, string cmd)
        {
            using(System.Diagnostics.Process process = new System.Diagnostics.Process())
            {
                process.StartInfo.FileName = progName;
                process.StartInfo.WorkingDirectory = workingDir;
                process.StartInfo.Arguments = cmd;
                process.StartInfo.Verb = "runas";
                process.Start();
                process.WaitForExit(100000);
            }
        }
       
    }

УСТАНОВКА NODEJS ИЗ ШАБЛОНА

Что нам нужно, чтобы установить NodeJS:
  • Разрядность ОС
  • Ссылка на скачивание NodeJS
  • Также, стоит проверить, не установлен ли уже в системе NodeJS, а если установлен, соответствует ли его билд требованиям npm-пакета
Для этих целей в общем коде создан класс jsHelper, при создании объекта которого в конструкторе получается вся нужная информация:

C#:
/// <summary>
    /// Класс получает информацию о разрядности ОС, наличии в системе установленного NodeJS и его версии,
    /// а так же получает ссыль на скачивание актуальной версии соотв. разрядности
    /// </summary>
    public class jsHelper
    {
        public int bitness;
        public const string osBitnessReg = @"\d{2}";
        public string downloadUrl{get;}
        public int installedNodejsVersion;
        public int minVersionNodejs = 122000;
        private string installerDownluadXpath = @"//th[contains(text(), 'Windows Installer (.msi)')]/following-sibling::td/a";
        private string installedNodejsVersionReg = @"(?<=v).*";
        private string getOsBitnessCommand = "/C wmic os get osarchitecture";
        public string getNodeVersionCommand = "/C node -v";
       
        /// <summary>
        /// Конструктор класса. При вызове, получает разрядность системы, проверяет наличие nodejs и его версию, получает сссылки на загрузку инсталлера
        /// </summary>
        /// <param name="hdoc"></param>
        public jsHelper(HtmlAgilityPack.HtmlDocument hdoc)
        {
            #region Get OS bitness
                string request = ZHelper.ZHelperExt.RunSingleCmdReturnToString(this.getOsBitnessCommand);
                bitness = Int32.Parse(Regex.Match(request, osBitnessReg).Value); //OS bitness value — 32 or 64
            #endregion
               
            #region Get nodejs downloadUrl
               
                var nodes = hdoc.DocumentNode.SelectNodes(installerDownluadXpath);
                foreach(var node in nodes)
                {
                    string innerhtml = node.InnerText;
                    int linkBit = Int32.Parse(Regex.Match(innerhtml, osBitnessReg).Value);
                    if(bitness == linkBit)
                    {
                        downloadUrl = node.Attributes["href"].Value;
                    }
                }
               
            #endregion
               
            #region Check is NodeJS installed and get installed version              
               
                request = ZHelper.ZHelperExt.RunSingleCmdReturnToString(this.getNodeVersionCommand);
                if(string.IsNullOrEmpty(request) || request.Substring(0, 1) != "v")
                {
                    installedNodejsVersion = 0;
                   
                }
                else if(!string.IsNullOrEmpty(request) || request.Substring(0, 1) == "v")
                {
                   
                    try
                    {
                        request = Regex.Match(request, installedNodejsVersionReg).Value.Replace(".", "").Trim();
                        if(request.Length == 5) request = request + "0";
                        installedNodejsVersion = Int32.Parse(request);
                       
                    }
                    catch{installedNodejsVersion = 0;}
                }
                else installedNodejsVersion = 0;
            #endregion
        }
    }

В кубике мы делаем get-запрос к странице скачивания NodeJS и передаем полученный html в документ HtmlAgilityPack, создаем экземпляр класса jsHelper (в свойства которого при создании передается разрядность ОС, версия NodeJS если установлен и 0 если нет). В качестве параметра мы передаем в метод документ HtmlAgilityPack, из которого, при создании экземпляра класса, в свойство downloadUrl записывается url для скачивания последней стабильной версии NodeJS нужной разрядности. И далее, если NodeJS не установлен, или его версия ниже требуемой, происходит установка. После завершения установки мы проверяем что установка выполнена:

C#:
#region get page nodejs download
string get = ZennoPoster.HTTP.Request(
                method:ZennoLab.InterfacesLibrary.Enums.Http.HttpMethod.GET,
                url:jsConst.nodejsPageDownloadUrl,
                Encoding:@"UTF-8",
                respType:ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.HeaderAndBody,
                Timeout:30000,
                throwExceptionOnError:true
    );
#endregion


//HtmlAgilityPack new document
HtmlDocument hdoc = new HtmlDocument();
hdoc.LoadHtml(get);

//Create new object JHelper
jsHelper helper = new jsHelper(hdoc);

#region check and install NodeJS
    //Если установленная версия меньше минимальной или если nodejs не установлен, устанавливаем его из url
    if(helper.minVersionNodejs > helper.installedNodejsVersion)
    {
        //setup to default folder (c:\Program Files)
        string workingDir = @"C:\temp\";
        string progName = "msiexec";
        string cmd = string.Format(@" /quiet /i {0}", helper.downloadUrl);
        //if need install nodejs to custom folder
        //string cmd = string.Format(@" /quiet /i {0} INSTALLDIR=F:\Zenno_tmpl\contentor\nodejs", helper.downloadUrl);
        ZHelperExt.RunSomeProgramm(progName, workingDir, cmd);
        project.SendInfoToLog(helper.minVersionNodejs.ToString()+" - "+helper.installedNodejsVersion.ToString(), false);
       
        Thread.Sleep(200);
       
        //check that installation is complete
        string res = ZHelper.ZHelperExt.RunSingleCmdReturnToString(helper.getNodeVersionCommand);
        if(!string.IsNullOrEmpty(res))project.SendInfoToLog(string.Format("Install NodeJS version {0}", res.Trim()), true);
    }
    else
    {
        string res = ZHelper.ZHelperExt.RunSingleCmdReturnToString(helper.getNodeVersionCommand);
        project.SendInfoToLog(string.Format("NodeJS is already installed, NodeJS version = {0}", res.Trim()), true);
    }
#endregion

Вот и все, наш шаблон выполнил установку NodeJS.


УСТАНОВКА NPM-ПАКЕТА READABILITY-CLI

Тут все просто — при установке, NodeJS автоматически подтягивает необходимые для работы модули, в том числе и собственный интерфейс командной строки (доступный из cmd), и менеджер пакетов npm.
Поэтому мы проверяем, установлен ли нужный нам пакет, и если нет, устанавливаем (опять же, с использованием методов статического класса ZHelperExt). Подробную справку по cli-интерфесу NodeJS можно вызвать командой node -h. Кубик установки выглядит так:

C#:
//устанавливаем пакет readability-cli
string cmd = @"/C npm install -g [email protected]";//инсталим не последнюю, а выборочную версию пакета, ключ -g задает глобальную установку пакета
string request = ZHelper.ZHelperExt.RunSingleCmdReturnToString(cmd);
Thread.Sleep(100);

//Проверяем, что установка выполнена успешно
cmd = @"/C readable -V";
request = ZHelper.ZHelperExt.RunSingleCmdReturnToString(cmd);
if(request.Trim().Contains("readability-cli v"))return true;
else throw new Exception("npm pacage is not install");
Теперь в нашем NodeJS стоит пакет, позволяющий очищать html-исходник от информационного мусора и служебных данных.

Весь процесс получения web-страницы, ее подготовки и обработки я показывать не буду, покажу лишь, кубик запроса к NodeJS, для получения очищенного html статьи:

C#:
#region Get current working folder and and the current drive
    string request = ZHelper.ZHelperExt.RunSingleCmdReturnToString("/C cd");
    string folderCurrent = request.Split(new string[]{@"\"}, StringSplitOptions.RemoveEmptyEntries)[0];
    string folderNeeded = project.Variables["FOLDER_page"].Value.Split(new string[]{@"\"}, StringSplitOptions.RemoveEmptyEntries)[0];
#endregion

#region Create list of command to cmd
    List<string> cmd = new List<string>();
    //If the current and desired disks are different
    if(folderCurrent != folderNeeded)
    {
        string mess = string.Format("Current folder disk: {0}; Needed folder disk: {1}", folderCurrent, folderNeeded);
       
        cmd.Add("/C");
        cmd.Add(string.Format("cd /d {0}", project.Variables["FOLDER_page"].Value));
        cmd.Add(string.Format("readable input.html > output.html -p html-title,html-content -b {0}", project.Variables["url"].Value));
    }
    //if the current and desired disks are equal
    else if(folderCurrent == folderNeeded)
    {
        cmd.Add("/C");
        cmd.Add(string.Format("cd {0}", project.Variables["FOLDER_page"].Value));
        cmd.Add(string.Format("readable input.html > output.html -p html-title,html-content -b {0}", project.Variables["url"].Value));
    }
#endregion

Thread.Sleep(500);

#region Send command to cmd and check result
    string result = ZHelper.ZHelperExt.RunListCmdReturnToString(cmd);
    string[] resultArr = result.Split(new string[]{"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
   
    foreach(string str in resultArr)
    {
        string s = str.Trim();
        project.SendInfoToLog(s, false);      
    }

#endregion
Что происходит в кубике:
  • Сначала мы проверяем, соответствует текущий диск диску, в котором находится целевая папка текущей страницы
  • После, создаем список команд, которые будем передавать в cmd:
  • Переходим в папку текущей страницы, в которой лежит html-исходник
  • В строке cmd.Add(string.Format("readable input.html > output.html -p html-title,html-content -b {0}", project.Variables["url"].Value)); указываем readability-cli, что нужно обработать файл input.html и после обработки передать html-title и html-content в файл output.html. C ключом -b передается url страницы, чтобы алгоритмы readability сохранили в атрибутах href и src валидные абслоютные пути.
  • Ну и собственно передаем в cmd список команд на исполнение


ЗАКЛЮЧЕНИЕ

Можно заметить, что мы использовали среду для выполнения js и запускали в ней вполне прикладные задачи совсем не используя JavaScript-код. До того, как остановиться на варианте с cli-интерфейсом, я пытался запустить пакеты с необходимостью написания js, но получалось небыстро и не просто, и как по-мне, cli-вариант совсем не плох, пока не хватает знаний на большее.


ССЫЛКИ

Страница скачивания NodeJS
Репозиторий с npm-пакетами для NodeJS
Страница пакета readability-cli на npmjs.com
Описание всех команд, параметров и ключей принимемых readability-cli на gitlab
Подробную справку по cli-интерфесу NodeJS можно вызвать командой node -h.

P.S. Прилагаемый шаблон написан в версии ZP 7.4.0
 
Тема статьи
Нестандартные хаки
Номер конкурса статей
Семнадцатый конкурс статей

Вложения

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

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

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

zxz27

Client
Регистрация
29.11.2018
Сообщения
35
Благодарностей
17
Баллы
8
Спасибо за статью! А можно версию понизить до 7.3.1.1 ?
 
  • Спасибо
Реакции: semafor

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 624
Благодарностей
1 220
Баллы
113
Прикол. Прямо сегодня днем понадобилось как раз в сторону NodeJS посмотреть. А тут такой подгон в тему )))
 
  • Спасибо
Реакции: semafor

SHILY

Client
Регистрация
05.06.2016
Сообщения
258
Благодарностей
307
Баллы
63
Статья очень даже годная, молодчина!:ay:

Кстати, да, отдельно - HtmlAgilityPack - избыточен, так, как в зенку он уже встроен, если что:al:

C#:
using Global.Zennolab.HtmlAgilityPack;
 

radv

Client
Регистрация
11.05.2015
Сообщения
3 786
Благодарностей
1 951
Баллы
113
Полезная статья, всегда хотел NodeJS попробовать применять для своих целей.
 
  • Спасибо
Реакции: semafor

semafor

Client
Регистрация
27.12.2016
Сообщения
289
Благодарностей
404
Баллы
63
Спасибо за статью! А можно версию понизить до 7.3.1.1 ?
Понизил до 7.2.0. (прикрепил к этому посту)

Прикол. Прямо сегодня днем понадобилось как раз в сторону NodeJS посмотреть. А тут такой подгон в тему )))
Здорово, что так метко вышло )))
Кстати, да, отдельно - HtmlAgilityPack - избыточен, так, как в зенку он уже встроен, если что:al:
Спасибо. А я все по-олдскульному, да )))
 

Вложения

  • Спасибо
Реакции: zxz27 и SHILY

gomoney

Client
Регистрация
27.09.2009
Сообщения
124
Благодарностей
37
Баллы
28
только сегодня идея посетила, а у вас такого же на Pythone нету? )
 
  • Спасибо
Реакции: semafor

SERG454

Client
Регистрация
14.10.2021
Сообщения
145
Благодарностей
143
Баллы
43
  • Спасибо
Реакции: semafor и Брат

Roman*

Client
Регистрация
25.09.2013
Сообщения
1 657
Благодарностей
656
Баллы
113
..."тем самым нанося непоправимый вред тонкой душевной организации многих владельцев Zennoposter " Классно сказано :D :ay:
 
  • Спасибо
Реакции: lzlmrf и semafor

semafor

Client
Регистрация
27.12.2016
Сообщения
289
Благодарностей
404
Баллы
63
только сегодня идея посетила, а у вас такого же на Pythone нету? )
Тут бы с js разобраться...

..."тем самым нанося непоправимый вред тонкой душевной организации многих владельцев Zennoposter " Классно сказано :D :ay:
Ну слов ведь из песни не выбросишь :D
 

ZennoLab Team

Super Moderator
Команда форума
Регистрация
22.01.2019
Сообщения
1 496
Благодарностей
3 744
Баллы
113
Добавлено видео от автора
 
  • Спасибо
Реакции: SHILY и semafor

semafor

Client
Регистрация
27.12.2016
Сообщения
289
Благодарностей
404
Баллы
63
Дошли руки позапускать разные приложения, используя класс Process. Несколько примеров:

Запускаем Memu.
У меня в диспетчере создано несколько виртуалок Memu. Чтобы запустить одну из них, я выполнил код:

C#:
List<string> cmd = new List<string>();
string request = string.Empty;

cmd.Add(@"cd /d D:\Program Files\Microvirt\MEmu");
cmd.Add(@"memuc.exe start -i 1");

using(System.Diagnostics.Process process = new System.Diagnostics.Process())
{
    process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardInput = true;               
    process.Start();
    using (StreamWriter sw = process.StandardInput)
    {
        if (sw.BaseStream.CanWrite)
        {
            foreach(string str in cmd)
            {
                sw.WriteLine(str);
            }
        }
    }
            
    while(!process.HasExited)
    {
        //сохранили ответ cmd
        request += process.StandardOutput.ReadToEnd();     
    }
    
    return request;
}
Где cmd.Add(@"cd /d D:\Program Files\Microvirt\MEmu"); — переход в папку, в которой находится exe-шник MEmuConsole.exe, а cmd.Add(@"memuc.exe start -i 1"); запуск из MEmuConsole.exe виртуалки под номером 1 (там еще есть возможность запускать по имени, но в моей системе оно не заработало).

Запуск Nox.
Так же, имеется несколько виртуалок Nox. Чтобы запустить какую-либо из них по имени — нужно перейти в директорию с Nox.exe и выполнить следующую команду nox.exe "title:NoxPlayer1", где NoxPlayer1 - имя виртуалки:

C#:
List<string> cmd = new List<string>();
string request = string.Empty;

cmd.Add(@"cd C:\Program Files (x86)\Nox\bin");
cmd.Add(@"nox.exe ""title:NoxPlayer1""");

using(System.Diagnostics.Process process = new System.Diagnostics.Process())
{
    process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardInput = true;               
    process.Start();
    using (StreamWriter sw = process.StandardInput)
    {
        if (sw.BaseStream.CanWrite)
        {
            foreach(string str in cmd)
            {
                sw.WriteLine(str);
            }
        }
    }
            
    while(!process.HasExited)
    {
        //сохранили ответ cmd
        request += process.StandardOutput.ReadToEnd();     
    }
    
    return request;
}
 
  • Спасибо
Реакции: GreenWay, SHILY и volody00

seodamage

Client
Регистрация
08.09.2014
Сообщения
224
Благодарностей
67
Баллы
28
я тоже заинтересовался node после статьи @Astraport
какое то время потратил решение вопроса - как поставить ноду в докер контейнер. на данный момент ставлю её в ручнном режиме на впску/ки из интерфейса портейнера. неудобно, хотя достаточно быстро и работает. интересно было почитать спасибо за статью.
 
  • Спасибо
Реакции: semafor

semafor

Client
Регистрация
27.12.2016
Сообщения
289
Благодарностей
404
Баллы
63
я тоже заинтересовался node после статьи @Astraport
какое то время потратил решение вопроса - как поставить ноду в докер контейнер. на данный момент ставлю её в ручнном режиме на впску/ки из интерфейса портейнера. неудобно, хотя достаточно быстро и работает. интересно было почитать спасибо за статью.
Да, докер интересная штука. Пока не погружался, стоит в очереди
 
  • Спасибо
Реакции: seodamage

Sanekk

Client
Регистрация
24.06.2016
Сообщения
999
Благодарностей
389
Баллы
63
отличная тех. статья, однозначно в закладки кину для более подробного изучения:bf:
 
  • Спасибо
Реакции: semafor

semafor

Client
Регистрация
27.12.2016
Сообщения
289
Благодарностей
404
Баллы
63

Zenokiller

Client
Регистрация
06.01.2021
Сообщения
34
Благодарностей
15
Баллы
8
Отличная статья! Приятно читать! Тоже положу в закладки, думаю пригодиться!
 
  • Спасибо
Реакции: semafor

neonb

Пользователь
Регистрация
10.05.2022
Сообщения
35
Благодарностей
15
Баллы
8

Azakim

Client
Регистрация
25.07.2021
Сообщения
166
Благодарностей
31
Баллы
28
Статья очень даже годная, молодчина!:ay:

Кстати, да, отдельно - HtmlAgilityPack - избыточен, так, как в зенку он уже встроен, если что:al:

C#:
using Global.Zennolab.HtmlAgilityPack;
Спасибо за уточнение не знал ,либу постоянно подгружать приходилось
 

nicos77777

Client
Регистрация
04.04.2013
Сообщения
333
Благодарностей
18
Баллы
18
Как быть если кодировка страницы не UTF-8?
 

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