C# 选择通过脚本添加到DOM的元素

C# 选择通过脚本添加到DOM的元素,c#,asp.net,html-agility-pack,C#,Asp.net,Html Agility Pack,我一直在尝试使用以下方法获取或标记: HtmlNode videoObjectNode = doc.DocumentNode.SelectSingleNode("//object"); HtmlNode videoEmbedNode = doc.DocumentNode.SelectSingleNode("//embed"); 这似乎不起作用 谁能告诉我如何获得这些标签和它们的内部HTML 嵌入YouTube的视频如下所示: <embed height="385" width="

我一直在尝试使用以下方法获取或标记:

HtmlNode videoObjectNode = doc.DocumentNode.SelectSingleNode("//object");
HtmlNode videoEmbedNode = doc.DocumentNode.SelectSingleNode("//embed");
这似乎不起作用

谁能告诉我如何获得这些标签和它们的内部HTML

嵌入YouTube的视频如下所示:

    <embed height="385" width="640" type="application/x-shockwave-flash" 
src="http://s.ytimg.com/yt/swf/watch-vfl184368.swf" id="movie_player" flashvars="..." 
allowscriptaccess="always" allowfullscreen="true" bgcolor="#000000">
string codeBlock = "if (x == 1) Console.WriteLine(\"Hello, World!\");";
我感觉JavaScript可能会阻止swf播放器工作,希望不是

干杯

更新2010-08-26,回应OP的评论:

我想你想得不对,亚历克斯。假设我写了一些C代码,如下所示:

    <embed height="385" width="640" type="application/x-shockwave-flash" 
src="http://s.ytimg.com/yt/swf/watch-vfl184368.swf" id="movie_player" flashvars="..." 
allowscriptaccess="always" allowfullscreen="true" bgcolor="#000000">
string codeBlock = "if (x == 1) Console.WriteLine(\"Hello, World!\");";
现在,如果我编写了一个C解析器,它是否应该将上面的字符串文本的内容识别为C代码并突出显示它或其他类似的内容?不,因为在格式良好的C文件的上下文中,该文本表示代码块变量被分配到的字符串

类似地,在YouTube页面上的HTML中,和元素在当前HTML文档的上下文中根本不是真正的元素。它们是驻留在JavaScript代码中的字符串值的内容

事实上,如果HtmlAgilityPack确实忽略了这一事实,并试图识别可能是HTML的文本的所有部分,那么这些元素仍然不会成功,因为在JavaScript中,它们被大量转义为\个字符。请注意我为解决此问题而发布的代码中不稳定的Unescape方法

我并不是说我下面的黑客解决方案是解决这个问题的正确方法;我只是在解释为什么获取这些元素不像用HtmlAgilityPack获取它们那么简单

YouTubeScraper 好的,亚历克斯:你要的,给你。一些真正的黑客代码可以从JavaScript的海洋中提取宝贵的元素

class YouTubeScraper
{
    public HtmlNode FindObjectElement(string url)
    {
        HtmlNodeCollection scriptNodes = FindScriptNodes(url);

        for (int i = 0; i < scriptNodes.Count; ++i)
        {
            HtmlNode scriptNode = scriptNodes[i];

            string javascript = scriptNode.InnerHtml;

            int objectNodeLocation = javascript.IndexOf("<object");

            if (objectNodeLocation != -1)
            {
                string htmlStart = javascript.Substring(objectNodeLocation);

                int objectNodeEndLocation = htmlStart.IndexOf(">\" :");

                if (objectNodeEndLocation != -1)
                {
                    string finalEscapedHtml = htmlStart.Substring(0, objectNodeEndLocation + 1);

                    string unescaped = Unescape(finalEscapedHtml);

                    var objectDoc = new HtmlDocument();

                    objectDoc.LoadHtml(unescaped);

                    HtmlNode objectNode = objectDoc.GetElementbyId("movie_player");

                    return objectNode;
                }
            }
        }

        return null;
    }

    public HtmlNode FindEmbedElement(string url)
    {
        HtmlNodeCollection scriptNodes = FindScriptNodes(url);

        for (int i = 0; i < scriptNodes.Count; ++i)
        {
            HtmlNode scriptNode = scriptNodes[i];

            string javascript = scriptNode.InnerHtml;

            int approxEmbedNodeLocation = javascript.IndexOf("<\\/object>\" : \"<embed");

            if (approxEmbedNodeLocation != -1)
            {
                string htmlStart = javascript.Substring(approxEmbedNodeLocation + 15);

                int embedNodeEndLocation = htmlStart.IndexOf(">\";");

                if (embedNodeEndLocation != -1)
                {
                    string finalEscapedHtml = htmlStart.Substring(0, embedNodeEndLocation + 1);

                    string unescaped = Unescape(finalEscapedHtml);

                    var embedDoc = new HtmlDocument();

                    embedDoc.LoadHtml(unescaped);

                    HtmlNode videoEmbedNode = embedDoc.GetElementbyId("movie_player");

                    return videoEmbedNode;
                }
            }
        }

        return null;
    }

    protected HtmlNodeCollection FindScriptNodes(string url)
    {
        var doc = new HtmlDocument();

        WebRequest request = WebRequest.Create(url);
        using (var response = request.GetResponse())
        using (var stream = response.GetResponseStream())
        {
            doc.Load(stream);
        }

        HtmlNode root = doc.DocumentNode;
        HtmlNodeCollection scriptNodes = root.SelectNodes("//script");

        return scriptNodes;
    }

    static string Unescape(string htmlFromJavascript)
    {
        // The JavaScript has escaped all of its HTML using backslashes. We need
        // to reverse this.

        // DISCLAIMER: I am a TOTAL Regex n00b; I make no claims as to the robustness
        // of this code. If you could improve it, please, I beg of you to do so. Personally,
        // I tested it on a grand total of three inputs. It worked for those, at least.
        return Regex.Replace(htmlFromJavascript, @"\\(.)", UnescapeFromBeginning);
    }

    static string UnescapeFromBeginning(Match match)
    {
        string text = match.ToString();

        if (text.StartsWith("\\"))
        {
            return text.Substring(1);
        }

        return text;
    }
}
原始答案 为什么不改用元素的Id呢

HtmlNode videoEmbedNode = doc.GetElementbyId("movie_player");
更新:哦,伙计,你在搜索JavaScript中的HTML标记?这就是为什么这不起作用的原因。从HtmlAgilityPack的角度来看,它们并不是真正需要解析的标记;所有这些JavaScript实际上是标记中的一个大字符串。也许有某种方法可以将标签的内部文本本身解析为HTML,并从中开始。

更新2010-08-26以回应OP的评论:

我想你想得不对,亚历克斯。假设我写了一些C代码,如下所示:

    <embed height="385" width="640" type="application/x-shockwave-flash" 
src="http://s.ytimg.com/yt/swf/watch-vfl184368.swf" id="movie_player" flashvars="..." 
allowscriptaccess="always" allowfullscreen="true" bgcolor="#000000">
string codeBlock = "if (x == 1) Console.WriteLine(\"Hello, World!\");";
现在,如果我编写了一个C解析器,它是否应该将上面的字符串文本的内容识别为C代码并突出显示它或其他类似的内容?不,因为在格式良好的C文件的上下文中,该文本表示代码块变量被分配到的字符串

类似地,在YouTube页面上的HTML中,和元素在当前HTML文档的上下文中根本不是真正的元素。它们是驻留在JavaScript代码中的字符串值的内容

事实上,如果HtmlAgilityPack确实忽略了这一事实,并试图识别可能是HTML的文本的所有部分,那么这些元素仍然不会成功,因为在JavaScript中,它们被大量转义为\个字符。请注意我为解决此问题而发布的代码中不稳定的Unescape方法

我并不是说我下面的黑客解决方案是解决这个问题的正确方法;我只是在解释为什么获取这些元素不像用HtmlAgilityPack获取它们那么简单

YouTubeScraper 好的,亚历克斯:你要的,给你。一些真正的黑客代码可以从JavaScript的海洋中提取宝贵的元素

class YouTubeScraper
{
    public HtmlNode FindObjectElement(string url)
    {
        HtmlNodeCollection scriptNodes = FindScriptNodes(url);

        for (int i = 0; i < scriptNodes.Count; ++i)
        {
            HtmlNode scriptNode = scriptNodes[i];

            string javascript = scriptNode.InnerHtml;

            int objectNodeLocation = javascript.IndexOf("<object");

            if (objectNodeLocation != -1)
            {
                string htmlStart = javascript.Substring(objectNodeLocation);

                int objectNodeEndLocation = htmlStart.IndexOf(">\" :");

                if (objectNodeEndLocation != -1)
                {
                    string finalEscapedHtml = htmlStart.Substring(0, objectNodeEndLocation + 1);

                    string unescaped = Unescape(finalEscapedHtml);

                    var objectDoc = new HtmlDocument();

                    objectDoc.LoadHtml(unescaped);

                    HtmlNode objectNode = objectDoc.GetElementbyId("movie_player");

                    return objectNode;
                }
            }
        }

        return null;
    }

    public HtmlNode FindEmbedElement(string url)
    {
        HtmlNodeCollection scriptNodes = FindScriptNodes(url);

        for (int i = 0; i < scriptNodes.Count; ++i)
        {
            HtmlNode scriptNode = scriptNodes[i];

            string javascript = scriptNode.InnerHtml;

            int approxEmbedNodeLocation = javascript.IndexOf("<\\/object>\" : \"<embed");

            if (approxEmbedNodeLocation != -1)
            {
                string htmlStart = javascript.Substring(approxEmbedNodeLocation + 15);

                int embedNodeEndLocation = htmlStart.IndexOf(">\";");

                if (embedNodeEndLocation != -1)
                {
                    string finalEscapedHtml = htmlStart.Substring(0, embedNodeEndLocation + 1);

                    string unescaped = Unescape(finalEscapedHtml);

                    var embedDoc = new HtmlDocument();

                    embedDoc.LoadHtml(unescaped);

                    HtmlNode videoEmbedNode = embedDoc.GetElementbyId("movie_player");

                    return videoEmbedNode;
                }
            }
        }

        return null;
    }

    protected HtmlNodeCollection FindScriptNodes(string url)
    {
        var doc = new HtmlDocument();

        WebRequest request = WebRequest.Create(url);
        using (var response = request.GetResponse())
        using (var stream = response.GetResponseStream())
        {
            doc.Load(stream);
        }

        HtmlNode root = doc.DocumentNode;
        HtmlNodeCollection scriptNodes = root.SelectNodes("//script");

        return scriptNodes;
    }

    static string Unescape(string htmlFromJavascript)
    {
        // The JavaScript has escaped all of its HTML using backslashes. We need
        // to reverse this.

        // DISCLAIMER: I am a TOTAL Regex n00b; I make no claims as to the robustness
        // of this code. If you could improve it, please, I beg of you to do so. Personally,
        // I tested it on a grand total of three inputs. It worked for those, at least.
        return Regex.Replace(htmlFromJavascript, @"\\(.)", UnescapeFromBeginning);
    }

    static string UnescapeFromBeginning(Match match)
    {
        string text = match.ToString();

        if (text.StartsWith("\\"))
        {
            return text.Substring(1);
        }

        return text;
    }
}
原始答案 为什么不改用元素的Id呢

HtmlNode videoEmbedNode = doc.GetElementbyId("movie_player");

更新:哦,伙计,你在搜索JavaScript中的HTML标记?这就是为什么这不起作用的原因。从HtmlAgilityPack的角度来看,它们并不是真正需要解析的标记;所有这些JavaScript实际上是标记中的一个大字符串。也许有某种方法可以将标记的内部文本本身解析为HTML并从中开始。

我得到一个错误代码:HtmlAlityPack.HtmlDocument“不包含“GetElementById”的定义,也没有扩展方法“GetElementById”。@AlexW:看起来b应该是小写的?试试那个GetElementbyId,看看你有没有运气。@Dan Tao-仍然没有抓到任何东西videoEmbedNode==null@AlexW:给我一个url,我也会试试看。@Dan Tao我的意思是任何YT视频url都是好的,就像我在代码中遇到了错误:HtmlAgilityPack.HtmlDocument'不包含“GetElementById”的定义,也没有扩展方法“GetElementById”。@AlexW:看起来b应该是小写的?试试那个GetElementbyId,看看你有没有运气。@Dan Tao-仍然没有抓到任何东西videoEmbedNode==null@AlexW:给我一个url,我也会试试看。@Dan Tao我的意思是任何YT视频url都很好,比如