如何获取 Frames/IFrames 中的 HtmlElement 值?

How to get an HtmlElement value inside Frames/IFrames?

我正在使用 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");

我已经 return 0

我需要打电话给任何 ajax 吗?

您链接的网页包含 IFrames
IFrame 包含它自己的 HtmlDocument。截至目前,您只解析主文档容器。
因此,您需要解析其他 Frame.
HtmlElements TAG 网页框架列表由 WebBrowser.Document.Window.Frames property, which returns an HtmlWindowCollection.
引用 集合中的每个 HtmlWindow 都包含它自己的 HtmlDocument 对象。

而不是解析 WebBrowser 返回的 Document 对象 属性,我们大多数时候需要解析 Frames 中的每个 HtmlWindow.Document =] 集合;除非,当然我们已经知道所需的元素是主文档的一部分或另一个已知的 Frame.

一个例子(与当前任务相关):

注:
请记住,一个网页可能由 Frames/IFrames 中包含的多个文档组成,如果使用 ReadyState = WebBrowserReadyState.Complete.
多次引发该事件,我们不会感到惊讶。 每个框架的 Document 将在 WebBrowser 完成加载时引发事件。

注:
由于多次引发 DocumentCompleted 事件,我们需要验证 HtmlElement 属性值也没有被多次存储。
在这里,我使用支持自定义 Class,它保存所有收集的值以及每个引用 Link 的 HashCode(此处,依赖于 GetHasCode() 的默认实现)。
每次解析一个 Document 时,我们检查一个值是否已经存储,比较它的 Hash。

  • 当我们确认已找到重复哈希时停止解析:框架文档元素已被提取。

:
在解析 HtmlWindowCollection 时,不可避免地会引发一些特定的异常:

  1. UnauthorizedAccessException: 部分Frames无法访问
  2. InvalidOperationException: 部分Elements/Descendants无法访问。

我们无法避免这种情况:元素不是 null,当我们尝试访问其属性的 any 时,它们只会抛出这些异常。
在这里,我只是捕获并忽略这些特定的异常:我们知道我们最终会得到它们,我们无法避免,继续。

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 Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    var browser = sender as WebBrowser;
    if (browser.ReadyState != WebBrowserReadyState.Complete) return;

    var documentFrames = browser.Document.Window.Frames;
    foreach (HtmlWindow Frame in documentFrames) {
        try {
            var videoElement = Frame.Document.Body
                .GetElementsByTagName("VIDEO").OfType<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
    }
}