一尘不染

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

c#

我正在使用该Winforms WebBrowser控件从下面链接的站点收集视频剪辑的链接。

链接

但是,当我逐元素滚动时,找不到<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吗?


阅读 306

收藏
2020-05-19

共1个答案

一尘不染

您链接的网页包含IFrames
一个IFrame包含它自己的HTMLDocument。到目前为止,您只解析主Document容器。
因此,您需要解析HtmlElements其他标签Frame
Web页面框架列表由WebBrowser.Document.Window.Frames属性引用,该属性返回HtmlWindowCollection。集合中的
每个HtmlWindow都包含自己的HtmlDocument对象。

相反解析的Document被返回的对象属性WebBrowser,我们大部分的时间,需要分析每个HtmlWindow.DocumentFrames收集;
除非,当然,除非我们已经知道所需的元素是主文档或其他已知文档的一部分Frame

一个示例(与当前任务有关):

注意:
请记住,网页可能是由Frames / IFrames中包含的多个Document组成的,如果使用多次引发事件,我们不会感到惊讶ReadyState = WebBrowserReadyState.Complete。加载完毕后,
每个Frame Document都会引发事件WebBrowser

注意:
由于DocumentCompleted事件引发多次,因此我们需要验证HtmlElement属性值也没有存储多次。
在这里,我使用的是一个支持自定义类,该类包含所有收集的值以及每个引用Link的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").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
    }
}
2020-05-19