Получение содержимого страницы в цикле при помощи CefSharp

Здравствуйте. Есть набор страниц сайта. Нужно с них получить весь html. С помощью простых http-запросов не получается, т.к. там стоит защита от парсинга, а найти способ обойти эту защиту не получилось. Поэтому использую cefsharp Offscreen. До недавнего времени все работало. А сейчас наблюдается проблема, что если, допустим, загрузить три страницы, то данные можно будет получить в лучшем случае с двух, но чаще только с одной. Первая глава получается всегда. Если парсить по странице, то все окей, только это очень долго, т.к. обычно надо перебрать страниц 50. И вот не могу понять почему постранично работает, а в цикле не хочет…
Пример страницы: https://author.today/work/92956
Использую следующий код, частично взятый из репозитория cefsharp на Гитхабе.

public static Task LoadPageAsync(IWebBrowser browser)
        {
            var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
 
            EventHandler<LoadingStateChangedEventArgs> handler = null;
            handler = (sender, args) =>
            {
                if (!args.IsLoading)
                {
                    browser.LoadingStateChanged -= handler;
                    tcs.TrySetResult(true);
                }
            };
 
            browser.LoadingStateChanged += handler;
 
            return tcs.Task;
        }
 
public static string chapterText(string html)
        {
            HtmlDocument HD = new HtmlDocument();
 
            HD.LoadHtml(html);
           
            var titleChapter = HD.DocumentNode.SelectSingleNode("//div[@id='text-container']");
            
            string textFormattedImage = titleChapter.InnerHtml;
            return textFormattedImage;
        }
 
private async static void MainAsync(string[] testUrl)
        {
            var browserSettings = new BrowserSettings();
            browserSettings.WindowlessFrameRate = 1;
            string title = titleBook(HtmlDom);
 
            string titleValidate = Regex.Replace(title, @"[\/?:*""><|]+", "", RegexOptions.Compiled);
 
            foreach (var url in testUrl)
            {
                using (var browser = new ChromiumWebBrowser(url, browserSettings))
                {
                    await LoadPageAsync(browser);
                    var source = await browser.GetSourceAsync();
                    using (StreamWriter sw = new StreamWriter(@"D:\" + titleValidate.Trim() + ".html", true, Encoding.UTF8))
                    {
                        sw.WriteLine(chapterText(source), Encoding.UTF8);
                    }
 
                    Console.WriteLine("Глава " + url + " получена");
                }
            }
 
 
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Книга получена!");
        }

Selenium проще всего для такой автоматизации.
Чтобы не показывать окно браузера есть headless chrome (не пробовал).

Если там защита, то может просто добавить паузу между страницами надо?
И может быть не перезапускать браузер для каждой.
Ну и чтобы совсем не отличить от человека — кликать по ссылкам для перехода по главам.

как это правильно сделать? Я пробовал task.delay(1000) и thread.sleep(1000), но эффекта это не дало. Может я делал это неправильно))

Для первого await надо.

Может 1 сек мало.

thread.sleep(5000); вроде как работает. Но что из этих двух способов будет более правильным?

Тут — любой.

async/await например для GUI имеет значение, чтобы легко выполнять долгие задачи асинхронно не вешая весь GUI, без ручного создания потоков и т.д.
Например строка await Task.Delay(5000); не повесит весь GUI на 5 сек, можно в это время нажимать другие кнопки и т.д., а через 5 сек код продолжит выполняться со следующей строки.

2 лайка

Текст надо получать по событию FrameLoadEnd. Иначе у вас скрипты не отрабатываются и вы получаете полусырую страницу. И тогда не надо будет извращаться с задержками.

Так она вроде между страницами, а не между загрузкой и получением HTML.

И возможно LoadingStateChanged + проверка IsLoading достигает того же эффекта, что FrameLoadEnd.