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都很好,比如