ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: wcymiss

[原创] 不懂html也来学网抓(xmlhttp/winhttp+fiddler)

    [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 14:29 | 显示全部楼层
本帖已被收录到知识树中,索引项:网页交互
本帖最后由 wcymiss 于 2014-10-21 16:01 编辑

获取数据-直接获取-POST

Open第一参数是“POST"的时候,Send方法一般会有参数。

举例:
网站:http://cn.zso8.com/odds/search/
操作:第一行,“联赛选择”内选择“英超”,然后点击最右边的“确定”,获取该数据。

用fiddler找到数据页面,查看Request框Raw里的内容:
POST1.png


同之前一样,填入“POST”,填入URL。然后,复制“type=2&CompanyID.......”这部分字符串,作为Send的参数。
代码成型:
  1. Sub Main()
  2.     Dim strText As String
  3.     With CreateObject("MSXML2.XMLHTTP") 'CreateObject("WinHttp.WinHttpRequest.5.1")
  4.         .Open "POST", "http://cn.zso8.com/odds/search/", False
  5. '        .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
  6. '        .setRequestHeader "Referer", ""
  7.         .Send "type=2&CompanyID=11%7C%E6%BE%B3%E9%97%A8&leagueID=36&teamID=0&kind=1&port=&odds1=&do0=%E7%A1%AE%E5%AE%9A"
  8.         strText = .responsetext
  9.         Debug.Print strText
  10.     End With
  11. End Sub
复制代码
运行。。。。然后发现,没有成功!

立即窗口没有数据:
POST2.png

Response框里是有数据的:
POST3.png


为什么没有成功呢?因为没有模拟setRequestHeader!
经验:“POST”时,一般都需要模拟setRequestHeader的“Content-Type”字段(Header)。

再回头,拷贝出Request中的Content-Type后面的值:application/x-www-form-urlencoded,填入代码中。
POST4.png


第二次成型代码:
  1. Sub Main()
  2.     Dim strText As String
  3.     With CreateObject("MSXML2.XMLHTTP") 'CreateObject("WinHttp.WinHttpRequest.5.1")
  4.         .Open "POST", "http://cn.zso8.com/odds/search/", False
  5.         .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
  6. '        .setRequestHeader "Referer", ""
  7.         .Send "type=2&CompanyID=11%7C%E6%BE%B3%E9%97%A8&leagueID=36&teamID=0&kind=1&port=&odds1=&do0=%E7%A1%AE%E5%AE%9A"
  8.         strText = .responsetext
  9.         Debug.Print strText
  10.     End With
  11. End Sub
复制代码
运行,查看立即窗口,这次有数据了:
POST5.png


小贴士:
Content-Type后面的值大部分都是application/x-www-form-urlencoded,但也有些网页不是这样的内容。每次代码模拟一定要和Request框内的内容保持一致,不要掉以轻心。

评分

4

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 15:20 | 显示全部楼层
本帖最后由 wcymiss 于 2014-10-22 12:36 编辑

新手作业:
网站:http://www.pinble.com/Lottery.htm
操作:点击“各省体彩”---“江苏七星彩”,获取江苏七星彩的数据。
说明:同样,代码只需在ResponseText获取到所需数据就行了。不需要整理。



这个数据网页的确认稍有点难度,要有耐心。嘿嘿。

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 15:25 | 显示全部楼层
本帖最后由 wcymiss 于 2014-10-22 16:52 编辑

获取数据-直接获取-静态参数:

在Request框内经常能看到各种参数。

参数用于客户端与服务器的交互。
参数的结构形式是:
    参数名1=参数值1&参数名2=参数值2&参数名3=参数值3.....
参数存在于SendData中(即vba代码里Send方法后面的那部分,又称POSTData、SendBody等),也存在于URL中。

在15楼的例子,参数存在于SendData中:
type=2&CompanyID=11%7C%E6%BE%B3%E9%97%A8&leagueID=36&teamID=0&kind=1&port=&odds1=&do0=%E7%A1%AE%E5%AE%9A

14楼的作业,参数存在于URL里。

点击Request框的WebForms按钮可清楚的查看各参数:
上面的“QueryString”框内显示的是URL部分的参数明细;
下面“Body"框内显示的是SendData部分的参数明细。
SendData1.png

通过多次对网站不同操作的抓包对比,可分析出每个参数各自对应的页面的选项。据此,在代码里定义多个变量,可动态获取各种不同的查询结果。

没有值的参数,大多时候可以省略。比如:
type=2&CompanyID=11%7C%E6%BE%B3%E9%97%A8&leagueID=36&teamID=0&kind=1&port=&odds1=&do0=%E7%A1%AE%E5%AE%9A
可以省略写成:
type=2&CompanyID=11%7C%E6%BE%B3%E9%97%A8&leagueID=36&teamID=0&kind=1&do0=%E7%A1%AE%E5%AE%9A


上述URL或SendData里的参数都是大部分都是静态的(14楼作业2里有一个参数非静态),也就是说,不管何时何地,只要服务器后台代码不改变,相同的页面选择,参数总也是相同的。

但很多网页都有动态参数。动态参数有防盗链的效果。即使你操作手法完全相同,动态参数也会有不同。这个在之后的知识点里会有具体讲解。

小贴士:查询的数据有多页时,这个页码会以参数的形式体现在发包头内。

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 16:10 | 显示全部楼层
本帖最后由 wcymiss 于 2014-10-30 10:11 编辑

获取数据-直接获取-转码:

在15楼的例子中:

从Request框的WebForms中可以看到:
CompanyID参数的值是“11|澳门”
do0参数的值是“确定”

但在Raw里看到的是:
CompanyID=11%7C%E6%BE%B3%E9%97%A8
do0=%E7%A1%AE%E5%AE%9A

这样的转换,可以用Javascript转换函数encodeURI或encodeURIComponent来实现(两者区别请自行百度)。

为了使代码容易解读,也为了让代码更换参数更加方便,我们将15楼的代码改动为:
  1. Sub Main()
  2.     Dim strText As String
  3.     With CreateObject("MSXML2.XMLHTTP") 'CreateObject("WinHttp.WinHttpRequest.5.1")
  4.         .Open "POST", "http://cn.zso8.com/odds/search/", False
  5.         .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
  6. '        .setRequestHeader "Referer", ""
  7.         .Send "type=2&CompanyID=" & encodeURI("11|澳门") & "&leagueID=36&teamID=0&kind=1&port=&odds1=&do0=" & encodeURI("确定")
  8.         strText = .responsetext
  9.         Debug.Print strText
  10.     End With
  11. End Sub
复制代码
自定义函数encodeURI请从11楼里复制。

但字符编码的类型有很多。上述只是一种比较常见的类型。一般来说,当一个中文转成3个16进制的码时(“%XX”为一个16进制码),适合用javascript的encodeURI或encodeURIComponent函数来解码。(实质是utf-8编码)

有时候是这样的编码:“abc一二三”转换为“abc%D2%BB%B6%FE%C8%FD” (ET的登录,用户名就是这样的编码)
在vba里,hex(asc("一"))="D2BB",所以,用循环及文本函数可以很容易写出转码的自定义函数:
  1. Function GBKEnCode(strText)
  2.     Dim i, s
  3.     For i = 1 To Len(strText)
  4.         s = Hex(Asc(Mid(strText, i, 1)))
  5.         If Len(s) = 4 Then s = Left(s, 2) & "%" & Right(s, 2)
  6.         GBKEnCode = GBKEnCode & "%" & s
  7.     Next
  8. End Function
复制代码
有人说,你这样连“abc”三个字符都转成“%61%62%63”了。。。没错,确实全部转了。但全部转了也可以Send成功的。不信你试试?

至于其他类型的编码,我想,只要你熟悉循环和文本函数,再了解下vba里的hex,asc,chr,ascw,chrw,总能写出自定义的转码函数的。

评分

3

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 16:52 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
吐槽:
卡死我了,是EH慢还是我的网速慢?一下午就写了这点帖子!每次都要刷新好多次才能成功发帖!我的网速昨天下载速度还上了8M/s的。。。

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 21:39 | 显示全部楼层
本帖最后由 wcymiss 于 2014-10-22 07:14 编辑

获取数据-防盗链的处理-模拟Referer:


当你的vba代码中:
GET部分后面的URL与Request框中的一摸一样;
或是POST的URL、SendData,与Request框中的一摸一样,Content-Type也没有忘记setRequestHeader;
但数据仍旧无法获取时,那你要获取的数据网页一定加了某种防盗链的措施。

此时要开始我们漫长的抓包调试过程了。(路漫漫其修远兮。。。)

调试这样的防盗链网页,如果在Request框中看到有这样的字样:
Referer: http://.......
那么,你首选模拟Referer(因为模拟Referer最简单)

在xmlhttp对象里模拟Referer是无效的。必须要用winhttp对象。


举例:
网站:http://www.sgs.gov.cn/lz/etpsInfo.do?method=index
操作:点选“企业名称”,在空白框内输入“通用技术集团医药控股有限公司”后点击“搜索”,在随后跳出的页面里点击“详细信息”,需要获取该公司的详细信息数据。

根据本楼之前的方法编写的代码:
  1. Sub Main()
  2.     Dim strText As String
  3.     With CreateObject("MSXML2.XMLHTTP") 'CreateObject("WinHttp.WinHttpRequest.5.1")
  4.         .Open "POST", "http://www.sgs.gov.cn/lz/etpsInfo.do?method=viewDetail", False
  5.         .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
  6. '        .setRequestHeader "Referer", ""
  7.         .send "etpsId=150000012002040300047"
  8.         strText = .responseText
  9.         Debug.Print strText
  10.     End With
  11. End Sub
复制代码
运行后,立即窗口显示:
Referer1.png

模拟Referer后的代码:
Sub Main()
    Dim strText As String
    With CreateObject("WinHttp.WinHttpRequest.5.1") 'CreateObject("MSXML2.XMLHTTP") '
        .Open "POST", "http://www.sgs.gov.cn/lz/etpsInfo.do?method=viewDetail", False
        .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
        .setRequestHeader "Referer", "http://www.sgs.gov.cn/lz/etpsInfo.do?method=doSearch"
        .send "etpsId=150000012002040300047"
        strText = .responseText
        Debug.Print strText
    End With
End Sub
再次运行,立即窗口即出现相关企业的详细信息。
Referer2.png


小贴士:除了Content-Type、Referer和Cookie,其他setRequestHeader的情况很少见。

点评

谢谢分享啊  发表于 2014-11-24 14:07

评分

4

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 21:55 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 acecrazy 于 2014-12-11 14:17 编辑

获取数据-防盗链的处理-模拟Cookie:

再次提醒,抓包前请先清除浏览器所有Cookie、缓存、历史数据。

举例:
网站:http://www.gzgczj.com:8080/costRegulatory/user.do?method=changeIndex&fareaId=1
操作:点击“控制价备案”,获取工程名称和招标控制价信息数据。

此网页模拟Referer后仍然无法获取数据。于是考虑模拟Cookie。
复制数据页面的cookie值,填入代码中(先不要去掉Referer的模拟):
Cookie1.png
  1. Sub Main()
  2.     Dim strText As String
  3.     With CreateObject("WinHttp.WinHttpRequest.5.1")
  4.         .Open "GET", "http://www.gzgczj.com:8080/costRegulatory/project.do?method=showProjectList&isVisitor=1&f_id=11011&t1413902083242", False
  5.         .setRequestHeader "Referer", "http://www.gzgczj.com:8080/costRegulatory/user.do?method=changeIndex&fareaId=1"
  6.         .setRequestHeader "Cookie", "E0685A9F6B708A1F1039BF2322B82A35"
  7.         .Send
  8.         strText = .responsetext
  9.         Debug.Print strText
  10.     End With
  11. End Sub
复制代码
运行,,立即窗口显示“请重新登录”!
Cookie2.png

这是为什么呢?这是因为Cookie失效了!我们需要模拟“新鲜”的Cookie才行!

模拟“新鲜”Cookie的方法:
1、复制上面Cookie值字符串。
2、搜索Session框内第一次出现此Cookie值的网页:
Cookie3.png

Cookie4.png

3、编写代码,获取该Cookie,然后模拟写入数据网页:
  1. Sub Main()
  2.     Dim strText As String
  3.     Dim strCookie As String
  4.    
  5.     With CreateObject("WinHttp.WinHttpRequest.5.1")
  6.         .Option(6) = False ' 禁止重定向,以获取原网页信息
  7.         .Open "GET", "http://www.gzgczj.com:8080/costRegulatory/user.do?method=changeIndex&fareaId=1", False
  8.         .Send
  9.         strText = .getAllResponseHeaders '获取所有的回应头信息
  10.         Debug.Print strText: Stop '在立即窗口里查看头信息
  11.         strCookie = Split(Split(strText, "Set-Cookie: ")(1), ";")(0) '取出Cookie值
  12.     End With
  13.    
  14.     '在同一个winhttp对象里能保留cookie,为了体现设置cookie的作用,启用一个新的winhttp对象
  15.     With CreateObject("WinHttp.WinHttpRequest.5.1")
  16.         .Open "GET", "http://www.gzgczj.com:8080/costRegulatory/project.do?method=showProjectList&isVisitor=1&f_id=11011&t1413902083242", False
  17.         .setRequestHeader "Referer", "http://www.gzgczj.com:8080/costRegulatory/user.do?method=changeIndex&fareaId=1"
  18.         .setRequestHeader "Cookie", strCookie '模拟Cookie
  19.         .Send
  20.         strText = .responsetext
  21.         Debug.Print strText
  22.     End With
  23. End Sub
复制代码
运行。。查看立即窗口,数据获取成功。
注意:本cookie是存在于重定向之前的网页的,要取到该cookie,必须禁用重定向。关于重定向,请参考108楼的帖子
不要用getResponseHeader("Set-Cookie")获取回应头信息中的Cookie值。如果有多个Cookie值,用getResponseHeader("Set-Cookie")获取不到完整的Cookie值。

你如果认为模拟Cookie只能写setRequestHeader的话,你就大错特错了。

xmlhttp对象和winhttp对象均可以保留Cookie。
也就是说,要获取某个网页的Cookie,可以先发送对此网页的请求(GET或POST)。只要xmlhttp对象或winhttp对象不关闭,此Cookie在对象运行期间全程有效。


据此,上述代码可以简化为:
  1. Sub Main()
  2.     Dim strText As String
  3.     With CreateObject("WinHttp.WinHttpRequest.5.1")
  4.         .Open "GET", "http://www.gzgczj.com:8080/costRegulatory/user.do?method=changeIndex&fareaId=1", False
  5.         .Send '此次send是为了获取cookie
  6.         .Open "GET", "http://www.gzgczj.com:8080/costRegulatory/project.do?method=showProjectList&isVisitor=1&f_id=11011&t1413902083242", False
  7.         .setRequestHeader "Referer", "http://www.gzgczj.com:8080/costRegulatory/user.do?method=changeIndex&fareaId=1"
  8.         .Send
  9.         strText = .responsetext
  10.         Debug.Print strText
  11.     End With
  12. End Sub
复制代码
运行。。查看立即窗口,数据同样获取成功。

小贴士:用setRequestHeader方法模拟Cookie时,要用winhttp对象。发送网页的请求获取Cookie则xmlhttp、winhttp都可以。

点评

你可以找个修改Cookie并提交,以欺骗服务器的例子,这样会更好的理解Cookie欺骗的意义及作用  发表于 2014-10-24 09:53
winhttp所有cookie在释放后就会销毁,也不存在和人家共享。  发表于 2014-10-21 22:07
cookie有两种,一种会话cookie,一种持久cookie,会话cookie是在内存的,关闭或通讯结束可立即过期。持续cookie是可保留在硬盘的。xmlhttp可共享到ie的持久cookie,或者excel本进程的webbrowser的所有cookie。  发表于 2014-10-21 22:06
呵呵,xmlhttp的cookie很有趣,例如excel建一个webbrowser,登陆后的cookie,在xmlhttp里面可以直接发送。常用于变态登陆页面手工操作,然后批量刷数据。  发表于 2014-10-21 22:02

评分

2

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-21 22:16 | 显示全部楼层
dg831451 发表于 2014-10-21 21:58
不知道吴姐,有没有研究过https加密网站同时还要发送证书的

https做过,但没遇到过有证书问题的网页。

winhttp有个选项可以忽略证书错误(Option(4) = 13056),但这可能不是你要的。

点评

这个就像浏览器证书错误,点继续浏览,不是发证书去校验。  发表于 2014-10-21 22:18

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-22 06:58 | 显示全部楼层
本帖最后由 wcymiss 于 2014-10-22 07:07 编辑

继续唠叨Cookie。。。

33楼的例子里,Cookie值的最初来源,来自服务器返回的回应头信息的“Set-Cookie”,它对winhttp对象的Cookie进行了设置。这种Cookie来源,不需要写setRequestHeader来模拟Cookie,只需发送一下相关页面的请求即能获取该Cookie。

但有些网页的Cookie值,来源并非是回应头信息的“Set-Cookie”。它可能是responsetext中的一部分。这时就只能setRequestHeader了。

(刚刚想找一个我以前写过的Cookie存在于responsetext的例子,发现网站竟然改版了,也“Set-Cookie”了!!)
征求Cookie存在于responsetext的例子。。。。

点评

可以重定向再唠嗑。重定向很多cookie因为跨域问题,都要手工发。回头我也找看看。  发表于 2014-10-22 10:54

评分

3

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-22 11:10 | 显示全部楼层
本帖最后由 wcymiss 于 2014-10-22 12:32 编辑

还是Cookie。。。

模拟Cookie的宗旨是向服务器发送一个它认可的Cookie。不管这个Cookie是回话Cookie还是持久Cookie,甚至该Cookie根本不存在你的电脑中(无论内存还是硬盘),只要服务器认可就行。

举例:
网站:http://club.excelhome.net/
操作:登录EH,在论坛首页点击“我发布的主题”,获取自己的主题帖数据。

EH的登录添加了验证码,这对我们初学网抓的人来说用xmlhttp/winhttp模拟登录EH是个无法克服的难题。

但是我们可以模拟Cookie来实现查询效果呀!

步骤:
1、抓包确认数据页面所在session。
2、点击该session的Request框的Cookie按钮可查看发送头内的Cookie内容。(挤在一起还是看不清楚)
EH1.png

3、点击Request框的Header按钮查看Cookie更清晰:
EH2.png

抓到的Cookie有很多,但不是每一个都需要模拟的。

经验:10位数字值一般都是用来记录时间的,这样的Cookie值一般不大会作为服务器的辨识标志,所以我们也一般不用模拟它。 (注意我用了“一般”这个词)

去除值为数字或空白的Cookie,只取值为字母数字混合物的Cookie写入代码中:
  1. Sub Main()
  2.     Dim strText As String
  3.     Const saltkey As String = "oUuXXXX"'请复制你自己的Cookie粘贴到这里。下同
  4.     Const sid As String = "tXXXX"
  5.     Const auth As String = "a30eEZTXXXXXXXXXXXXXXXXXXXX"
  6.     Const cookiereport As String = "f1fXXXXXXXXXXXXXXXXXXXXXXXX"
  7.     Const ulastactivity As String = "84cXXXXXXXXXXXXXXXXXXXX"
  8.     Const touclick As String = "70a9vPXXXXXXXXXXXXXXXXXXXX"
  9.     Const member_login_uid As String = "218917"
  10.     Const member_login_sid As String = "tXXXX"
  11.    
  12.     With CreateObject("WinHttp.WinHttpRequest.5.1")
  13.         .Open "GET", "http://club.excelhome.net/home.php?mod=space&do=thread&view=me ", False
  14.         .setRequestHeader "Cookie", _
  15.         "5WOj_b676_saltkey=" & saltkey _
  16.         & ";5WOj_b676_sid=" & sid _
  17.         & ";5WOj_b676_auth=" & auth _
  18.         & ";5WOj_b676_cookiereport=" & cookiereport _
  19.         & ";5WOj_b676_ulastactivity=" & ulastactivity _
  20.         & ";5WOj_b676_touclick=" & touclick _
  21.         & ";5WOj_b676_member_login_uid=" & member_login_uid _
  22.         & ";5WOj_b676_member_login_sid=" & member_login_sid
  23.         .Send
  24.         strText = .responsetext
  25.         Debug.Print strText
  26.     End With
  27. End Sub
复制代码
运行。。查看立即窗口,获取数据成功。

继续测试,去除一些对获取数据无影响的Cookie(连论坛ID都去除了,大跌眼镜),代码最后成型为:
  1. Sub Main()
  2.     Dim strText As String
  3.     Const saltkey As String = "oUuXXXX"
  4.     Const auth As String = "a30eEZTXXXXXXXXXXXXXXXXXXXX"
  5.    
  6.     With CreateObject("WinHttp.WinHttpRequest.5.1")
  7.         .Open "GET", "http://club.excelhome.net/home.php?mod=space&do=thread&view=me ", False
  8.         .setRequestHeader "Cookie", _
  9.         "5WOj_b676_saltkey=" & saltkey _
  10.         & ";5WOj_b676_auth=" & auth
  11.         .Send
  12.         strText = .responsetext
  13.         Debug.Print strText
  14.     End With
  15. End Sub
复制代码
这两个Cookie值就是EH的关键登录Cookie。它不需要保存在你的电脑里(本地电脑清除cookie、缓存后代码依旧运行成功)。我不知道它在服务器上的生存期有多长,我用了三天依然有效,哪怕在这三天内已经无数次的在不同地点手工重新登录过EH。有兴趣的话可以自己测试下它的生存期。

评分

7

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-3-28 20:31 , Processed in 0.372102 second(s), 8 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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