ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 40155|回复: 38

[讨论] VBA网页取数据的若干问题总结

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2013-6-11 02:32 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖已被收录到知识树中,索引项:网页交互
本帖最后由 moon2778 于 2013-12-10 16:49 编辑

一、插入webbrowser控件 getElementById 方法失效
用VBA从网页上取数据,用getelementsbyid 方法,经过我的测试,没有作用,用getelementsbyname 方法可以,但是因为某些网页上没有写明name,有的甚至id和name都不存在,其取值方法可以采取document.all(index)方式获得,或者document.all.tags("****")(index)获得,或者全部取出,用正则或者split分割。
document.all(index) index获得的具体数值,需要通过遍历得到,具体可以使用这个帖子里面的附件得到。
http://club.excelhome.net/forum.php?mod=viewthread&tid=377077

二、框架结构、js代码生成的网页链接 加载完毕的判断
遇到这个问题往往是真正用到的内容是框架里面的或者js代码里面的链接,不是网址本身的主页面,目前根据我的实践,解决方法有3个:
1、直接用抓包软件找到目标链接地址,然后提交数据请求,返回请求代码,
http://club.excelhome.net/thread-894527-1-1.html这里面提到的方法

2、用框架里面或者链接加载完毕后里面的代码,这个代码要能够跟主页面代码有所区别,就是说主页面里面没有的代码,然后通过在主页面代码里面查找框架或链接里面独特代码是否存在的形式,来完成页面是否加载的判断
,具体代码为:
Do While InStr(主页面代码, "框架某一独特代码") <= 1
DoEvents
Loop

建议主页面代码用一个自定义函数,这样就能够不断更新主代码,比如,我的框架独特代码为queryword,
[code=vb]sub test1()
Do While InStr(textn, "queryWord") <= 1
DoEvents
Loop
end sub
Function textn()
b = Sheets(1).WebBrowser1.Document.body.innerhtml
textn = b
End Function
[/code]


3、延时执行程序,这个方式不推荐.

本帖会根据本人的实践,实时更新





补充内容 (2013-6-14 13:19):
关于插入webbrowser控件 getelementsbyid 方法失效的问题补充:
该方法并没有失效,原因在于拼写错误,getElementById()   getElementsByName()   前面是element  后面是 elements

补充内容 (2013-6-22 17:56):
获取网页元素对象的方法:
1、getelementById("id")
2、getElementsByName("name")
3、getElementsBytagName("tag")
4、getelementsbyclassname("class")(n)--见7楼
5、Document.all()循环与InStr字符串查找结合

补充内容 (2013-9-13 11:38):
6、在以上方法的基础上再次运用上面的方法,比如getelementsbyclassname("class")(0).getelementsbyclassname("BV")(0),还可以加上children,这些加在一起基本够用了

补充内容 (2014-1-2 12:39):
虽然下面的帖子基本说了如何动态加载网页的加载完毕的判断,但是整个过程过于复杂而且也不高效,.ReadyState = "complete"通常只能判断出在页面加载时第一个加载出来的页面,这个可以通过抓包方法得到验证,如火狐firebug

补充内容 (2014-1-2 12:42):
但是我觉得还是要掌握,虽然winhttp和xmlhttp+抓包能够直接抓到目标网址,避开加载其他页面问题,但是由于防盗链会越来越多,所以还是要掌握的为好

补充内容 (2014-1-2 12:45):
鉴于有些同学不知道html基础知识,无法使用相关的方法,无法看懂网页结构,比如getelementById,getelementsbytag,href,url等,在此提供一套讲解html网页制作的视频,应当只看前8讲即可

补充内容 (2014-1-2 12:45):
链接: http://pan.baidu.com/s/1qW32Uw0 密码: 11cc

补充内容 (2014-7-29 15:36):
上面链接已经失效,请点击此链接: http://pan.baidu.com/s/1o69cOKq 密码: l5tp

点评

经过版主纠正,将getelementsbyid 改为 getElementById  发表于 2013-12-10 16:49

评分

4

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-6-16 14:30 | 显示全部楼层
三、插入webbrowser控件方法,如何屏蔽webbrowser打开的网页中图片等
手动的方法是:打开IE,选Tool->Internal Options...
1.去图片: 在Advanced页里面的MultiMedia项下,把Show Pictures前面的勾去掉,如果不要放声音和录像的话可以同样去掉Play Sounds和Play Videos。
2.去脚本: 在Security页下,选Internet或Local Intranet(取决于你的环境),点Custom Level...,然后在Scripting项下的Active Scripts,选Disable。
这样的话你的WebBowser控件就达到你的要求了。
如果要用VBA的话,需要读写注册表。
图片:HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main
Display Inline Images改成"no"就是没有图片。反之是"yes"。
脚本:Internet区:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3的1400改成3就是Disable脚本,如果改成0就是Enable脚本。


TA的精华主题

TA的得分主题

 楼主| 发表于 2013-6-16 14:34 | 显示全部楼层
本帖最后由 new4w 于 2013-6-16 14:42 编辑

四、getelementsbyclassname 无效,如何自己构建函数,以查找定位classname标签
最近,在写程序的时候,发现很多网页代码本身没有放置id属性,tag标签又很难精准定位,而class属性确是有的,所以自己构建了一个classname的函数,代码没有做优化,需要的自己优化下。
[code=vb]
Function tagnub(obj As Object, classname As String) As Integer   
With obj      'obj可以为Sheets(1).WebBrowser1.Document
For m = 0 To .all().Length - 1
If InStr(.all(m).classname, classname) >= 1 Then
tagnub = m
GoTo 100:
End If
Next m
100:
End With
End Function

[/code]





TA的精华主题

TA的得分主题

 楼主| 发表于 2013-6-21 00:55 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 new4w 于 2013-6-21 01:01 编辑

补充:关于前面  框架结构、js代码生成的网页链接 加载完毕的判断
可能有人用到了上述方法,但是还是无法取出网页,或者提示错误或者程序始终处于循环状态,经过本人仔细研究,发现这个是因为网页脚本中,加入的js类的代码,该代码的作用是动态加载网页内容,这里的动态是指,当鼠标或者滚动条滚动到此处时,才会自动加载网页内容,否则网页始终不加载,所以程序就陷入了无限循环,这个解决方法就是模拟滚动条滚动到需要加载内容的区域。
这涉及到两个内容:
第一个网页元素在浏览器页面中的定位方法;
     元素对象相对于目前浏览器顶部位置的像素距离:object.getBoundingClientRect().top
     元素对象相对于目前浏览器左侧位置的像素距离:object.getBoundingClientRect().left
第二个滚动条控制方法;
      Document.parentWindow.scrollBy X,Y(一般x为0,Y为top值)
所以,完整答案为:

用框架里面或者链接加载完毕后里面的代码,这个代码要能够跟主页面代码有所区别,就是说主页面里面没有的代码,然后通过在主页面代码里面查找框架或链接里面独特代码是否存在的形式,来完成页面是否加载的判断,具体代码为:
Do While InStr(主页面代码, "框架某一独特代码") <= 1
DoEvents
Loop

建议主页面代码用一个自定义函数,这样就能够不断更新主代码,比如,我的框架独特代码为queryword,
普通浏览复制代码

[code=vb]
sub test1()
Do While InStr(textn, "queryWord") <= 1
top = Sheets(1).WebBrowser1.Document.getElementById("queryWord").getBoundingClientRect().Top - 300 '注意这里把queryWord看成了一个id值,如果不是,可以在其附近找一个容易取出来的元素代替,注意元素要与目标代码在一个浏览屏幕
WebBrowser1.Document.parentWindow.scrollBy 0, top
DoEvents
Loop
end sub


Function textn()
b = Sheets(1).WebBrowser1.Document.body.innerhtml
textn = b
End Function


[/code]




TA的精华主题

TA的得分主题

 楼主| 发表于 2013-6-21 01:25 | 显示全部楼层
补充:关于WebBrowser1.ReadyState 作为判断是否准确问题
经过实践和最近查找的资料来看,大概分成三种情况:


1\当目标网页加载后,要取的资料在第一个加载返回的页面时,这个是有效的,当不是第一个加载页面时,基本无效,是不是第一个加载页面,需要用watchhttp等抓包工具来查看;


2\当目标数据在非加载的第一个html文档时,通过比较返回的网页代码和目标数据里面的网页代码,似乎可以完成加载完毕的确认(这里的加载完毕是指达到目的,不一定整个网页加载完毕,加载完成了需要的数据的代码段即可);


3\当目标数据在js代码里面时,同时,网页经过js代码控制(这里指当网页没有滚动,则不加载下面网页内容,如果滚动,则代码加载到滚动页面处),通过比较代码的方式可能失效,此时需要加上滚动条控制代码来实现。


这三种情况,抓包软件中的表现为:
2013-06-21 01-17-09.jpg

注:上述内容是根据百度搜索还有部分个人猜测,最近在琢磨网页数据提取的问题,刚开始学些这些,术语不准确,见谅,如有其它问题请朋友们补充下,一起完善网页代码提取的技术

TA的精华主题

TA的得分主题

发表于 2013-6-21 08:19 来自手机 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-6-22 01:42 | 显示全部楼层
本帖最后由 new4w 于 2013-6-22 18:12 编辑

补充:关于getelementsbyclassname方法讨论
目前这一方法IE9 IE10支持,返回的是一个对象集合,但是如果你的浏览器本身是IE9或者IE10,如果你用excel调入插件webbrowser插件,你可能仍然无法使用这一方法,但是可以解决。
1、如果你的浏览器本身IE9以下,那么如果还想用这种方法,就自己编辑一个函数,具体函数见3楼,3楼中知识点有点问题,这个问题就是如果你是IE9或者IE10,你是可以使用这个方法的,但是需要修改注册表。
2、如果你的浏览器是IE9或者IE10,根据微软介绍,通常使用的webbrowser插件的版本是IE7,所以你需要修改注册表,让他默认的webbrowser用IE9或者IE10.


如果你想修改,请注意两个版本的不同,在不同电脑上运行代码,会出现相应问题,如果你愿意接受IE9带来的好处,承受相应损失,请看8楼。
傲游截图20130622014050.jpg
傲游截图20130622013837.jpg

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-6-22 18:09 | 显示全部楼层
本帖最后由 new4w 于 2013-6-22 18:15 编辑

五、关于更改 webbrowser 控件IE内核方法讨论

即使你的IE版本是IE9或者IE10,你实际用的webbrowser 控件IE内核模式仍然是IE7,因为这是默认的,除非你更改它。
如何判定你现在用的webbrowser 控件IE内核?用webbrowser 控件打开这个网址即可:浏览器内核测试地址:http://se.360.cn/v5/iecoretest.html

具体见下面的参考文档:
MSDN參考說明:
http://msdn.microsoft.com/en-us/library/ee330730%28VS.85%29.aspx#browser_emulation
1.webbrowser调用的就是本机IE9,并且webbrowser默认就是运行在IE7 mode下,除非你改变它.
发现一个msdn的帖子,明确表示webbrowser调用的就是本机IE9,并且webbrowser默认就是运行在IE7 mode下,除非你改变它。
How to make c# WebBrowser equivalent to IE browser  
http://social.msdn.microsoft.com/Forums/en/winforms/thread/2ed65b9d-c601-4ca8-bde1-64584fc87515
摘几句:
Wow first post with such bold claim without any source backing up. You probably should read the IE SDK (the manual you need to read if you want to use the webbrowser control) or dig through the IE programming forums (that's the place others often go when they are stuck on IE programming) if you want to use the webbrowser control.
Webbrowser is a wrapper around IE APIs. There is no such thing as multiple versions of IE coexisting on the same computer. You will always get the one and only version of IE installed on the computer from webbrowser control.
There are many, many documented setting differences between default IE and webbrowser. Basically you don't have to opt out new features in webbrowser that may break your app (the Visual Studio team learned a hard lesson here, when IE8 breaks Visual Studio's wizards) , you have to write code to opt in, unless the improvement is security related. That means the webbrowser will run in IE7 mode unless you change the mode in feature control.
Note some web site declare their requirement of IE7 or IE8 mode. It may not be wise to force the IE9 mode.  

2.微软新闻组的一个帖子,Webbrowser Control without IE,里面明确提到,不装IE,无法用webbrowser.
http://groups.google.com/group/microsoft.public.vb.controls/browse_thread/thread/7575bd25e0730ded/aa40f3dfc799407d?lnk=gst&q=WebBrowser+ie#aa40f3dfc799407d
IE must be installed on the machine for you to use Webbrowser Control.
Internet Explorer MUST be installed to use the WebBrowser control.  There are simply no ifs, ands, or buts about it.  How can you expect to use IE functionality if IE is not installed?

3.如何设置WebBrowser在IE9 mode下工作呢?
答曰:需要修改注册表,具体看下面4,5,6,尤其6最全面,可以光看6。

4.WPF webbrowser control using IE7 instead of IE9
http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/4431908e-1869-4435-bcea-a3ec0820edfb
摘抄几句:
How do I make it so the WPF WebBrowser control will use IE9 as the browser engine instead of IE7?
I have some HTML that is rendering differently in the WebBrowser control than in the IE9 browser. When I run the following javascript in the WebBrowser, the result is "7". as in IE7.
I found an article by Rick Strahl that describes registry settings that will get the WebBrowser to use IE9. But I would like to avoid that. And I am interested to know how IE7 comes about being used.http://www.west-wind.com/weblog/ ... ying-the-IE-Version
回答:You want to avoid the only documented way to set document compatibility mode for webbrowser hosts? Why?

5.WebBrowser and CSS3 ?
http://social.msdn.microsoft.com/Forums/en-AU/winforms/thread/1b656af7-bda9-47d9-8f9a-1d886d3688ca
Web browser control by default runs in compatibility mode unless you set the feature browser emulation registry key. The fact that IE9 is able to render CSS3 correctly and browser control is not seems to suggest browser control is not running in IE9 standards mode.
You'll need to set Browser emulation feature key (FEATURE_BROWSER_EMULATION) described at this link http://msdn.microsoft.com/en-us/library/ee330730%28v=vs.85%29.aspx
You can use 9000 value, unless you want to force IE 9 standards mode for all pages. In case of later, you need to use 9999.
hklm
If hklm and 64bit machine used, you need to check is Wow6432Node needs to be changed.
And finally you need to add process name hosting browser control as value name in the registry key.
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION]
"prevhost.exe"=dword:00001f40
"sllauncher.exe"=dword:00001f40
"WindowsFormsApplication1.exe"=dword:0000270f

6.Web Browser Control – Specifying the IE Version
http://www.west-wind.com/weblog/posts/2011/May/21/Web-Browser-Control-Specifying-the-IE-Version
I use the Internet Explorer Web Browser Control in a lot of my applications to display document type layout. HTML happens to be one of the most common document formats and displaying data in this format – even in desktop applications, is often way easier than using normal desktop technologies.
One issue the Web Browser Control has that it’s perpetually stuck in IE 7 rendering mode by default. Even though IE 8 and now 9 have significantly upgraded the IE rendering engine to be more CSS and HTML compliant by default the Web Browser control will have none of it. IE 9 in particular – with its much improved CSS support and basic HTML 5 support is a big improvement and even though the IE control uses some of IE’s internal rendering technology it’s still stuck in the old IE 7 rendering by default.
This applies whether you’re using the Web Browser control in a WPF application, a WinForms app, a FoxPro or VB classic application using the ActiveX control. Behind the scenes all these UI platforms use the COM interfaces and so you’re stuck by those same rules.
Feature Delegation via Registry Hacks
Fortunately starting with Internet Explore 8 and later there’s a fix for this problem via a registry setting. You can specify a registry key to specify which rendering mode and version of IE should be used by that application. These are not global mind you – they have to be enabled for each application individually.
There are two different sets of keys for 32 bit and 64 bit applications.
32 bit:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
Value Key: yourapplication.exe
64 bit:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
Value Key: yourapplication.exe
The value to set this key to is (taken from MSDN here) as decimal values:
9999 (0x270F)
Internet Explorer 9. Webpages are displayed in IE9 Standards mode, regardless of the !DOCTYPE directive.
9000 (0x2328)
Internet Explorer 9. Webpages containing standards-based !DOCTYPE directives are displayed in IE9 mode.
8888 (0x22B8)
Webpages are displayed in IE8 Standards mode, regardless of the !DOCTYPE directive.
8000 (0x1F40)
Webpages containing standards-based !DOCTYPE directives are displayed in IE8 mode.
7000 (0x1B58)
Webpages containing standards-based !DOCTYPE directives are displayed in IE7 Standards mode.

是不是看晕了,我是的,下面转换成咱们看得懂的语言表述下:
1,打开注册表(win7在运行里面输入regedit即可打开注册表)32位系统:HKEY_LOCAL_MACHINE (or HKEY_CURRENT_USER)
SOFTWARE
Microsoft   
Internet Explorer   
Main            
FeatureControl   
FEATURE_BROWSER_EMULATION     
contoso.exe = (DWORD) 00000000其中的"contoso.exe"为您的程序名字.即嵌入了WebBrowser控件的可执行程序的名字.

我直接换成了excel.exe后面的数值"00000000"代表WebBrowser控件使用的IE的版本,值对应的IE版本如下图:我用的是10000,十进制的

附上本人的修改(这里的excel.exe是我通过右键新建,DWORD32位,建立的) 傲游截图20130622013837.jpg
如果您使用的是64位的操作系统,而你的程序是32位的,那么你则要在以下注册表中更改该值
.HKEY_LOCAL_MACHINE (or HKEY_CURRENT_USER)
SOFTWARE
Wow6432Note
Microsoft
Internet Explorer
Main
FeatureControl
FEATURE_BROWSER_EMULATION
contoso.exe = (DWORD) 00000000
360浏览器,傲游浏览器,淘宝浏览器等都可以用这种方式来操作.


看结果,这个方法的确可以使用。
傲游截图20130622014050.jpg


注意:如果更换了webbrowser用的基础IE版本,如果换了电脑,由于对方的IE版本可能不同,会引起一些列问题,需要注意。
目前发现:
  • excel2013,在插入webbrowser控件存在问题,无法插入,可能需要修改注册表等,具体解决方案暂没有看到。
  • childnodes在IE9 IE10下,存在问题,需要用children来代替;
  • getBoundingClientRect()方法在IE7下可以用getBoundingClientRect().bottom(right/top),但是IE9 10就需要加入元素名称getBoundingClientRect("id").bottom,才不会弹出错误。
  • 另外特别提醒的是getelementsbyclassname()方法返回的是对象数组,所以如果返回代码或者文本,需要getelementsbyclassname(“classname”)(0).innerhtml
部分网页由于兼容问题,如果更换不同的IE版本,很多以前的问题,可能不是问题。

浏览器内核测试地址:http://se.360.cn/v5/iecoretest.html


TA的精华主题

TA的得分主题

 楼主| 发表于 2013-6-25 11:29 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
六、一些网页操作注意细节
1、click无反应
通常原因为没有定位到争取的位置,click的发生,是因为存在链接,所以一定要定位到链接上,再click,比如定位到<a>或者submit上,而不是定位到<li>  <ul> <div>上,因为对象本身不存在链接,所以click方法也就无效了。


2、获取网页数据,在循环时,尽量先判断,再执行;
如果先执行,再判断可能会出现执行的第一步网页还没有加载好,而执行的第二步网页此时正好加载好,这里就存在出现漏洞的机会


3、注意每一次点击后,都要加入代码判断点击后网页是否加载完毕,否则容易出现问题,这里判断的方法推荐用1楼中的对加载完毕的判断方法。



补充内容 (2013-8-13 14:40):
4、涉及循环的时候,尽量加入doevents 这个语句,可以防止程序陷入假死状态

补充内容 (2013-8-13 14:44):
5、为了防止webbrowser控件,经常弹出脚本错误,首选在ie浏览器里面设置好,显示每个脚本错误,去掉勾选,然后在程序中加入代码 webbrowser.silent=ture

补充内容 (2013-9-13 10:13):
上述说明经过这段时间实践,发现有部分错误,以15楼为准

TA的精华主题

TA的得分主题

发表于 2013-7-11 07:28 | 显示全部楼层
好,这里既有经验的总结,又有方法的探讨,还说的很全面,详细和具体,非常适合学习
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-22 00:46 , Processed in 0.046156 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表