在最近的数据采集研究中, 发现很多页面的内容都是在iframe中的, 这位采集带来了不少困难. 经过一番思考之后, 我想到了C#的解决办法:
1. 运行Spider Studio, 加载页面 http://www.w3school.com.cn/tiy/t.asp?f=html_iframe
2. 编辑代码, 将iframe指向 http://www.w3school.com.cn
3. 这个页面具备如下结构:
Page > IFrame1 -> IFrame2 (就是我们代码中写的那个IFrame)
我的目标是通过C#代码先获取IFrame1的内容, 然后继续获取IFrame2的内容, 继而设置IFrame2的src到 GDT首页 去.
4. 获取IFrame1
var iframe1 = Default.SelectSingleNode("#result iframe").Contents().SelectSingleNode("body"); if(iframe1.IsEmpty() == false) { MessageBox.Show(iframe1.Html()); }
此时显示结果正确, 证明成功取到了IFrame1的内容:
5. 获取IFrame2
var iframe2 = Default.SelectSingleNode("#result iframe").Contents().SelectSingleNode("iframe").Contents().SelectSingleNode("body"); if(iframe2.IsEmpty() == false) { MessageBox.Show(iframe2.Html()); }
此时显示结果正确, 证明也成功取到IFrame2的内容了:
6. 设置IFrame2的Src
iframe2 = Default.SelectSingleNode("#result iframe").Contents().SelectSingleNode("iframe"); //重新定位iframe2到IFrame元素上 iframe2.Attr("src", "http://www.gdtsearch.com");
此时IFrame2已经跳转, 结果正确!
7. 全部预期功能实现, 现在所说已知的局限性:
7.1 不兼容跨域访问
如果iframe中的页面和父页面不在一个域名下面, 这段代码因为安全性的原因是失效的. 比如我将iframe2的src换成 http://www.gdtsearch.com, 那么相应的取iframe2.Body的时候就会报错:
7.2 判断IFrame中页面何时加载完成的代码逻辑有点复杂, 我写了一个方法供大家参考:
public void IFrameReady(JQueryContext iframe, string jQueryExpr) { while(Default.Available) { var contents = iframe.Contents(); if(contents.IsEmpty() == false) { var node = contents.SelectSingleNode(jQueryExpr); if(node.IsEmpty() == false && node.Html().Trim().Length > 10) { return; } } Thread.Sleep(1000); Application.DoEvents(); } }
8. 和Spider Studio采集以及相关脚本编写的其他文章: