Тот, кто занимался вэб программированием, знает, как удобно использовать JQuery и CSS селекторы. На .Net написана очень удобная библиотека AngleSharp.
Я покажу, как с её помощью можно значительно облегчить себе труд.
Это продолжение статьи .Net в 1С. Примеры использования HTTPClient,AngleSharp. Асинхронные HTTP запросы, отправка Post нескольких файлов multipart/form-data,сжатие трафика с использованием gzip, deflate,удобный парсинг сайтов итд
https://github.com/AngleSharp/AngleSharp это .Net библиотека для разбора HTML файлов в стиле CSS селекторов, аналогично использованию JQuery. Которая также поддерживает CSS и JavaScript. Но библиотека поддержки JavaScript пока плющевая и давно не обновлялась https://github.com/AngleSharp/AngleSharp.Scripting
На первой же странице есть пример получения названий всех серий сериала "Теория большого взрыва"
// устанавливаем параметры для использования разбора документа
var config = Configuration.Default.WithDefaultLoader();
// Устанавливаем адрес страницы сайта
var address = "https://en.wikipedia.org/wiki/List_of_The_Big_Bang_Theory_episodes";
// загружаем страницу и разбираем её
var document = await BrowsingContext.New(config).OpenAsync(address);
// Используем CSS селектор для получения строк таблицы с классом и выбрать из этой строки 3 колонку
var cellSelector = "tr.vevent td:nth-child(3)";
// Получим все ячейки
var cells = document.QuerySelectorAll(cellSelector);
//Выделим из ячеек текстовое содержимое
var titles = cells.Select(m => m.TextContent);
Красиво, не правда ли?
На 1С это будет выглядеть так
config = AngleSharp_Configuration;
Расширение=Врап.ПолучитьТип("AngleSharp.ConfigurationExtensions");
config =Расширение.WithDefaultLoader(config);
// Load the names of all The Big Bang Theory episodes from Wikipedia
address = "https://en.wikipedia.org/wiki/List_of_The_Big_Bang_Theory_episodes";
// Asynchronously get the document in a new context using the configuration
document = Врап.ПолучитьТип("AngleSharp.BrowsingContext").New(config);
BrowsingContextExtensions=Врап.ПолучитьТип("AngleSharp.BrowsingContextExtensions");
document =BrowsingContextExtensions.OpenAsync(document,address).Result;
// This CSS selector gets the desired content
cellSelector = "tr.vevent td:nth-child(3)";
// Perform the query to get all cells with the content
cells = document.QuerySelectorAll(cellSelector);
// We are only interested in the text - select it with LINQ
Для каждого стр Из cells Цикл
Сообщить(стр.TextContent)
КонецЦикла;
В предыдущей статье я уже показывал описание
Но повторю
// Сборку AngleSharp.dll поместить в каталог программы
//Для использования Scripting Api
КатаогПрограммы=Врап.ПолучитьТип("System.AppDomain").CurrentDomain.BaseDirectory;
ИмяСборкиAngleSharp=Врап.ПолучитьТип("System.IO.Path").Combine(КатаогПрограммы,"AngleSharp.dll");
AngleSharp_Configuration=Врап.ПолучитьТипИзСборки("AngleSharp.Configuration",ИмяСборкиAngleSharp);
parser = Врап.СоздатьОбъект("AngleSharp.Parser.Html.HtmlParser");
AngleSharp.dll можно поместить в любое место, но для динамической компиляции нужно, чтобы библиотека находилась в домене приложения(КаталогПрограммы). Об этом в конце статьи. Про CSS селекторы и их использование можно почитать здесь
http://anton.shevchuk.name/javascript/jquery-for-beginners-selectors
http://htmlbook.ru/css/nth-child
https://learn.javascript.ru/css-selectors
https://habrahabr.ru/post/51717/
http://webknowledge.ru/slozhnye-css-selektory-soderzhaschie-klass-i-id-elementov/
Теперь посмотрим, как можно получить тот же результат, но с использованием HTTPClient, и заполним данные в таблице
stopWatch = Врап.СоздатьОбъект("System.Diagnostics.Stopwatch");
stopWatch.Start();
Client = Врап.СоздатьОбъект(HttpClient);
Client.BaseAddress = Врап.СоздатьОбъект("System.Uri","https://en.wikipedia.org");
res = Client.GetStringAsync("wiki/List_of_The_Big_Bang_Theory_episodes").Result;
parser = Врап.СоздатьОбъект("AngleSharp.Parser.Html.HtmlParser");
//Just get the DOM representation
document = parser.Parse(res);
СелекторСтроки = "tr.vevent";
Тз=новый ТаблицаЗначений;
Колонки=Тз.Колонки;
Колонки.Добавить("НомерСерии");
Колонки.Добавить("НомерСерииВСезоне");
Колонки.Добавить("Название");
Колонки.Добавить("Режиссер");
Колонки.Добавить("Автор");
Колонки.Добавить("Дата");
Колонки.Добавить("Код");
Колонки.Добавить("Просмотров");
Строки =document.QuerySelectorAll(СелекторСтроки);
stopWatch.Stop();
Сообщить("Скачка и парсинг");
ВывестиВремя(stopWatch,истина);
stopWatch.Restart();
Для Каждого стр из Строки Цикл
сч=0;
стрТз=Тз.Добавить();
Ячейки=стр.Cells;
Для каждого Ячейка из Ячейки Цикл
стрТз[сч]=Ячейка.TextContent;
сч=сч+1;
Если сч=8 Тогда
прервать
КонецЕсли;
КонецЦикла
КонецЦикла;
stopWatch.Stop();
Сообщить("Время выполнения =");
ВывестиВремя(stopWatch,истина);
Тз.ВыбратьСтроку();
Все прекрасно. Но меня ждало разочарование. Заполнение составляло 8 секунд. Решение я нашел. Но об этом попозже.
Надо отметить, что QuerySelectorAll и QuerySelector можно применять к контейнерам поддерживающих интерфейс
public interface IParentNode
{
int ChildElementCount { get; }
IHtmlCollection<IElement> Children { get; }
IElement FirstElementChild { get; }
IElement LastElementChild { get; }
void Append(params INode[] nodes);
void Prepend(params INode[] nodes);
IElement QuerySelector(string selectors);
[DomName("querySelectorAll")]
IHtmlCollection<IElement> QuerySelectorAll(string selectors);
}
}
Мы можем например задать селектор для строки. Например получить первый и третий элемент строки
Строки =document.QuerySelectorAll(СелекторСтроки);
Для Каждого стр из Строки Цикл
//Ячейки=стр.Cells;
Ячейки=стр.QuerySelectorAll("th:nth-child(1),td:nth-child(3)");
Для каждого Ячейка из Ячейки Цикл
стрТз[сч]=Ячейка.TextContent;
КонецЦикла
КонецЦикла;
Добавлю еще про коллекци.
public interface IHtmlCollection<T> : IEnumerable<T>, IEnumerable where T : IElement
{
T this[int index] { get; }
T this[string id] { get; }
int Length { get; }
}
К ним можно обращаться по номерe и по ID или атрибуту. Например
Строки =document.QuerySelectorAll(СелекторСтроки);
ВтораяСтрока=Строки.get_Item(1);
Пока покажу, как использовать селекторы. Возьмем ту же страницу, но выделим только ссылки на серии.
Client.BaseAddress = Врап.СоздатьОбъект("System.Uri","https://en.wikipedia.org");
res = Client.GetStringAsync("wiki/List_of_The_Big_Bang_Theory_episodes").Result;
document = parser.Parse(res);
СелекторСтроки = "li.toclevel-2>a";
Строки =document.QuerySelectorAll(СелекторСтроки);
// Получим селекторы аннотации выделим текст и Хэш ссылку
Для Каждого стр из Строки Цикл
Сообщить(Стр.TextContent + " "+стр.Hash);
КонецЦикла;
Теперь попробуем использовать форму поиска
Форма=document.QuerySelector("form#searchform");
ссылка= Форма.Action;
структура=новый структура;
Для каждого Элемент Из Форма.Elements Цикл
Элем=Врап.ПолучитьИнтерфейс(Элемент,"IHtmlInputElement");
//Нужны только Input элементы
//Выберем все элементы Input
// и запишем их имена и значения
Если Элем<> Неопределено Тогда
структура.Вставить(Элем.Name,Элем.Value);
Сообщить(Элем.Name+"="+Элем.Value);
КонецЕсли;
КонецЦикла;
структура.search="Кириллица";
// Если удалить fulltext то произойдет Redirect
// структура.Удалить("fulltext");
Врап.ВСтроку(Элемент);
сб=Врап.СоздатьОбъект(StringBuilder,ссылка+"?");
//var uri = new Uri(builder.ToString(), dontEscape: true);
// Создадим строку запроса. Для метода Get
// так как Форма.Method=""
Для каждого стр Из структура Цикл
сб.AppendFormat("{0}={1}&",HttpUtility.UrlPathEncode(стр.Ключ),HttpUtility.UrlPathEncode(стр.Значение),0);
КонецЦикла;
стр=сб.ToString(0,сб.Length-1);
Сообщить(стр);
//Сделаем запрос по относительному пути
//Так как основной путь уже прописан в BaseAddress
res = Client.GetStringAsync(стр).Result;
// Посмотрим результат
// Можно посмотреть страницу используя например
//http://filyanin.ru/8-vizualnyy-HTML-onlayn-redaktor.html
Текст=Новый ТекстовыйДокумент;
Текст.УстановитьТекст(res);
Текст.Показать();
document = parser.Parse(res);
// Найдем результаты поиска по пути
// ul с классом mw-search-results в первом потомке li и в первом потомке div и а
CSSСелектор = "ul.mw-search-results>li>div>a";
Строки =document.QuerySelectorAll(CSSСелектор);
Для Каждого стр из Строки Цикл
Сообщить(Стр.TextContent + " "+Стр.PathName);
КонецЦикла;
Очень часто приходится искать информацию на сайтах с авторизацией. При этом поля формы содежат дополнительные поля для верификации.
Вот пример поиска нужного значения.
var configuration = Configuration.Default.WithDefaultLoader().WithCookies();
var context = BrowsingContext.New(configuration);
// откромем начальную страницу
await context.OpenAsync(WebsiteUrl);
// Найдем ссылку содержашуюся в элементе a и классом log-in
await context.Active.QuerySelector<IHtmlAnchorElement>("a.log-in").Navigate();
// Установим элементам формы нужное значение и вызовем Submit
await context.Active.QuerySelector<IHtmlFormElement>("form").Submit(new
{
User = "User",
Password = "secret"
});
// Опять найдем нужную ссылку и перейдем на страницу с искомым значением
await context.Active.QuerySelector<IHtmlAnchorElement>("a.secret-link").Navigate();
// Получим это искомое значение
Теперь перепишем все это с использованием HTTPClient
Клиент = Врап.СоздатьОбъект(HttpClient);
Клиент.BaseAddress = Врап.СоздатьОбъект("System.Uri",WebsiteUrl);
// Стоит отметить, что по умолчанию HttpClient использует Cookie
//Загрузим основную страницу
res = Клиент.GetStringAsync("").Result;
document = parser.Parse(res);
// Найдем адрес страницы для авторизации
Аннотация= document.QuerySelector("a.log-in");
//Полный относительный путь Аннотация.PathName+Аннотация.Search
// Но в данном случае Аннотация.Search просто нет
// Если использовать BrowsingContext то полный путь содержится в Href
res= Клиент.GetStringAsync(Аннотация.PathName).Result;
document = parser.Parse(res);
// Найдем элемент form для авторизации
//В которой есть поле для верификации __RequestVerificationToken
Форма=document.QuerySelector("form");
Сообщить(Форма.Method);
d = Врап.СоздатьОбъект(Dictionary);
Для каждого Элемент Из Форма.Elements Цикл
Элем=Врап.ПолучитьИнтерфейс(Элемент,"IHtmlInputElement");
//Нужны только Input элементы
//Выберем все элементы Input
// и запишем их имена и значения в словарь
Если Элем<> Неопределено Тогда
d.Add(Элем.Name, Элем.Value);
Сообщить(Элем.Name+"="+Элем.Value);
КонецЕсли;
КонецЦикла;
d.set_Item("User", "User");
d.set_Item("Password", "secret");
Контент=Врап.СоздатьОбъект(FormUrlEncodedContent,d);
// Отправим пост запрос с данными формы по адресу находящемся в Action
резулт=Клиент.PostAsync(Форма.Action,Контент).Result;
// И получим ответ
res=резулт.Content.ReadAsStringAsync().Result;
document = parser.Parse(res);
// Найдем на этой странице ссылку на секретную страницу
Аннотация= document.QuerySelector("a.secret-link");
res= Клиент.GetStringAsync(Аннотация.PathName).Result;
document = parser.Parse(res);
// Получим из первого параграфа искомое значение
Сообщить(document.QuerySelector("p").TextContent)
В C# есть удобный сахар в виде расширений. Например, код
Configuration.Default.WithDefaultLoader().WithCookies();
//На самом деле представляет собой
var configuration = AngleSharp.Configuration.Default;
configuration=AngleSharp.ConfigurationExtensions.WithDefaultLoader(configuration);
configuration = AngleSharp.ConfigurationExtensions.WithCookies(configuration);
// Так как функция WithDefaultLoader представляет функцию расширения
// так как первый параметр помечен как this
// Что позволяет использовать этот метод через точку
public static IConfiguration WithDefaultLoader(this IConfiguration configuration, Action<LoaderService> setup = null, IEnumerable<IRequester> requesters = null);
Кроме того, используются дженерик функции. Я покажу, как с этим бороться.
Но, к сожалению, красивый код на C# превращается в монстра на 1С. Но зато есть примеры, как с этим бороться
/Получить типизированную дженерик функцию
//TElement QuerySelector<TElement>(this IParentNode parent, string selectors)
Функция ПолучитьДжененрикМетодИнфо(тип,ИмяМетода,типПараметра)
method = Врап.ТипКакОбъект(тип).GetMethod(ИмяМетода);
generic = method.MakeGenericMethod(типПараметра);
return generic;
КонецФункции
// Когда есть перегрузка методов нужно искать метод по имени и типам параметров
// Task<IDocument> Navigate<TElement>(this TElement element)
// string Text<T>(this T element)
Функция ПолучитьМетодИнфоОдинДженерикТип(тип,ИмяМетода,типПараметра)
Для Каждого m in Врап.ТипКакОбъект(тип).GetMethods() Цикл
параметры = m.GetParameters();
if (m.Name = ИмяМетода)
И (параметры.Length = 1)
И (Врап.ТипКакОбъект(параметры.GetValue(0).ParameterType).IsGenericParameter)
Тогда
method = m;
break;
КонецЕсли
КонецЦикла;
generic = method.MakeGenericMethod(типПараметра);
return generic;
КонецФункции
Функция ПолучитьМетодИнфо(тип,ИмяМетода)
method = Врап.ТипКакОбъект(тип).GetMethod(ИмяМетода);
return method;
КонецФункции
Функция ПолучитьПропертиИнфо(тип,ИмяСвойства)
свойство = Врап.ТипКакОбъект(тип).GetProperty(ИмяСвойства);
return свойство;
КонецФункции
Функция ПолучитьМетодИнфо2Параметра(тип,ИмяМетода)
Для Каждого m in Врап.ТипКакОбъект(тип).GetMethods() Цикл
параметры = m.GetParameters();
if (m.Name = ИмяМетода)
И (параметры.Length = 2)
Тогда
method = m;
break;
КонецЕсли
КонецЦикла;
return method;
КонецФункции
Функция Получить_SBAppend()
Для Каждого m in Врап.ТипКакОбъект(StringBuilder).GetMethods() Цикл
параметры = m.GetParameters();
if ( (m.Name = "Append")
И (параметры.Length = 1)
И (Врап.ТипКакОбъект(параметры.GetValue(0).ParameterType).Equals(String)))
Тогда
возврат m
КонецЕсли
КонецЦикла;
возврат Неопределено
КонецФункции
Процедура AngleSharpFormНажатие(Элемент)
// Вставить содержимое обработчика.
ПутьКСборке="d:Vs2024ProgramsTestScriptingAPITestScriptingAPIinDebugAngleSharp.dll";
WebsiteUrl = "http://localhost:54361";
// Получим используемые типы
AngleSharp_ConfigurationExtensions = Врап.ПолучитьТип("AngleSharp.ConfigurationExtensions");
BrowsingContext = Врап.ПолучитьТип("AngleSharp.BrowsingContext");
BrowsingContextExtensions = Врап.ПолучитьТип("AngleSharp.BrowsingContextExtensions");
ApiExtensions = Врап.ПолучитьТип("AngleSharp.Extensions.ApiExtensions");
// Получим типы нужных интерфейсов
IHtmlAnchorElement = Врап.ПолучитьТип("AngleSharp.Dom.Html.IHtmlAnchorElement");
IHtmlFormElement = Врап.ПолучитьТип("AngleSharp.Dom.Html.IHtmlFormElement");
IElement=Врап.ПолучитьТип("AngleSharp.Dom.IElement");
// Получим типизированные функции
QuerySelector_AnchorElement = ПолучитьДжененрикМетодИнфо(ApiExtensions, "QuerySelector",IHtmlAnchorElement);
QuerySelector_FormElement = ПолучитьДжененрикМетодИнфо(ApiExtensions, "QuerySelector",IHtmlFormElement);
ApiExtensions_Navigate=ПолучитьМетодИнфоОдинДженерикТип(ApiExtensions,"Navigate",IHtmlAnchorElement);
ApiExtensions_Text= ПолучитьМетодИнфоОдинДженерикТип(ApiExtensions,"Text",IElement);
configuration = Configuration.Default;
configuration = AngleSharp_ConfigurationExtensions.WithDefaultLoader(configuration);
configuration = AngleSharp_ConfigurationExtensions.WithCookies(configuration);
context = BrowsingContext.New(configuration);
// Загрузим начальную страницу
BrowsingContextExtensions.OpenAsync(context, WebsiteUrl).Wait();
doc = context.Active;
// Получим ссылку содержащий адрес страницы для авторизации
//<a class="log-in" href="/Home/LogIn">log in here</a>
HtmlAnchorElement = Врап.MethodInfo_Invoke(QuerySelector_AnchorElement,Неопределено,doc, "a.log-in");
// var HtmlAnchorElement = AngleSharp.Extensions.ApiExtensions.QuerySelector<AngleSharp.Dom.Html.IHtmlAnchorElement>(doc, "a.log-in");
// И перейдем на страницу авторизации
// doc = ApiExtensions.Navigate(HtmlAnchorElement).Result;
doc = Врап.MethodInfo_Invoke(ApiExtensions_Navigate,Неопределено,HtmlAnchorElement).Result;
// doc = context.Active;
// Получим форму
//скрытый элемент для верификации который нужно отправить
//<input name="__RequestVerificationToken" type="hidden" value="2Y-sFIY9JBZc6wc7antGFsBPG1GoiYCbVDtS0khv3JRkcG8CuN69pS3tAZrSiTevGkBjzpTF9AnuK8tZEUrjqn4qB_lbF4dVxsQBubYZkck1">
HtmlFormElement = Врап.MethodInfo_Invoke(QuerySelector_FormElement,Неопределено,doc, "form");
// var HtmlFormElement = AngleSharp.Extensions.ApiExtensions.QuerySelector<AngleSharp.Dom.Html.IHtmlFormElement>(doc, "form");
d = Врап.СоздатьОбъект(Dictionary);
d.Add("User", "User");
d.Add("Password", "secret");
// Авторизуемся установив нужные поля и отправим Post запрос на сервер
ApiExtensions.Submit(HtmlFormElement, d).Wait();
doc = context.Active;
// получим ссылку на искомую страницу
//<a class="secret-link" href="/Home/Secret">our secret</a>
HtmlAnchorElement = Врап.MethodInfo_Invoke(QuerySelector_AnchorElement,null, doc, "a.secret-link");
// HtmlAnchorElement = AngleSharp.Extensions.ApiExtensions.QuerySelector<AngleSharp.Dom.Html.IHtmlAnchorElement>(doc, "a.secret-link");
// Перейдем по ссылке
// doc = ApiExtensions.Navigate(HtmlAnchorElement).Result;
doc = Врап.MethodInfo_Invoke(ApiExtensions_Navigate,null,HtmlAnchorElement).Result;
// В первом селекторе параграфе лежит искомая строка
//<p>The answer to everything is <span id="secret">42</span>.</p>
селектор=doc.QuerySelector("p");
резулт = Врап.MethodInfo_Invoke(ApiExtensions_Text,null,селектор);
// резулт =The answer to everything is 42
Сообщить(резулт);
КонецПроцедуры
Одним из удобных способов это использовать
https://github.com/dotnet/roslyn
https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples
Для использования Scripting-API создал сборку. Проинсталлировал
Install-Package Microsoft.CodeAnalysis.Scripting Создал класс
namespace ScriptApiDlls
{
public class КлассДляВычесленияВыражений
{
public static Microsoft.CodeAnalysis.Scripting.ScriptOptions Опции { get { return Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default; } }
public static object Вычислить(string Код, Microsoft.CodeAnalysis.Scripting.ScriptOptions опции )
{
return Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync(Код, опции).Result;
}
}
}
И теперь можно с удобством использовать код, написанный на C#.
Для использования DLL не из GAC их нужно поместить в домен приложения. В данном случае это каталог программы.
врап=новый COMОбъект("NetObjectToIDispatch45");
КлассДляВычесленияВыражений=Врап.ПолучитьТипИзСборки("ScriptApiDlls.КлассДляВычесленияВыражений",ПутьКДлл+"ScriptApiDlls.dll");
Опции=КлассДляВычесленияВыражений.Опции;
Катаог=Врап.ПолучитьТип("System.AppDomain").CurrentDomain.BaseDirectory;
ИмяСборкиAngleSharp=Врап.ПолучитьТип("System.IO.Path").Combine(Катаог,"AngleSharp.dll");
СтрокаКода = "string WebsiteUrl = ""http://localhost:54361"";
|var configuration = Configuration.Default.WithDefaultLoader().WithCookies();
| var context = BrowsingContext.New(configuration);
| context.OpenAsync(WebsiteUrl).Wait();
|
| var elem=context.Active.QuerySelector<IHtmlAnchorElement>(""a.log-in"");
| if (elem==null) return context.Active.Body.InnerHtml;
| elem.Navigate().Wait();
| context.Active.QuerySelector<IHtmlFormElement>(""form"").Submit(new
| {
| User = ""User"",
| Password = ""secret""
| }).Wait();
|context.Active.QuerySelector<IHtmlAnchorElement>(""a.secret-link"").Navigate().Wait();
|
|return context.Active.QuerySelector(""p"").Text();
|";
scr = Опции
.WithReferences(ИмяСборкиAngleSharp)
.WithImports("System","AngleSharp","AngleSharp.Dom.Html","AngleSharp.Extensions");
резулт = КлассДляВычесленияВыражений.Вычислить(СтрокаКода,scr);
Сообщить(резулт);
А сейчас я расскажу, как можно значительно ускорить процесс использования AngleSharp. Вообще скорость вызовов методов через обертку составляет порядка 20 000 вызовов методов в секунду. Но дело в том, что все классы в библиотеке являются не публичными, передаются только интерфейсы. И вот здесь при передаче ссылок .Net начинает тормозить. Но решение было найдено через использование типизированных коллекций и использование PropertyInfo
stopWatch = Врап.СоздатьОбъект("System.Diagnostics.Stopwatch");
stopWatch.Start();
Client = Врап.СоздатьОбъект(HttpClient);
Client.BaseAddress = Врап.СоздатьОбъект("System.Uri","https://en.wikipedia.org");
res = Client.GetStringAsync("wiki/List_of_The_Big_Bang_Theory_episodes").Result;
parser = Врап.СоздатьОбъект("AngleSharp.Parser.Html.HtmlParser");
//Just get the DOM representation
document = parser.Parse(res);
СелекторСтроки = "tr.vevent";
Тз=новый ТаблицаЗначений;
Колонки=Тз.Колонки;
Колонки.Добавить("НомерСерии");
Колонки.Добавить("НомерСерииВСезоне");
Колонки.Добавить("Название");
Колонки.Добавить("Режиссер");
Колонки.Добавить("Автор");
Колонки.Добавить("Дата");
Колонки.Добавить("Код");
Колонки.Добавить("Просмотров");
Строки =document.QuerySelectorAll(СелекторСтроки);
stopWatch.Stop();
Сообщить("Скачка и парсинг");
ВывестиВремя(stopWatch,истина);
Dom_INode=Врап.ПолучитьТип("AngleSharp.Dom.INode");
TextContentСвойство=ПолучитьПропертиИнфо(Dom_INode,"TextContent");
IHtmlTableRowElement=Врап.ПолучитьТип("AngleSharp.Dom.Html.IHtmlTableRowElement");
ЯчейкиТаблицыСвойство=ПолучитьПропертиИнфо(IHtmlTableRowElement,"Cells");
IEnumerator=Врап.ПолучитьТип("System.Collections.IEnumerator");
CurrentСвойство=ПолучитьПропертиИнфо(IEnumerator,"Current");
stopWatch.Restart();
// Строки=Врап.МассивИзЭнумератора(Строки,IHtmlTableRowElement);//Врап.ПолучитьПеречислитель(строки);
Строки=Врап.ПолучитьТипизированныйПеречислитель(Строки,IHtmlTableRowElement);
Для каждого стр из Строки Цикл
сч=0;
стрТз=Тз.Добавить();
Ячейки=ЯчейкиТаблицыСвойство.GetValue(стр);//Ячейки=стр.Cells;
//Ячейки=Врап.МассивИзЭнумератора(Ячейки,Dom_INode);
Ячейки=Врап.ПолучитьТипизированныйПеречислитель(Ячейки,Dom_INode);
Для каждого Ячейка из Ячейки Цикл
стрТз[сч]=TextContentСвойство.GetValue(Ячейка);//Ячейка.TextContent;
сч=сч+1;
Если сч=8 Тогда
прервать
КонецЕсли;
КонецЦикла
КонецЦикла;
stopWatch.Stop();
Сообщить("Время выполнения =");
ВывестиВремя(stopWatch,истина);
Тз.ВыбратьСтроку();
Используя MetodInfo, тоже можно ускорить процесс процентов на 20%.
stopWatch = Врап.СоздатьОбъект("System.Diagnostics.Stopwatch");
КоличествоИтераций=20000;
stopWatch.Start();
StringBuilder_Append=Получить_SBAppend();
StringBuilder_ToString=ПолучитьМетодИнфо2Параметра(StringBuilder,"ToString");
стр="";
НачВремя=ТекущаяДата();
stopWatch.Restart();
SB = врап.СоздатьОбъект("System.Text.StringBuilder");
Для сч=1 по КоличествоИтераций Цикл
// SB.Append(Строка(сч));
Врап.MethodInfo_Invoke(StringBuilder_Append,SB,Строка(сч));
КонецЦикла;
stopWatch.Stop();
стр=SB.ToString();
Сообщить(СтрДлина(стр));
ВывестиВремя(stopWatch,истина);
stopWatch.Restart();
SB2 = врап.СоздатьОбъект("System.Text.StringBuilder");
Для сч=0 по SB.Length-1 Цикл
//SB2.Append(SB.ToString(сч,1));
Врап.MethodInfo_Invoke(StringBuilder_Append,SB2,Врап.MethodInfo_Invoke(StringBuilder_ToString,SB,сч,1));
КонецЦикла;
stopWatch.Stop();
стр=SB2.ToString();
Сообщить(СтрДлина(стр));
Сообщить("Время выполнения =");
ВывестиВремя(stopWatch,истина);
Картинки = doc.QuerySelectorAll("img[src]");
Для каждого стр из Картинки Цикл
адрес=Врап.ПолучитьИнтерфейс(стр,"IElement").GetAttribute("src");
КонецЦикла
Так же приеры использования AngleSharp на .Net Core есть здесь
Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux II
и здесь
Благодарю всех, кто дошел до конца. Надеюсь, мои труды вам пригодятся.
Я уже не буду перегружать статью. Но можно использовать скрипты для заполнения данных 1С
Показать
(1) классные статьи, тоже интересная.
Но есть парочку НО:
1. Материал подается в неудобочитаемом виде.
2. Мало практических примером, близких к реальности.
ИМХО. Без обид.
(2) Спасибо. Может подкинешь идею? Могу в свободное время взяться за конкретный пример или кому то помочь с реальной задачей
(3) я был бы рад увидеть статью про валидаторы данных применительно к 1с, особенно приятно если бы это получилось хорошо. Понимаю что тема большая, но хоть что то. Вот например по этой тематикеhttps://habrahabr.ru/post/246521/
(4) Да уж. Можно смотреть на валидаторы внутри ASP.Net MVC. Там генерятся валидаторы как на JavaScript так и на уровне HTML5
http://stephenwalther.com/archive/2012/03/13/html5-form-validation
(5) У тебя по ссылке валидация форм, хотя хотелось бы иметь валидацию произвольных данных. На входе — произвольный набор проверяемых данных и правила которым он должен удовлетворять. На выходе — ошибки, если есть. Если ошибок нет — валидация прошла успешно. Например, ты грузишь что то из какого нибудь excel или внешней базы и надо чтобы данные удовлетворяли определенным условиям. Часто фарш в данных обнаруживается значительно позднее чем мог бы.
Это из области парсеровhttps://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D 1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0
(7) Это была идея для статьи чтобы не придумывать велосипед, а взять готовый на NET, если такой существует.
(8) Они существуют. Только не универсальные. XML, HTML, C# итд.
Что касается LIVR то прочтяhttps://github.com/koorchik/LIVR вроде как на .Net нет библиотеки
Вот пример парсинга мисты
Показать
Обратите внимание
(3) можно написать обработку, которая сжимает или приводит к одному виду изображения в базе с помощью средств .NET платформы, да еще и Parallel прикрутить для ускорения.
Еще было бы интересно рассказать про стандартные возможности .NET’а слежения за изменением в каталоге, передача файлов по сети с помощью фоновой интеллектуальной службы BITS (Windows).
Может об этом уже писали конечно, не искал специально.
(14) Большое спасибо за совет.
.NET(C#) для 1С. Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия
Там есть подписка на события System.IO.FileSystemWatcher
Насчет картинок была статья ElisyОбработка изображений 1С средствами .Net framework
http://www.forum.mista.ru/topic.php?id=758131&page=3#229
Строка в дату. Универсальное решение. Применение NetObjetToIDispatch45
http://www.forum.mista.ru/topic.php?id=763810&page=1
Я на мисте предлагал
Но как то мало это народ интересует.
Нужны какие то простые, но понятные примеры типа
Например больше всего популярностью пользуетсяИспользование классов .Net в 1С для новичков
Главное заинтересовать, а там дальше пойдет.
Еще один пример парсинга
Показать
Подскажите, пожалуйста, где взять файл AngleSharp.dll?
(17)http://files.rsdn.ru/19608/AndleSharpScriptDlls.zip
Но за версиями лучше следить здесьhttps://www.nuget.org/packages/AngleSharp/
https://anglesharp.github.io/
Кстати новая версия вышла. Проверю. Обновил
Спасибо! А то скачал сборку с Гитхаба, а как ее использовать не понял..
В составе AngleSharp.Scripting для парсинга сайтов с использованием JS
https://github.com/AngleSharp/AngleSharp/wiki/Examples
Есть парсер
https://github.com/sebastienros/jint
Вот пример использования
Показать
Можно передавать свои объекты и и использовать их при выполнении скриптов . Пример на C#
Показать
Проверил работают такие конструкции поиска
Поиск div с id начинающихся на «row»
Найти аннотацию с классом pagenav и содеращую текст ‘Вперёд’
Я бы еще добавил Silenium прежде всего как построитель DOM в заскриптованных таблицахhttp://www.seleniumhq.org/docs/05_selenium_rc.jsp#c
http://scraping.pro/example-of-scraping-with-selenium-webdriver-in-csharp/
Для того что бы добраться до сформированного DOM можно использовать вместо PageSource
вычисляемый скрипт
var pageSource = (string)driver.ExecuteScript(«return document.body.outerHTML»);
Для получения атрибута нужно применить следующий код
Сергей, подскажите плиз, что не так в этом коде?
Объекты HttpClient и HttpRequestMessage создаются.
А дальше нужно добавить к запросу Method и RequestUri — это не получается.
(В C# аналогичный код работает)
ХТТПЗапрос.RequestUri = Врап.СоздатьОбъект(«System.Uri», адрес);
HttpMethod = Врап.ПолучитьТипИзСборки(«System.Net.Http.HttpMethod», «System.Net.Http.dll»);
ХТТПЗапрос.Method = HttpMethod.Get;
И в 1-й и в 2-й строках одинаковая ошибка:
Произошла исключительная ситуация (mscorlib): Exception has been thrown by the target of an invocation.
Получение System.Uri видел у Вас здесь и в других публикациях. HttpMethod попробовал методом тыка.
А зачем для Get нужен какой то метод. Используй нужные методы с Get
.Net в 1С. Асинхронные HTTP запросы, отправка Post нескольких файлов multipart/form-data, сжатие трафика с использованием gzip, deflate, удобный парсинг сайтов и т.д.
Вот здесь куча примеров
Используй HTTPClient . он более продвинутый. У меня все примеры с ним.
(23) Сергей дело говорит, selenium часто спасает. Правда я его юзаю через python, но какая разница.
Никогда не мог понять зачем делать парсер в 1С, если можно на том же .NET написать нормальный парсер и юзать его через тот же SOAP как веб сервис. А если потребуется парсить в несколько потоков или т.д.? Для чего жопаболь с 1С-языком?
(27) На самом деле и в 1С можно запустить несколько задач
Асинхронное программирование в 1С через использование классов .Net из Native ВК
А как тестировать и отлаживать парсинг? Компилить каждый раз прогу на C# или дергать весь сайт заново из 1С?
Не надо извращений со скрещиванием C# и 1С. Берете python и пишете на BeautyfulSoup парсинг в реальном времени в консольке.
Изучается за час-два, получаете результат в JSON и передаете в 1С.
Можно и прямо из 1С запускать готовые py-скрипты, даже хранить их в базе, а не зашивать в хардкоде алгоритмы.
Уже не один год вижу статьи про .NET+1C, такое ощущение что автору в какой то глубинке нечем заняться и он упорно шлифует «свою прелесть»
(15) Пилил сжатие изображений.
Показать
КонецЕсли;
Режет картику до размера 500 пикселей на сколько-то там…. Ну исходя из начального размера. Если размер меньше 500 пикселей то оставляет как есть, жмет неплохо, качество не теряется, быстро и сердито, можно красивее, но нужно было сделать что-то быстро, а потом оказалась и так неплохо.
(23) Может кому будет полезным.
Показать
А есть ли какой-то способ вызывать конструкции вида =>
?