Как получить значение HtmlElement внутри Frames / IFrames? - PullRequest
0 голосов
/ 08 ноября 2018

Я использую элемент управления Winforms WebBrowser для сбора ссылок на видеоклипы с сайта, указанного ниже.

LINK

Но, когда я прокручиваю элемент за элементом, я не могу найти тег <video>.

void webBrowser_DocumentCompleted_2(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    try
    {
        HtmlElementCollection pTags = browser.Document.GetElementsByTagName("video");
        int i = 1;
        foreach (HtmlElement link in links)
        {

            if (link.Children[0].GetAttribute("className") == "vjs-poster")
            {
                try
                {

                    i++;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }
    }   // Added by edit
}

Вскоре после использования

HtmlElementCollection pTags = browser.Document.GetElementsByTagName("video");

Я уже вернул 0

Нужно ли мне звонить на любой Ajax?

1 Ответ

0 голосов
/ 09 ноября 2018

Веб-страница, на которую вы ссылаетесь, содержит IFrames .
IFrame содержит свой собственный HtmlDocument . На данный момент вы анализируете только основной контейнер Document.
Таким образом, вам нужно проанализировать HtmlElements теги некоторых других Frame.
На список фреймов веб-страниц ссылается свойство WebBrowser.Document.Window.Frames , которое возвращает HtmlWindowCollection .
Каждый HtmlWindow в коллекции содержит свой собственный HtmlDocument объект.

Вместо анализа свойства объекта Document, возвращаемого WebBrowser, нам, в большинстве случаев, необходимо проанализировать каждый HtmlWindow.Document в коллекции Frames; если, конечно, мы уже не знаем, что требуемые элементы являются частью основного документа или другого известного Frame.

Пример (относится к текущей задаче):

  • Подписаться на событие DocumentCompleted элемента управления / класса WebBrowser.
  • Проверьте свойство WebBrowser.ReadyState , чтобы убедиться, что документ загружен полностью.

Примечание:
Помня, что веб-страница может состоять из нескольких документов, содержащихся в кадрах / IFrames, мы не удивимся, если событие будет вызвано несколько раз с ReadyState = WebBrowserReadyState.Complete.
Document каждого кадра вызовет событие, когда WebBrowser завершит его загрузку.

Примечание:
Поскольку событие DocumentCompleted вызывается несколько раз, нам необходимо убедиться, что значение атрибута HtmlElement также не сохраняется несколько раз.
Здесь я использую пользовательский класс поддержки, который содержит все собранные значения вместе с HashCode каждой ссылочной ссылки (здесь, опираясь на реализацию по умолчанию GetHasCode()).
Каждый раз, когда документ анализируется, мы проверяем, было ли уже сохранено значение, сравнивая его хэш.

  • Остановите синтаксический анализ, когда мы проверим, что дублированный хэш был найден: элементы документа кадра уже извлечены.

Примечание
При синтаксическом анализе HtmlWindowCollection неизбежно возникает ряд особых исключений:
1) UnauthorizedAccessException : доступ к некоторым кадрам невозможен.
2) InvalidOperationException : доступ к некоторым элементам / потомкам невозможен.

Мы ничего не можем сделать, чтобы этого избежать: элементы не null, они просто выдают эти исключения, когда мы пытаемся получить доступ к любому их свойств (плохой дизайн базового класса).
Здесь я просто ловлю и игнорирую эти конкретные исключения: мы знаем, что в конечном итоге мы их получим, мы не можем этого избежать, иди дальше.

public class MovieLink
{
    public MovieLink() { }
    public int Hash { get; set; }
    public string VideoLink { get; set; }
    public string ImageLink { get; set; }
}

List<MovieLink> MoviesLinks = new List<MovieLink>();

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (webBrowser1.ReadyState != WebBrowserReadyState.Complete) return;

    var DocumentFrames = webBrowser1.Document.Window.Frames;
    foreach (HtmlWindow Frame in DocumentFrames)
    {
        try
        {
            var VideoElement = 
                Frame.Document.Body
                     .GetElementsByTagName("VIDEO").Cast<HtmlElement>().FirstOrDefault();

            if (VideoElement != null)
            {
                string VideoLink = VideoElement.Children[0].GetAttribute("src");
                int Hash = VideoLink.GetHashCode();
                if (MoviesLinks.Any(m => m.Hash == Hash))
                {
                    // Done parsing this URL: remove handler or whatever 
                    // else is planned to move to the next site/page
                    return;
                }

                string SourceImage = VideoElement.GetAttribute("poster");
                MoviesLinks.Add(new MovieLink() {
                    Hash = Hash, VideoLink = VideoLink, ImageLink = SourceImage
                });
            }
        }
        catch (UnauthorizedAccessException) { } // Cannot be avoided: ignore
        catch (InvalidOperationException) { }   // Cannot be avoided: ignore
    }
}
...