ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] 网页采集(网页提交)教程第一课-用XMLHTTP获取数据并用Adodb.Stream转换编码提取信息

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2012-7-15 13:52 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:网页交互
本帖最后由 心电感应 于 2015-3-21 11:28 编辑

******************** 提示 **********************
1、想学习网页采集,请务必提前学习VBA的基本操作常识,不要奢望用金山WPS来使用带有宏的工作簿,谢谢!                                    
2、如果有代工需求的,请务必理解什么是尊重劳动,不要奢望使小钱做大事,亦不要奢望花一份钱做多件事,谢谢!

3、网页采集课程的注意事项及必备能力

****************************************************************************************

第一课:http://club.excelhome.net/thread-893760-1-1.html
第二课:http://club.excelhome.net/thread-894527-1-1.html
第三课:http://club.excelhome.net/thread-896608-1-1.html
第四课:http://club.excelhome.net/thread-897117-1-1.html
第五课:http://club.excelhome.net/thread-899268-1-1.html

高级篇:
第一课:http://club.excelhome.net/thread-902266-1-1.html
第二课:http://club.excelhome.net/thread-939881-1-1.html


本示例是为了解决http://club.excelhome.net/thread-893673-1-1.html此帖问题。


********************* 我是上课的分割线 **********************

初学者学习网页采集要经历的几大难关:
1、如何找到抓取的数据所在的网页链接---用httpfox或者fiddler2
2、如何得到数据-------------------------------用Microsoft.XMLHTTP、Msxml2.XMLHTTP、MSXML2.ServerXMLHTTP、WinHttp.WinHttpRequest.5.1对象
3、如何转换编码-------------------------------用Adodb.Stream对象
4、如何得到最终需要的数据-----------------vba字符串处理的基本功(字符串和数组处理,split、replace、filter、正则等)

下面看一个简单的网页采集例子
  1. Sub test()
  2.     Dim strRespText$, tt$, i&, DW$
  3.     Dim URL
  4.     URL = "******************************"          '链接请看楼顶说明里的帖子,俺这里就不写了,以免被防水墙删贴
  5.     With CreateObject("Microsoft.XMLHTTP")
  6.         .Open "GET", URL, False                     '要抓取的链接,"GET"尽量用大写,以免某些系统不兼容
  7.         .Send
  8.         tt = .responsetext
  9.         With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")    'DataObject对象,数据放入剪贴板,记事本观察数据
  10.             .SetText tt                                                    '因为XMLHTTP默认是UTF-8,不能识别gb2312,会发现数据乱码
  11.             .PutInClipboard                                                '所以不能采用.responsetext对象来得到字符串
  12.         End With
  13.         tt = BytesToBstr(.ResponseBody, "GB2312")                          '因此要用Adodb.Stream对象
  14.         'tt = StrConv(.ResponseBody, vbUnicode,&H804)                     '或者StrConv函数,从.ResponseBody得到字符串
  15.         'tt = StrConv(.ResponseBody, vbUnicode)                            '因网页为GB2312,简体版的操作系统也可以不写第三个参数
  16.         With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")    '得到的字符串放入剪贴板,记事本观察数据
  17.             .SetText tt                                                    '数据正常显示,可以提取了
  18.             .PutInClipboard
  19.         End With
  20.         tt = Replace(tt, vbCrLf, "")                                       '清理要提取的数据,准备提取
  21.         tt = Replace(tt, "</font></b></td>                  <td width=""392""><font size=""2"">", "")
  22.         DW = Split(Split(tt, "报考单位:")(1), "<")(0)                     '提取数据
  23.         MsgBox DW
  24.     End With
  25. End Sub
复制代码
下面是采集用到的Bstr编码转换函数
  1. Function BytesToBstr(strBody, CodeBase)         '使用Adodb.Stream对象提取字符串
  2.     Dim objStream
  3.     On Error Resume Next
  4.     Set objStream = CreateObject("Adodb.Stream")
  5.     With objStream
  6.         .Type = 1                               '二进制
  7.         .Mode = 3                               '读写
  8.         .Open
  9.         .Write strBody                          '二进制数组写入Adodb.Stream对象内部
  10.         .Position = 0                           '位置起始为0
  11.         .Type = 2                               '字符串
  12.         .Charset = CodeBase                     '数据的编码格式
  13.         BytesToBstr = .ReadText                 '得到字符串
  14.     End With
  15.     objStream.Close
  16.     Set objStream = Nothing
  17.     If Err.Number <> 0 Then BytesToBstr = ""
  18.     On Error GoTo 0
  19. End Function
复制代码
注意:如果网站是UTF-8编码的,不需要使用上面的函数进行转码,XMLHTTP默认会识别的。

VBA高级教程之基础篇--字符串和编码,使用ADODB.Stream转换ANSI/UNICODE/UTF-8等编码

交流:如何封装和保护Excel文件里面的公式及VBA代码,防止被抄袭和非授权外流

http://msdn.microsoft.com/zh-cn/library/ie/bg182326%28v=vs.85%29.aspx
使用 F12 开发人员工具











评分

45

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-7-15 13:53 | 显示全部楼层
本帖最后由 liucqa 于 2015-4-22 23:02 编辑

捕获.JPG

本例使用FireFox浏览器配合Httpfox查找数据链接

方法如下:
1、启动FireFox,启动Httpfox,点击start
2、在浏览器地址栏输出地址,回车
3、在httpfox窗口中可以看到捕获的http链接请求
4、依次点击捕获到的链接,在httpfox的Content标签里面,查找是否有需要的数据

本例中,捕获到的第一个链接就是需要的数据链接,因此该链接即可作为XMLHTTP的get提交

注意,不同的网站提交的方法不一样,一般有GET和POST两种方式,提交的模式又分同步或异步两种模式。
如果你发现换页之后数据变化而链接不变,则是使用POST提交的

本课只讲解最简单的"GET"方式提交(同步模式)
**********************************************

http://www.cnblogs.com/TankXiao/archive/2012/02/06/2337728.html

Fiddler 教程
Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说,都有很大的帮助。
阅读目录






捕获1.JPG
捕获.JPG

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-7-15 13:54 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 liucqa 于 2013-4-10 23:36 编辑

捕获1.JPG

识别网页的编码,点击浏览器菜单--查看--字符编码

本例是gb2312。因XMLHTTP默认识别的编码是UTF-8,因此直接从.responsetext对象得到的字符串会发现其中的汉字为乱码。

捕获0.JPG

所以使用Adodb.Stream对象来进行字符串的提取

一楼示例中的 BytesToBstr函数,就是将通过XMLHTTP的.ResponseBody得到的二进制数组(GET得到的网页原始数据)传递给Adodb.Stream对象,然后设置编码字符集,以便Stream对象能够识别二进制数据,再通过Stream对象的.ReadText方法得到二进制数据转换之后的字符串。

这样就可以提取数据了。

**********************

另一种常用的转换方法是使用StrConv函数
tt = StrConv(.ResponseBody, vbUnicode, &H804)
    这个函数可以将Locale ID (LCID 区域标志符) 的ANSI数组转成Unicode字符串,,在简体中文版里面就是gb2312转成Unicode。如果数组是非ANSI编码或者LCID错误,则不能正确显示字符串。
针对GB2312的网页,在简体版系统中可以直接使用默认的LCID,tt = StrConv(.ResponseBody, vbUnicode)

**********************

考虑到网站编码转换的灵活性,我推荐使用Adodb.Stream对象。
这个对象比StrConv的处理能力要强许多,大部分网页编码都支持,可以直接处理数据流,通用性好一些。

参考此帖http://club.excelhome.net/thread-868093-1-1.html

使用Adodb.Stream对象,要求您的机器上要安装有ADO2.5或者更高版本

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-7-15 13:55 | 显示全部楼层
本帖最后由 liucqa 于 2013-4-11 00:13 编辑

得到编码之后的网页数据,如何提取需要的信息呢?

捕获.JPG

请看上图,我们需要提取的信息是报考单位的信息,在Adodb.Stream得到的字符串粘贴到记事本之后,我们可以很容易地找到需要的信息。
在"报考单位:"  与  "法院机关服务中心"之间,有许多HTML的标识,如何处理呢?

这个时候,就看各位的VBA字符串处理的基本功了。

一般处理的步骤如下:
1、找到信息块的头部标记,找到信息块的尾部标记,用split函数掐头去尾,得到准备处理的数据块。(此步骤也可以省略)
2、找到提取数据的一个分隔标识字符串,此例中是  "报考单位:"
3、处理分隔标识字符串与实际需要的信息之间的无用字串。一楼示例中,使用两个replace语句去掉了换行符和HTML标记。如果你不知道怎么找到需要替换的字符是什么,慢慢在记事本里面钻研好了。可以一点一点替换,早晚会找到需要替换的字符串的。

捕获2.JPG

4、通过上面几步,我们得到字符串为   "报考单位:法院机关服务中心<",再使用split语句,就可以得到需要的信息了

复杂的处理需要使用正则,这不在本文的讨论范围



TA的精华主题

TA的得分主题

 楼主| 发表于 2012-7-15 13:55 | 显示全部楼层
本帖最后由 liucqa 于 2015-2-11 22:26 编辑

下面说一下几个提取网页所用到的对象的异同

"Microsoft.XMLHTTP"  微软官网上说这是MSXML 2.x系列版本的progid。比较古老,简单用用可以。MSXML2稳定性要好一些。
"MSXML2.XMLHTTP"  相当于"MSXML2.XMLHTTP.3.0"
"Msxml2.XMLHTTP.4.0"
“Msxml2.XMLHTTP.5.0"
"Msxml2.XMLHTTP.6.0"
     以上几个对象,在不同系统中不一定都存在,使用前可以测试一下,一般的说,安装了office 2007之后,除了4.0,别的应该都可以使用的。
    上述对象依赖于Microsoft Win32 Internet (WinInet),与IE同内核的,他们的COOKIE和缓存是和IE共用的,要是你能解决跨域问题,用IE登录某站后,再用他们登录也会是登录状态的。所以他们和IE一样是有本地缓存的,同一网页缓存未过期,请求过一次再次请求会很快。因为这时是直接读取了缓存数据。
     这也是为什么有些人用这个组件做实时数据抓取的时候,发现网页数据已刷新,而使用代码采集到的数据却更新不及时的原因。
     MSXML2.XMLHTTP访问网页可以一般很方便cookie是自动处理,用setRequestHeader方法可以指定其他http头但不能指定cookie。5.0之后可以指定cookie。但Msxml2.XMLHTTP.6.0版本不能设置referer的(好像微软出于安全原因给去掉了),今天测试发现5.0也没有Referer(2013.1.14)

WinHttp.WinHttpRequest.5.1
     WinHTTP比WinINet更加安全和健壮,这个组件独立于IE,没有本地缓存,其代理服务器的设置也是独立于IE的(使用Proxycfg或者NetSh设置代理),支持网页重定向,支持修改Cookie和referer,可以用于解决网站的防盗链问题。但是这个组件毛病也不少,实际用起来往往执行结果与想象中的不太一样,需要耐心调试,甚至要用Sniffer抓包调试。该组件支持HTTPS。Winhttp使用起来适应性最广,参数较多。
     WinHTTP在编码转换上与其他组件不同的是,貌似返回的Head如果没有Content-Type: text/html; charset=utf-8的标识,就不转换UTF-8编码(Win7测试发现),即使返回的数据有UTF-8的BOM头(239,187,191)也不转换。
http://msdn.microsoft.com/en-us/library/aa384106%28v=vs.85%29.aspx   WinHttpRequest object
http://msdn.microsoft.com/en-us/library/aa384108.aspx                               WinHttpRequestOption enumeration
http://www.playes.net/Blog/595.asp                                                             WinHttp.WinHttpRequest.5.1

MSXML2.ServerXMLHTTP
1、这个对象依赖于 HTTP 客户端堆栈 WinHTTP,所以很多用法与WinHttp类似。如果MSXML2.XMLHTTP对象不好使的话,可以换这个对象,再不好用就换winhttp。
2、ServerXMLHTTP可以用SetTimeouts自定义超时,XMLHTTP是默认超时。
3、ServerXMLHTTP在内部支持重定向,可以跨域访问,即你访问的地址如果跳到另外的域名去了,它也可以继续请求页面,而XMLHTTP会抛出异常,说:禁止访问
4、如果你用的是MSXML2.ServerXMLHTTP.4.0及更高版本的对象,那么可以用.getOption(-1) 来获得最终页面地址 http://support.microsoft.com/kb/308607/zh-cn
5、新版ServerXmlhttp的referer貌似也被微软封掉了

Msxml2.ServerXMLHTTP
Msxml2.ServerXMLHTTP.3.0
Msxml2.ServerXMLHTTP.4.0
Msxml2.ServerXMLHTTP.5.0
Msxml2.ServerXMLHTTP.6.0


在一楼的示例中,将CreateObject("Microsoft.XMLHTTP")里面的Microsoft.XMLHTTP换成上述任意一个对象,都可以得到相同的结果。

参考资料
http://club.excelhome.net/forum.php?mod=redirect&goto=findpost&ptid=869382&pid=5952249

http://msdn.microsoft.com/en-us/library/aa382925%28VS.85%29.aspx        About WinHTTP
Fiddler中文使用教程,解决乱码.rar (1.01 MB, 下载次数: 1713)

点评

Msxml2.XMLHTTP.5.0支持伪造COOKIE和REFERER,所以现在,除了重定向的页面,很少用到WINHTTP了。  发表于 2012-7-15 21:29

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-7-15 13:56 | 显示全部楼层
本帖最后由 liucqa 于 2019-5-20 23:40 编辑

第一课小结:

    本课以一个实例,讲解了获取网页数据链接、识别汉字编码、转换和处理字符串并得到所需要的数据的简单方法。请同学们课后找一些网站多多测试、练习抓包软件的使用方法和获取字符串之后用split等函数提取数据的基本功。

    在实际的网页采集中,往往我们会碰到比示例的网站复杂几倍乃至几十倍的网页。一个完整的网页采集程序,需要处理以下问题:
    1、如果有必要的话,登录网站。可能需要过验证码(需要获取图片以及做OCR识别)
    2、找到网站的初始链接,获取Cookie或者viewstate等隐藏的submit信息,为提交真正的数据链接做准备。
    3、如果有必要的话,找到网站中文语言的设置方法,可能是直接写在链接里面、可能写在提交的参数里面、可能要做专门的语言设置链接提交。
    4、找到网站的数据链接,抓包获取Referer值,解决防盗链
    5、处理初始网页,获取为后面数据链接提交所需要的参数(可能没有,也可能有许多)
    6、处理网站数据链接的提交参数(可能有时间戳),可能是GET方式、可能是POST方式。后者还要处理URLEncode编码或其他形式的编码问题(如果是UTF-8编码,XMLHTTP会自己处理;WinHttp可以通过参数选择URL编码的格式)。
    7、判断网站返回数据的编码,处理成可以识别的字符串(可能需要htmlfile对象来快速操作html文档中的表格等)
    8、处理需要采集数据的字符串,可能要从中提取页码,可能要提取下一页的参数、可能要用数组的方式提取所需要的信息(网页表格尤其如此)
    9、循环执行6~8,直至数据提取结束


    其实,无论网站有多么复杂,获取数据的基础无外乎两点:
    1、抓包看链接、Cookie、Referer、Post参数、隐藏的submit参数、MD5或者RSA加密参数等等,然后模拟提交
    2、处理编码并提取字符串
    只要精通这两个基本步骤,再加上充裕的时间、坚定的信念、充分的耐心和一点点运气,网页采集的工作就迎刃而解了!


    相信我吧

另附VBA调用JS函数的几个方法
http://club.excelhome.net/thread-1478285-1-1.html





点评

反正我就信了  发表于 2012-8-23 15:06

评分

8

查看全部评分

TA的精华主题

TA的得分主题

发表于 2012-7-15 14:01 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2012-7-15 14:18 | 显示全部楼层
本帖最后由 ExcelHome 于 2012-10-6 16:00 编辑

一起期待, 大侠辛苦了。重新干同样的事确实很郁闷啊。。。。

TA的精华主题

TA的得分主题

发表于 2012-7-15 15:01 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
在线学习,等教程

TA的精华主题

TA的得分主题

发表于 2012-7-15 15:12 | 显示全部楼层
liucqa 发表于 2012-7-15 13:54
识别网页的编码,点击浏览器菜单--查看--字符编码

本例是gb2312。因XMLHTTP默认识别的编码是UTF-8, ...

水侠开始务实了,恭喜呀。非常好的资料,强烈顶起。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-29 01:34 , Processed in 0.063116 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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