- Регистрация
- 27.12.2016
- Сообщения
- 289
- Благодарностей
- 404
- Баллы
- 63
Всем добра и мира!
Из названия статьи понятно, что мы будем прикручивать к шаблону ZP NodeJS — наш шаблон будет автоматически устанавливать ноду, автоматически устанавливать npm-пакет, с которым будем работать, ну и посылать данные на обработку и получать в ответах результаты. И все это — непосредственно из кода, без всяких батников.
РАЗБОР ТЕМЫ ХОЧЕТСЯ НАЧАТЬ С БЛАГОДАРНОСТЕЙ:
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 (и скорее всего, более медленнная версия). Итак, о функционале:
Чтобы эти либы функционировали, нужно поместить их в папку ExternalAssemblies Zennoposter.
Нелишним будет и небольшой обзор директив using:
ОБЩЕНИЕ С КОМАНДНОЙ СТРОКОЙ ИЗ КОДА C#
Класс Process из сборки System.Diagnostics, позволяет запускать и останавливать любой процесс ОС (т.е. в том числе и исполняемый файл). Используя этот класс, мы будем запускать интерфейс командной строки cmd.exe и выполнять в нем команды, а также запустим инсталятор msi с аргументамми, позволяющими установить NodeJS. Код для вызова командной строки и выполнения команды (например, опредилить битность системы), выглядит вот так:
Данный код позволяет выполнить в cmd однострочную команду, и получить в переменную результат ее выполнения. Здесь в параметр process.StartInfo.FileName мы передаем имя процесса (в нашем случае cmd.exe), а параметру process.StartInfo.Arguments команду, которую нужно выполнить - "/C wmic os get osarchitecture" (вернуть битность ОС), где ключ /C обозначет, что после выполнени команды, процесс должен быть завершен. А как быть если нужно выполнить последовательность команд? Решение имеется:
Так как общения с cmd в шабе дофига, я создал в общем коде статический класс, и запихал все это хозяйство туда, см. сборку ZHelper. Там же добавлен метод, позволяющий запустить инсталлер msi(а в принципе, любой процесс Windows), и передать ему в качестве аргумента команду установить NodeJS из указанного url:
УСТАНОВКА NODEJS ИЗ ШАБЛОНА
Что нам нужно, чтобы установить NodeJS:
В кубике мы делаем get-запрос к странице скачивания NodeJS и передаем полученный html в документ HtmlAgilityPack, создаем экземпляр класса jsHelper (в свойства которого при создании передается разрядность ОС, версия NodeJS если установлен и 0 если нет). В качестве параметра мы передаем в метод документ HtmlAgilityPack, из которого, при создании экземпляра класса, в свойство downloadUrl записывается url для скачивания последней стабильной версии NodeJS нужной разрядности. И далее, если NodeJS не установлен, или его версия ниже требуемой, происходит установка. После завершения установки мы проверяем что установка выполнена:
Вот и все, наш шаблон выполнил установку NodeJS.
УСТАНОВКА NPM-ПАКЕТА READABILITY-CLI
Тут все просто — при установке, NodeJS автоматически подтягивает необходимые для работы модули, в том числе и собственный интерфейс командной строки (доступный из cmd), и менеджер пакетов npm. Поэтому мы проверяем, установлен ли нужный нам пакет, и если нет, устанавливаем (опять же, с использованием методов статического класса ZHelperExt). Подробную справку по cli-интерфесу NodeJS можно вызвать командой node -h. Кубик установки выглядит так:
Теперь в нашем NodeJS стоит пакет, позволяющий очищать html-исходник от информационного мусора и служебных данных.
Весь процесс получения web-страницы, ее подготовки и обработки я показывать не буду, покажу лишь, кубик запроса к NodeJS, для получения очищенного html статьи:
Что происходит в кубике:
ЗАКЛЮЧЕНИЕ
Можно заметить, что мы использовали среду для выполнения 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
Из названия статьи понятно, что мы будем прикручивать к шаблону ZP NodeJS — наш шаблон будет автоматически устанавливать ноду, автоматически устанавливать npm-пакет, с которым будем работать, ну и посылать данные на обработку и получать в ответах результаты. И все это — непосредственно из кода, без всяких батников.
РАЗБОР ТЕМЫ ХОЧЕТСЯ НАЧАТЬ С БЛАГОДАРНОСТЕЙ:
- @Astraport — за появление NodeJS в моем поле зрения (прочитав именно его статью, я сделал себе заметку о необходимости потыкать палочкой этот инструмент)
- @Lord_Alfred за идею (Универсальный экстрактор контента) с использованием readability библиотеки, а так же за офигенные снипеты для очистки контента, проверки ответов на get-запросы, адские регулярки и все остальное, что присутствует в шаблоне, прикрепленном к указанной статье. Множество решений из нее не однажды использовал.
- @marsht за замечательную статью о JS
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 информации о полученных материалах (можно было и сами материалы туда же, но решил не заморачиваться)
- HtmlAgilityPack. Очень люблю эту либу за огромные возможности при парсинге (отдельно за отсутствие глюков при обработке всевозможных кастомных атрибутов, с которыми натерпелся при использовании штатных возможностей ZP). В принципе, она избыточна здесь, но выпиливать ее не стал.
- System.Data.SQLite - библиотека для работы с БД SQLite
- Dapper, Dapper.Contrib — либы, позволяющие пользовать ОРМ Dapper, о них я писал в прошлом конкурсе статей — MySQL, SQLite.
Чтобы эти либы функционировали, нужно поместить их в папку 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. Подробности далее.
ОБЩЕНИЕ С КОМАНДНОЙ СТРОКОЙ ИЗ КОДА 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();
}
}
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();
}
}
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-пакета
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");
Весь процесс получения 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
- Тема статьи
- Нестандартные хаки
- Номер конкурса статей
- Семнадцатый конкурс статей
Вложения
-
1,1 МБ Просмотры: 182
Для запуска проектов требуется программа ZennoPoster или ZennoDroid.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...
Для того чтобы запустить шаблон, откройте нужную программу. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.
Последнее редактирование модератором: