Быстрый старт проектов, готовое решение! Ускоряем разработку с помощью OwnCode и методов расширения!

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63
16 - mainLogo.jpg



Приветствую всех!

В этой статье хочу описать свой путь в разработке проектов. Статья будет опираться на шаблон в котором собраны решения помогающие ускорить разработку и сократить количество кода. Таким образом вы можете писать ваши проекты взяв его логику за основу, дополнив необходимым функционалом, либо воспользоваться, как готовым решением.
  • В статье я хочу обсудить базовые тезисы. Привести примеры методов расширения.
  • Шаблон, это готовое решение для ваших потенциальных проектов. А также, демонстрация, как можно строить шаблоны, на примере парсера интернет магазина.
  • Видео, призвано объяснить и помочь разобраться в структуре шаблона.
Статья является контекстом к шаблону и рассматривает лишь часть методов расширения. Пожалуйста, посмотрите видео, в нем я наглядно объясняю, как устроен шаблон.


В каждом шаблоне, могут быть базовые наборы действий:
  • Работа с тестовым файлом, получение строки, запись строки, чтение файла;
  • Отладка шаблона, сохранение репортов, отлов ошибок;
  • Работа с браузером;
Когда, мы пишем на кубиках, приходиться копировать однотипные блоки кубиков, которые отвечают за ту или иную проверку. Со временем, большие проекты разрастаются до масштабов, в которых сложно ориентироваться или быстро найти нужный элемент, т.к. весь проект может занимать несколько экранов, если только вы не знаете проект досконально. А что если вы год не открывали его, и необходимо найти ошибку или что-то подправить?

Если для вас это актуально, то, как вариант, можно использовать [C Sharp] в своих проектах. В статье я раскажу свой путь и ошибки, которые совершил.


МИФ: КОД БЫСТРЕЕ КУБИКОВ

В 2016, когда я купил ZennoPoster, я писал шаблоны на кубиках, они работали и выполняли возложенные на них задачи. На тот момент, факт того, что всё работает, уже был удовлетворительным. Но именно в этот период времени начал зарождаться тренд на создание шаблонов в коде. Это было ново, интересно, но мало понятно. Возможно именно тогда родилась версия, что код работает быстрее кубиков!?

11_1 - 2k16.jpg
11_2_- 2k16.jpg

Можно обратить внимание, что какие-то вещи сделаны в коде, тогда я только начинал его внедрять. И у меня, как у начинающего пользователя, кубик C# мог содержать только одно действие:

C#:
instance.ClearCookie();
C#:
Tab Tab1 = instance.ActiveTab;

try
{
    string mystring = Tab1.FindElementByXpath("//a[@class='comp']", 0);
    System.Threading.Thread.Sleep(3 * 1000);
}
catch (Exception e)
{
    project.SendErrorToLog(e.Message);
}

return mystring;
Подобный подход к разработке не имеет никаких видимых преимуществ, перед использованием кубиков.

ВЫВОД: Если у вас есть шаблон, который работает на кубиках без ошибок. Отлично! Перенос проекта в код может никак не сказаться на производительности! Код не работает быстрее кубиков!


МИФ: КОД КОМПАКТНЕЕ КУБИКОВ

С одной стороны может показаться, что код будет гораздо компактнее набора кубиков, и это утверждение отчасти является верным, но это не всегда так. Я привел пример, реализации однотипного функционала на кубиках и в коде, как видно, по площади занимаемой на экране они сопоставимы.

12 - Кубики vs Код.jpg

ВЫВОД: Не стоит гнаться за переносом всего и вся в код, практическую пользу можно получить только в отдельно взятых случаях. К примеру, в применении настроек для инстанса.

Этот код, действительно будет компактнее, 5 отдельно взятых кубиков.
C#:
instance.LoadPictures = false;
instance.UseCSS = false;
instance.UsePlugins = false;
instance.DownloadFrame = false;
instance.AllowPopUp = false;

ЗАДАЧИ ПЕРЕД КОДОМ

Когда я научился делать проекты на кубиках, мне это быстро наскучило, на тот момент набирали популярность курсы по C# для ZennoPoster. Желание научиться чему-то новому и делать другим образом, отправили меня в путь оптимизации кода.

Плюсы, которые я для себя выделил в переходе от кубиков к коду:
  1. Надежность работы шаблона при обновлениях.
  2. Возможность отладки и проверки всех действий;
  3. Отсутствие однотипного повторяющегося кода;
  4. Быстрый доступ к коду, читаемость, блочная структура;
  5. Внесение правок и доработка проекта не должны ломать структуру;
  6. Быстрый старт - шаблон должен выступать основой новых проектов.
Перенос проекта в код, может отчасти решить проблему обновления функционала кубиков, нет необходимости откатываться на предыдущую версию. К сожалению, в кубиках с обновленным функционалом, могут появиться зависимости. В итоге проект начнет выдавать ошибки, которым необходимо уделять время для поиска, внося правки в шаблон, а также время на тесты, чтобы понять фича это или баг :-)


ЧТО БЫЛО ДАЛЬШЕ? ПОВОРОТ НЕ ТУДА!

В желании учиться делать всё в коде, я сначала начал переносить каждый отдельно взятый кубик в его аналог в коде. Затем я начал всё это объединять в логические блоки сокращая количество кубиков с кодом.

В конечном итоге, это привело к рождению шаблона работающего из одно кубика и содержащего в себе +1100 строк. Всё было последовательно и логично, можно было проскролить быстро к нужному участку, но это не то, что я хотел получить, когда ставил цели перейти на код. Меня не удовлетворяло качество отладки, код содержал много однотипных кусков кода.

13 - 1100l.png

Что по итогу я получил, строя свой шаблон полностью в коде и одном кубике:
  • Сложность в изменении логики работы шаблона, перестроении циклов.
  • Много однотипных кусков кода.
  • Функционал шаблона сложен в отладке, т.к. приходиться копировать большие однотипные куски проверок для каждого элемента.
  • В больших проектах, количество строк при таком подходе может превышать несколько тысяч, включая комментарии. Что делает работу с такими проектами еще сложнее, чем работу с кубиками.

ВЫВОД: Писать в коде можно, нужно, но не так, как это делал я! Итого, я смог справиться только с первым пунктом "Надежность работы шаблона при обновлениях."


РЕШЕНИЕ == ОБЩИЙ КОД

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

Способ работы в общем коде № 1:
C#:
public class z
{
    public Instance instance;
    public IZennoPosterProjectModel project;

    public z (Instance instance, IZennoPosterProjectModel project)
    {
        this.instance = instance;
        this.project = project;
    }
}
Это хороший способ работы с общим кодом и написанием проектов, но он ставит перед нами ряд правил, которые необходимо соблюдать:
  • Необходимо заранее объявлять переменные в кубике, чтобы их можно было передать в метод общего кода;
  • Необходимо прописывать out, в случае возврата значений переменных из метода;
  • Необходимо объявлять передаваемые переменные внутри метода;
  • Необходимо в каждом классе объявлять проект и инстанс, если это необходимо.

Способ работы в общем коде № 2:
C#:
public class z
{
    public Instance instance;
    public IZennoPosterProjectModel project;

    public _is InputSettings;

    public z (Instance instance, IZennoPosterProjectModel project)
    {
        this.instance = instance;
        this.project = project;

        InputSettings = new _is(this);
    }
}

public class _is
{
    public _is (z t)
    {
    }
}

ОТЛАДКА И ПРОВЕРКА ВСЕХ ДЕЙСТВИЙ
  • Обернуть в методы все однотипные проверки:
Как правило, если были предусмотренны все сцерации проверки элемента, то взаимодествие не вызовет ошибку. В моих шаблонах, зачастую, я собираю данные со страницы, чтобы отладить сбор, необходимо сначала проверять наличие элемента на странице, а затем обращаться к нему. Для реализации я решил завернуть в методы, все однотипные проверки на странице. Я использую два типа обращений, с помощью Tab и библиотеки HtmlAgilityPack.

Что можно проверять на странице:
  • Элемент;
  • Колекцию;
  • Элемент в колекции;
  • Атрибут элемента.
Проверка существования элемента, возвращает true/false
C#:
/// <tep.IsVoid_e>
/// Проверка существования элемента, возвращает true/false
/// tep.IsVoid_e(t.tab, ".//*");
/// </tep.IsVoid_e>
/// <param name="Tab">Текущая вкладка</param>
/// <param name="xpath">Путь к элементу, xPath</param>
/// <param name="num">Порядковый номер совпадения (int), по умолчанию - 0</param>
/// <param name="b">Логический тип (bool), по умолчанию - false</param>

public static bool IsVoid_e (this Tab tab, string xpath, int num = 0, bool b = false)
{
    if (!tab.FindElementByXPath(xpath,0).IsVoid) b = true;
    return b;
}
Проверка существования HtmlNode (элемента в коллекции), с помощью HtmlAgilityPack, возвращает true/false
C#:
/// <hap.IsNull_n>
/// Проверка существования HtmlNode (элемента в коллекции), с помощью HtmlAgilityPack, возвращает true/false
/// hap.IsNull_c(t, ".//*");
/// </hap.IsNull_n>
/// <param name="t">Текущий поток</param>
/// <param name="Node">Объект HtmlNode в котором осуществляется проверка</param>
/// <param name="xpath">Путь к элементу, xPath</param>
/// <param name="b">Логический тип, по умолчанию - false</param>

public static bool IsNull_n (z t, HtmlNode Node, string xPath, bool b = false)
{
    if (Node.SelectSingleNode(xPath) != null) b = true;
    return b;
}
Проверка существования атрибута у элемента (в HtmlNode), с помощью HtmlAgilityPack, возвращает true/false
C#:
/// <hap.IsNull_a>
/// Проверка существования атрибута у элемента (в HtmlNode), с помощью HtmlAgilityPack, возвращает true/false
/// hap.IsNull_a(t, Node[i],".//*", "href");
/// </hap.IsNull_a>
/// <param name="t">Текущий поток</param>
/// <param name="Node">Объект HtmlNode в котором осуществляется проверка</param>
/// <param name="xpath">Путь к элементу, xPath</param>
/// <param name="Attribute">Проверяемый атрибут у элемента</param>
/// <param name="b">Логический тип, по умолчанию - false</param>

public static bool IsNull_a (z t, HtmlNode Node, string xPath, string Attribute, bool b = false)
{
    if (Node.SelectSingleNode(xPath).Attributes[Attribute] != null) b = true;
    return b;
}
  • Сделать возможность дебага проекта:
После обращения к элементу, мы возвращаем его значение в переменную относящуюся к этому элементу. Если мы получили InnerText по нашему пути xPath и он не пустой, то мы возвращаем Info сообщение с полученным значением.
Если мы не смогли найти элемент по xPath, то через else, мы можем присвоить переменной какое-то значение, к примеру "-", "-1", "null". В этом сценарии мы будем выводить Warning.
В случае если мы нашли путь, но переменная IsNullOrEmpty, то мы вернем Error.

Таким образом мы сможем быстро сориентироваться при отладке проекта, т.к. на разных сайтах разметка может изменяться исходя из категории, и для одного элемента необходимо подбирать несколько разных путей xPath.

Метод отладки работы проекта.
C#:
/// <log.DebugInfo>
/// > Метод отладки работы проекта.
/// > Объявляется после необходимого действия в проекте и передает тип оповещения исходя из получаемого значения действия.
/// log.DebugInfo(t, "Stage", "Variable");
/// </log.DebugInfo>
/// <param name="t">Текущий поток</param>
/// <param name="text">Сообщение отправляемое в лог</param>
/// <param name="showInZP">Логический тип (bool), показывать сообщение в ZennoPoster. По умолчанию - true</param>
/// <param name="stage">Указание точки в проекте, за которую отвечает DebugInfo</param>
/// <param name="variable">Переменная значение которой будет передавать в DebugInfo. Исходя из которого будет выбран тип оповещения.</param>

public static void DebugInfo (z t, string stage, string variable)
{
    if (t._is.b_DebugMode)
    {
        if (string.IsNullOrEmpty(variable)) log.SendLogError(t, String.Format("{0} {1}", stage, variable), t._is.b_DebugMode);
        else if (variable == "-") log.SendLogWarning(t, String.Format("{0} {1}", stage, variable), t._is.b_DebugMode);
        else log.SendLogInfo(t, String.Format("{0} {1}", stage, variable), t._is.b_DebugMode);
    }
}

  • Создать генератор отчета об ошибках:
Для эффективной отладки проекта нам необходимо сохранять расширенные отчеты об ошибках, в которых нам может пригодиться следующая информация:
  • Дата и время ошибки;
  • Проки потока;
  • Сообщение об ошибке;
  • DOM модель страницы;
  • Скриншот инстанса.
Метод сохраняет отчет об ошибке:
C#:
/// <e.BugReport>
/// Метод сохраняет отчет об ошибке.
/// > В папке Bug Reports (директория проекта), создается папка "1589207820", где 1589207820 - это время старта потока в UnixTime формате.
/// > В этой папке создается текстовый документ "1589207820.txt", в который сохраняются данные: Прокси потока, DateTime, Сообщение об ошибке, DOM инстанса.
/// > InstanceScreenshot = true, сохранит скриншот инстанса "1589207820.jpg".
/// e.BugReport(t, "Message");
/// </e.BugReport>
/// <param name="t">Текущий поток</param>
/// <param name="excMessage">Сообщение об ошибке</param>
/// <param name="InstanceScreenshot">Логический тип (bool), по умолчанию - false. Отвечает за сохранение скриншота инстанса.</param>

public static void BugReport (z t, string excMessage, bool InstanceScreenshot = false)
{
    lock(Locker.FileExceptionReport)
    {
        string DOM = string.Empty;

        if (!Directory.Exists(Path.Combine(t.project.Directory, "Bug Reports"))) Directory.CreateDirectory(Path.Combine(t.project.Directory, "Bug Reports"));
        if (!Directory.Exists(Path.Combine(t.project.Directory, "Bug Reports", t._ts.unixtime.ToString()))) Directory.CreateDirectory(Path.Combine(t.project.Directory, "Bug Reports", t._ts.unixtime.ToString()));

        if (!t.tab.IsVoid || !t.tab.IsNull) DOM = t.tab.DomText.ToString();

        string TxtFilePath = Path.Combine(t.project.Directory, "Bug Reports", t._ts.unixtime.ToString(), String.Format("{0}.txt", t._ts.unixtime.ToString()));
        string ImgFilePath = Path.Combine(t.project.Directory, "Bug Reports", t._ts.unixtime.ToString(), String.Format("{0}.jpg", t._ts.unixtime.ToString()));
        string myLine = String.Format("Proxy :: {1};{0}DateTime :: {2};{0}Exception Message :: {3};{0}{0}DomText ::{0}{4}", "\r\n", t._ts.proxy, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), excMessage, DOM);

        Files.Writer(t, Locker.FileExceptionReport, TxtFilePath, myLine);

        if (InstanceScreenshot && !t.tab.IsVoid || InstanceScreenshot && !t.tab.IsNull)
        {
            using (var ms = new MemoryStream(Convert.FromBase64String(t.tab.GetPagePreview())))
            using (var bm = new Bitmap(ms))
            {
                bm.Save(ImgFilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
        }
    }
}

  • Создать свой расширенный Exception метод:
В работе проекта могут использоваться прокси и задание, в случае если в проекте возникает ошибка, то нам может быть необходимо вернуть строку прокси назад в файл/базу и вернуть задание. Иначе информация об этом задании будет утеряна, т.к. поток возьмет строку, но не вернет её в случае ошибки.

Метод заменяет стандартный throw new Exception(e)
C#:
/// <e.ThrowExc>
/// Метод заменяет стандартный throw new Exception(e)
/// > Метод вернет строки Proxy и Task в текстовые файлы.
/// > Вызовет метод e.BugReport, чтобы сохранить отчет об ошибке в папку Bug Reports (директория проекта).
/// > Вызовет throw new Exception(e), чтобы завершить работу с ошибкой.
/// e.ThrowExc(t, "Message");
/// </e.ThrowExc>
/// <param name="t">Текущий поток</param>
/// <param name="excMessage">Сообщение об ошибке</param>

public static void ThrowExc (z t, string excMessage)
{
    try
    {
        Files.Writer(t, Locker.FileProxy, t._is.FilePath_Proxy, t._ts.proxy);
        Files.Writer(t, Locker.FileTask, t._is.FilePath_Task, t._ts.task);
        if (!excMessage.Contains("Manual Stopped")) e.BugReport(t, excMessage, true);
    }
    finally
    {
        throw new Exception(excMessage);
    }
}

УНИВЕРСАЛИЗАЦИЯ ОДНОТИПНОГО КОДА

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

Метод чистит список от дубликатов:
C#:
/// <e.DoubleDel>
/// Метод чистит список от дубликатов
/// e.DoubleDel(t, t.Lists.lst_TxtFiles);
/// </e.DoubleDel>
/// <param name="t">Текущий поток</param>
/// <param name="MyList">Список List<string>, который чистим от дубликатов</param>

public static void DoubleDel (z t, List<string> MyList)
{
    lock(Locker.lstDuplicates)
    {
        HashSet<string> hs = new HashSet<string>(MyList);
        MyList.Clear();
        MyList.AddRange(hs);
    }
}

Метод читает все строки из текстового файла в список
C#:
/// <Files.ReadAll>
/// Читаем все строки из текстового файла в список
/// Files.ReadAll(t, Locker.FileTask, @"D:\sourceList.txt", t.Lists.lst_TxtFiles);
/// </Files.ReadAll>
/// <param name="t">Текущий поток</param>
/// <param name="myLocker">Объект lock(object)</param>
/// <param name="myFilePath">Путь к текстовому документу</param>
/// <param name="MyList">Список List<string> в который отправим данные из файла</param>

public static void ReadAll (z t, object myLocker, string myFilePath, List<string> MyList)
{
    lock(myLocker)
    {
        try
        {
            string data = string.Empty;
            using (var stream = File.Open(myFilePath, FileMode.Open, FileAccess.Read))
            using (var reader = new StreamReader(stream))
            {
                if (new FileInfo(myFilePath).Length > 0) while (!reader.EndOfStream) MyList.Add(reader.ReadLine());
                else e.ThrowExc(t, String.Format(t._pm.m2, myFilePath));
            }
        }
        catch (IOException exc)
        {
            e.ThrowExc(t, String.Format(t._pm.m3, "Files.ReadAll()", myFilePath, exc.GetType().Name));
        }
    }
}

Метод чистит список по файлу BlackList.txt
C#:
/// <Files.BlackList>
/// Чистим список по файлу BlackList.txt
/// > По умолчанию, BlackList.txt должен находиться в директории проекта.
/// Files.BlackList(t, Locker.FileBlackList, t.Lists.lst_TxtFiles);
/// </Files.BlackList>
/// <param name="t">Текущий поток</param>
/// <param name="myLocker">Объект lock(object)</param>
/// <param name="MyList">Список List<string>, который проверяем.</param>

public static void BlackList (z t, object myLocker, List<string> MyList)
{
    lock(myLocker)
    {
        string myFilePath = Path.Combine(t.project.Directory, "BlackList.txt");
        List<string> blackList = new List<string>();

        try
        {
            using (var stream = File.Open(myFilePath, FileMode.Open, FileAccess.Read))
            using (var reader = new StreamReader(stream))
            {
                if (new FileInfo(myFilePath).Length > 0)
                {
                    while (!reader.EndOfStream) blackList.Add(reader.ReadLine());

                    List<string> Except = MyList.AsParallel().AsOrdered().Except(blackList.AsParallel(), StringComparer.OrdinalIgnoreCase).ToList();
                    MyList.Clear();
                    MyList.AddRange(Except);
                }
                else log.SendLogWarning(t, String.Format(t._pm.m2, myFilePath));
            }
        }
        catch (IOException exc)
        {
            e.ThrowExc(t, String.Format(t._pm.m3, "Files.BlackList()", Path.GetFileName(myFilePath), exc.GetType().Name));
        }

    }
}

ЧИТАЕМОСТЬ КОДА, БЛОЧНАЯ СТРУКТУРА

Использование общего кода позволяет групировать методы в классы, а классы структурировать в удобном порядке. Важно понимать, что порядок расположения независимых классов и методов, не влияет на их работоспособность. Таким образом обернув методы и классы в регионы "#region", мы получим структуру кода в которой легко ориентироваться и не составит труда найти нужный метод, чтобы внести коретировки в код.

14 - Структура NS.png


РЕЗУЛЬТАТЫ

Применение на практике, позволило прийти к новому способу написания шаблонов. Благодаря этим решениям я смог закрыть все поставленные задачи:
  • Надежность работы шаблона при обновлениях.
  • Возможность отладки и проверки всех действий;
  • Отсутствие однотипного повторяющегося кода;
  • Быстрый доступ к коду, читаемость, блочная структура;
  • Внесение правок и доработка проекта не должны ломать структуру;
  • Быстрый старт - шаблон должен выступать основой новых проектов.
А написание шаблона свелось к необходимости:
  • Объявить переменные для проекта;
  • Собрать xPath к элементам;
  • Составить каркас базы данных;
  • Прописать работу с элементами на странице (Data Collect).
15 - кубик кода.png


ВИДЕО


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

0 - Предыстория кода;
5:15 - Логика работы шаблона;
8:50 - Основа общего кода;
12:20 - Демонстрация работы шаблона;
15:30 - Кубик C# в шаблоне;
16:30 - Структура Name Space;
18:35 - Как быстро развернуть новый проект;
19:50 - Классы внутри шаблона;
20:30 - Переменные проекта;
29:00 - Tab / HtmlAgilityPack;
32:55 - log - Логирование проекта;
37:10 - Класс Proxy;
40:05 - Класс Task;
41:10 - Класс Files;
47:50 - Класс Captcha;
50:30 - Technical Extension Voids;
53:00 - Bug Report;
55:00 - Класс Database;
56:40 - Класс Data;
1:05:45 - Класс z;
1:06:35 - Ошибка: Object reference not set to an instance of an object.

Приношу извинения за звук в последние 7 минут видео, youtube не хотел пропускать из-за Fleetwood Mac - The Chain (Remastered Version), которая играла фоном. Пришлось делать Noise Reduction и накладывать новую дорожку с музыкой.


Спасибо за ваше внимание! Надеюсь совокупность статьи, шаблона и видео, позволили раскрыть тему. На своем примере я хотел показать, что стремление к какой-то идее, не всегда приводит к желанному результату и шаблон на 1100 строк кода, тому пример. Этой статьёй вы можете подчеркнуть какие-то идеи и выбрать оптимальный путь в написании шаблонов, чтобы это было удобно именно вам!

Если вам понравилась данная конкурсная работа, пожалуйста, проголосуйте за неё!
 

Вложения

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

Dexio

Client
Регистрация
09.05.2014
Сообщения
1 217
Благодарностей
209
Баллы
63
Шикарно. Доходчиво и понятно и с примерами, мне было очень полезно! Спасибо за примеры
 
  • Спасибо
Реакции: masterLomaster и RoyalBank

seregakot

Client
Регистрация
19.03.2016
Сообщения
97
Благодарностей
54
Баллы
18
Спасибо за труды.
Давно хотел научиться коду.
Вот все не могу выучить c#.
 
  • Спасибо
Реакции: masterLomaster и RoyalBank

radv

Client
Регистрация
11.05.2015
Сообщения
1 098
Благодарностей
548
Баллы
113
Класс. :ay: Когда я только начинал работать с общим кодом в зенке и начинал изучать си шарп, таких статей не было :( и приходилось методом тыка пробовать, или покупать разные видео курсы. :az:
 
  • Спасибо
Реакции: masterLomaster и RoyalBank

GREXA

Client
Регистрация
16.09.2017
Сообщения
127
Благодарностей
27
Баллы
28
Благодарю за интересную тему!
Отдал свой голос!
 
  • Спасибо
Реакции: RoyalBank

sergio197675

Client
Регистрация
21.09.2019
Сообщения
150
Благодарностей
129
Баллы
43
Спасибо , наконец то компактно и доходчиво , то несколько раз пробовал начать и окунуться в C#.... но при чтении про классы ,методы , "ваши переменные это не те переменные" ...и прочее напрочь отбивало желание :D , ещё бы так доходчиво про "грамматику" - то не там кавычки поставишь , то ещё чего .....сильно раздражает , что столько нюансов :be:
 
  • Спасибо
Реакции: RoyalBank

Nike59

Client
Регистрация
05.08.2011
Сообщения
118
Благодарностей
111
Баллы
43
Отличная работа. Систематическое и доходчивое объяснение общего кода. Давно хотел упорядочить свои наработки и фичи, полученные в ходе обучения на различных курсах. Многим эта статья сэкономит время и приличные суммы денег.

Добавил PS.
Посмотрел код более подробно. Автор проделал просто титаническую работу. Почти полторы тысячи строк содержит общий код. Охвачен весь спектр инструментария Zennoposter. Бери и пользуйся. Это подарок всем нам.
В общем, снимаю шляпу перед этим огромным трудом, сделанным профессионально и с душой.
 
Последнее редактирование:

Koqpe

Client
Регистрация
23.12.2014
Сообщения
931
Благодарностей
495
Баллы
63
Спасибо за статью.
В одном месте для меня прервалась логическая цепочка статьи, нет описания плюсов и минусов (а они есть) работы в общем коде №2:
Аннотация 2020-05-22 230638.png
Аннотация 2020-05-22 230819.png
 
  • Спасибо
Реакции: RoyalBank и intagens

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63
В одном месте для меня прервалась логическая цепочка статьи, нет описания плюсов и минусов (а они есть) работы в общем коде №2:
Спасибо за подмеченный момент, подразумевалось, что второй способ нивелирует необходимость следовать ряду правил, которые ставит перед нами использование первого способа.
 
  • Спасибо
Реакции: Koqpe

Nats1

Client
Регистрация
15.04.2015
Сообщения
148
Благодарностей
139
Баллы
43
Книгу купить не пробовали?)) Очередной велосипед...
 
  • Спасибо
Реакции: Platon

zenno.xxx

Client
Регистрация
05.10.2016
Сообщения
605
Благодарностей
187
Баллы
43

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

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 807
Благодарностей
3 483
Баллы
113

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63
Да, спасибо, как раз недавно оставлял ссылку на этот комментарий в предложениях по ZP. Я отказался от tab методов проверки, использую только htmlagilitypack. В случае если шаблон только собирает информацию, то можно одной строкой переделать под работу на запросах.
 

Phoenix78

Client
Регистрация
06.11.2018
Сообщения
3 207
Благодарностей
1 464
Баллы
113
насколько я знаю, раньше в зенке не было работы с xpath через строковые переменные и все пользовались htmlagilitypack . Сейчас есть такие методы в зенке. Знает кто чем лучше ,на текущий момент, htmlagilitypack от встроенных методов зенки ?
 

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63
насколько я знаю, раньше в зенке не было работы с xpath через строковые переменные и все пользовались htmlagilitypack . Сейчас есть такие методы в зенке. Знает кто чем лучше ,на текущий момент, htmlagilitypack от встроенных методов зенки ?
В версии 5.11.1.0, они как раз "убрали зависимость от htmlagilitypack", насколько я понял, просто интегрировали либу в ZP.
 

sambukanuka

Client
Регистрация
17.09.2019
Сообщения
190
Благодарностей
49
Баллы
28
Спасибо про мифы - появилось осознание. Сейчас изучаю с# , ни х не понятно но очень интересно! Стал изучать только из-за Xpath (купил обучение) , в обучение именно все через C# , хочу хотя бы основы понять. Спасибо за статью !
56487
 
  • Спасибо
Реакции: RoyalBank

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 807
Благодарностей
3 483
Баллы
113
Да, спасибо, как раз недавно оставлял ссылку на этот комментарий в предложениях по ZP. Я отказался от tab методов проверки, использую только htmlagilitypack. В случае если шаблон только собирает информацию, то можно одной строкой переделать под работу на запросах.
Речь о другом, о использовании IsNull и IsVoid.
 

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63

Advert31337

Client
Регистрация
18.12.2016
Сообщения
51
Благодарностей
36
Баллы
18
Как раз хотел заморочиться чем-то подобным, сделать себе архитектурные заготовки и заготовки под определенные действия. Спасибо за труды)
 
  • Спасибо
Реакции: RoyalBank

silom2000

Client
Регистрация
16.12.2019
Сообщения
21
Благодарностей
4
Баллы
3
Что не так с моими настройками, не могу запустить ваш проект?
 

Вложения

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63
Что не так с моими настройками, не могу запустить ваш проект?
Проверьте если порт правильный для socks5, ошибка установки прокси говорит о том, что шаблон не смог проверить его на работоспособность. Суть проверки в отправке запроса на один из четырех источников:

C#:
"http://api.ipify.org/",
"http://chek.zennolab.com/proxy.php",
"http://check2.zennolab.com/proxy.php",
"http://chekfast.zennolab.com/proxy.php"
 

silom2000

Client
Регистрация
16.12.2019
Сообщения
21
Благодарностей
4
Баллы
3
Вот отчет при подключении
Proxy :: Ca**AN:16***@91.**.136.2**:**00;
DateTime :: 2020-05-26 17:54:05;
Exception Message :: SQLite.Insert() Exception: [[FastSqliteHelper.Init]: 'Ошибка подключения к БД: Не удается загрузить DLL "SQLite.Interop.dll": Не найден указанный модуль. (Исключение из HRESULT: 0x8007007E)'. Last query: ''. Строка подключения: Data Source=E:\Zennoposter\!Zenno\13_RoyalBank\db\Warehouse.sqlite3;Version=3;Journal Mode=WAL;];
 

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63
Exception Message :: SQLite.Insert() Exception: [[FastSqliteHelper.Init]: 'Ошибка подключения к БД: Не удается загрузить DLL "SQLite.Interop.dll": Не найден указанный модуль. (Исключение из HRESULT: 0x8007007E)'. Last query: ''. Строка подключения: Data Source=E:\Zennoposter\!Zenno\13_RoyalBank\db\Warehouse.sqlite3;Version=3;Journal Mode=WAL;];
Моя ошибка, пожалуйста, добавьте эту библиотеку в папку ExternalAssemblies
 

Вложения

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

silom2000

Client
Регистрация
16.12.2019
Сообщения
21
Благодарностей
4
Баллы
3
Теперь вот что получаю. Screenshot_1333.jpg
 

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
366
Благодарностей
300
Баллы
63
Теперь вот что получаю.
Удалите старую базу, шаблон создаст новую с нуля. Эта ошибка говорит, что в базе нет нужной таблицы, база могла быть создана, но из-за отсутсвия библиотеки в ней не бала создана таблица, из-за этого при попытке отправить данные в базу, происходит ошибка.
 

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