如何获取 Frames/IFrames 中的 HtmlElement 值?
How to get an HtmlElement value inside Frames/IFrames?
我正在使用 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");
我已经 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
.
一个例子(与当前任务相关):
- 订阅 WebBrowser Control/Class 的 DocumentCompleted 事件。
- 检查 WebBrowser.ReadyState 属性 以验证文档是否已完全加载。
注:
请记住,一个网页可能由 Frames/IFrames 中包含的多个文档组成,如果使用 ReadyState = WebBrowserReadyState.Complete
.
多次引发该事件,我们不会感到惊讶。
每个框架的 Document
将在 WebBrowser
完成加载时引发事件。
- 使用Frame.Document.Body.GetElementsByTagName()方法解析
Document.Window.Frames
集合中每个Frame的HtmlDocument
。
- 使用HtmlElement.GetAttribute方法提取
HtmlElements
Attibute
。
注:
由于多次引发 DocumentCompleted
事件,我们需要验证 HtmlElement
属性值也没有被多次存储。
在这里,我使用支持自定义 Class,它保存所有收集的值以及每个引用 Link 的 HashCode(此处,依赖于 GetHasCode()
的默认实现)。
每次解析一个 Document 时,我们检查一个值是否已经存储,比较它的 Hash。
- 当我们确认已找到重复哈希时停止解析:框架文档元素已被提取。
注:
在解析 HtmlWindowCollection
时,不可避免地会引发一些特定的异常:
- UnauthorizedAccessException: 部分Frames无法访问
- 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
}
}
我正在使用 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");
我已经 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
.
一个例子(与当前任务相关):
- 订阅 WebBrowser Control/Class 的 DocumentCompleted 事件。
- 检查 WebBrowser.ReadyState 属性 以验证文档是否已完全加载。
注:
请记住,一个网页可能由 Frames/IFrames 中包含的多个文档组成,如果使用 ReadyState = WebBrowserReadyState.Complete
.
多次引发该事件,我们不会感到惊讶。
每个框架的 Document
将在 WebBrowser
完成加载时引发事件。
- 使用Frame.Document.Body.GetElementsByTagName()方法解析
Document.Window.Frames
集合中每个Frame的HtmlDocument
。 - 使用HtmlElement.GetAttribute方法提取
HtmlElements
Attibute
。
注:
由于多次引发 DocumentCompleted
事件,我们需要验证 HtmlElement
属性值也没有被多次存储。
在这里,我使用支持自定义 Class,它保存所有收集的值以及每个引用 Link 的 HashCode(此处,依赖于 GetHasCode()
的默认实现)。
每次解析一个 Document 时,我们检查一个值是否已经存储,比较它的 Hash。
- 当我们确认已找到重复哈希时停止解析:框架文档元素已被提取。
注:
在解析 HtmlWindowCollection
时,不可避免地会引发一些特定的异常:
- UnauthorizedAccessException: 部分Frames无法访问
- 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
}
}