ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] 网页采集(网页抓取)教程第二课-用WinHTTP提交Post,viewstate获取和URLEncode编码方法

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-9-16 19:49 | 显示全部楼层
本帖已被收录到知识树中,索引项:网页交互
代码也贴一下,省去大师们下载附件的麻烦:
Option Explicit

Private Sub CommandButton1_Click()

    Dim n As Long
    Dim yema As Integer
    Dim oDoc As Object
    Dim tt
    Dim s1 As String
    Dim s2 As String
    Dim s3 As String
    Dim s4 As String
    Dim a As String
    Dim i As Long
    Dim j As Long
    Dim p As Integer
    Dim 省份 As String
    Dim 年份 As String
    Dim 科类 As String
    Dim r As Object
        
  
    On Error Resume Next
    n = Range("c65536").End(xlUp).row
    If n > 1 Then
        Range(Cells(2, 1), Cells(n, "H")).Clear
    End If
    Range("A2:H2") = Split("专业名称,省份地区,年份,科类,学制,培养方式,计划人数,报考要求", ",")      '以全角的逗号为分隔符
   
    Set oDoc = CreateObject("htmlfile")

'首先以get方式提交,从返回页面中获取下次POST方式提交的数据取值
    With CreateObject("MSXML2.ServerXMLHTTP")
        .Open "GET", "http://zsw.bjtu.edu.cn/JHFS/Default.aspx", False
        .send
        tt = .responsetext
'返回数据放入剪切板供调试使用,其中{}内的数值为剪切板的CLSID,可以通过windows注册表获得。
        With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
            .SetText tt
            .PutInClipboard
        End With
      
        a = "__EVENTTARGET=ctl04%24sysq&__EVENTARGUMENT=&__LASTFOCUS=&"
        s1 = "__VIEWSTATE=" & EncodePostdata(Split(Split(tt, "__VIEWSTATE"" value=""")(1), """")(0))
        a = a & s1 & "&"
        s2 = "__VIEWSTATEGENERATOR=" & EncodePostdata(Split(Split(tt, "VIEWSTATEGENERATOR"" value=""")(1), """")(0))
        a = a & s2 & "&"
        s3 = "__PREVIOUSPAGE=" & EncodePostdata(Split(Split(tt, "PREVIOUSPAGE"" value=""")(1), """")(0))
        a = a & s3 & "&"
        s4 = "__EVENTVALIDATION=" & EncodePostdata(Split(Split(tt, "__EVENTVALIDATION"" value=""")(1), """")(0))
        a = a & s4 & "&"
        省份 = Range("C1").Value
        年份 = Range("E1").Value
        科类 = Range("G1").Value
        a = a & "ctl04%24sysq=" & EncodePostdata(省份) & "&"
        a = a & "ctl04%24nf=" & EncodePostdata(年份) & "&"
        a = a & "ctl04%24xkml=" & EncodePostdata(科类) & "&"
        a = a & "ctl04%24zymc=%B2%BB%CF%DE&ctl04%24pyfs=%B2%BB%CF%DE"
'构造的上述数据,在fiddler中发送后,可正常返回,但在本程序中不行,why?
'填入拟查询的条件,POST提交查询,返回的数据是首页数据(后来发现是把ctl04误写为了ct104导致的,字母l和数字1吆)
'为了测试,把抓包的数据先ctrl+V复制到剪贴板,然后放到这儿来发,看看到底如何?结果仍然是错误的请求。
'
'    Dim mydataobj As New DataObject
'    mydataobj.GetFromClipboard
'    a = mydataobj.GetText
'    Set mydataobj = Nothing
'    Debug.Print a
   
        .Open "POST", "http://zsw.bjtu.edu.cn/JHFS/Default.aspx", False
        .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
        .SetRequestHeader "Connection", "Keep-Alive"
        .send a
            
        With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
            .SetText a
            .PutInClipboard
        End With
        
        tt = ""
        tt = .responsetext
        With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
            .SetText tt
            .PutInClipboard
        End With
'解读返回数据,获取总页数
        yema = CInt(Left(Split(tt, " style=""color:Black;"">")(UBound(Split(tt, " style=""color:Black;"">"))), 1))
'按照分页查询的方式组织POST数据,逐页获取网站数据
        For p = 1 To yema
            a = "__EVENTTARGET=ctl04%24zsjh&" & "__EVENTARGUMENT=Page%24" & p & "&"
            s1 = "__VIEWSTATE=" & EncodePostdata(Split(Split(tt, "__VIEWSTATE"" value=""")(1), """")(0))
            a = a & s1 & "&"
            s2 = "__PREVIOUSPAGE="
            s2 = s2 & EncodePostdata(Split(Split(tt, "PREVIOUSPAGE"" value=""")(1), """")(0))
            a = a & s2 & "&"
            s3 = "__EVENTVALIDATION=" & EncodePostdata(Split(Split(tt, "__EVENTVALIDATION"" value=""")(1), """")(0))
            a = a & s3
            省份 = Range("C1").Value
            年份 = Range("E1").Value
            科类 = Range("G1").Value
            a = a & "&ctl04%24sysq=" & EncodePostdata(省份)
            a = a & "&ctl04%24nf=" & EncodePostdata(年份)
            a = a & "&ctl04%24xkml=" & EncodePostdata(科类)
            a = a & "&ctl04%24zymc=%B2%BB%CF%DE&ctl04%24pyfs=%B2%BB%CF%DE"
            n = Range("c65536").End(xlUp).row
            .Open "POST", "http://zsw.bjtu.edu.cn/JHFS/Default.aspx", False
            .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
            .SetRequestHeader "Connection", "keep-alive"
            .send a
            
        With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
            .SetText a
            .PutInClipboard
        End With
        
            tt = ""
            tt = .responsetext
        With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
            .SetText tt
            .PutInClipboard
        End With

            oDoc.body.innerHTML = .responsetext
            Set r = oDoc.getElementById("ctl04_zsjh").Rows
            For i = 1 To r.Length - 1
                For j = 0 To r(i).Cells.Length - 1
                    Cells(i + n, j + 1) = r(i).Cells(j).innerText
                Next j
            Next i
        Next p
    End With
End Sub

Private Function EncodePostdata(szInput)
    Dim i As Long
    Dim x() As Byte
    Dim szRet As String
    szRet = ""
    x = StrConv(szInput, vbFromUnicode)
    For i = LBound(x) To UBound(x)
        If x(i) >= 48 And x(i) <= 57 Or x(i) >= 65 And x(i) <= 90 Or x(i) >= 97 And x(i) <= 122 Then
            szRet = szRet & Chr(x(i))
        Else
            szRet = szRet & "%" & Hex(x(i))
        End If
    Next
    EncodePostdata = szRet
End Function

TA的精华主题

TA的得分主题

发表于 2014-9-16 22:17 | 显示全部楼层
回91楼
  1. Function URLEncodePlus(strURL)
  2. 'ANSI编码,空格处理成+号
  3.     Dim i
  4.     Dim tempStr
  5.     For i = 1 To Len(strURL)
  6.         If Asc(Mid(strURL, i, 1)) < 0 Then
  7.             tempStr = "%" & Right(CStr(Hex(Asc(Mid(strURL, i, 1)))), 2)
  8.             tempStr = "%" & Left(CStr(Hex(Asc(Mid(strURL, i, 1)))), Len(CStr(Hex(Asc(Mid(strURL, i, 1))))) - 2) & tempStr
  9.             URLEncodePlus = URLEncodePlus & tempStr
  10.         ElseIf (Asc(Mid(strURL, i, 1)) >= 65 And Asc(Mid(strURL, i, 1)) <= 90) Or _
  11.                  (Asc(Mid(strURL, i, 1)) >= 97 And Asc(Mid(strURL, i, 1)) <= 122) Or _
  12.                  (Asc(Mid(strURL, i, 1)) >= 48 And Asc(Mid(strURL, i, 1)) <= 57) Then
  13.             URLEncodePlus = URLEncodePlus & Mid(strURL, i, 1)
  14.         Else
  15.             tempStr = Mid(strURL, i, 1)
  16.             Select Case tempStr
  17.             Case ".", "-", "~", "_"                                               '如果发现网站有其他不需要编码的字符,放在这里
  18.                 URLEncodePlus = URLEncodePlus & tempStr
  19.             Case " "
  20.                 URLEncodePlus = URLEncodePlus & "+"
  21.             Case Else
  22.                 URLEncodePlus = URLEncodePlus & "%" & Hex(Asc(tempStr))
  23.             End Select
  24.         End If
  25.     Next
  26. End Function



  27. Sub 按钮1_单击()
  28.     Dim url, html
  29.     url = "http://zsw.bjtu.edu.cn/JHFS/Default.aspx"
  30.     Set html = CreateObject("htmlfile")
  31.     n = 1
  32.     With CreateObject("msxml2.xmlhttp")
  33.         .Open "get", url, False
  34.         .send
  35.         html.body.innerhtml = .responsetext
  36.         Set tb = html.all.tags("tr")
  37.         For i = 0 To tb.Length - 1
  38.             If tb(i).classname = "common_title" Then
  39.                 n = n + 1
  40.                 For j = 0 To tb(i).Cells.Length - 1
  41.                     Cells(n, j + 1) = tb(i).Cells(j).innertext
  42.                 Next
  43.             End If
  44.         Next




  45.         For p = 2 To 3 '只做了3页
  46.             VIEWSTATE = URLEncodePlus(html.getElementById("__VIEWSTATE").Value)
  47.             VIEWSTATEGENERATOR = URLEncodePlus(html.getElementById("__VIEWSTATEGENERATOR").Value)
  48.             PREVIOUSPAGE = URLEncodePlus(html.getElementById("__PREVIOUSPAGE").Value)
  49.             EVENTVALIDATION = URLEncodePlus(html.getElementById("__EVENTVALIDATION").Value)
  50.             pd = "__EVENTTARGET=ctl04%24zsjh"
  51.             pd = pd & "&__EVENTARGUMENT=Page%24" & p
  52.             pd = pd & "&__LASTFOCUS="
  53.             pd = pd & "&__VIEWSTATE=" & VIEWSTATE
  54.             pd = pd & "&__VIEWSTATEGENERATOR=" & VIEWSTATEGENERATOR
  55.             pd = pd & "&__PREVIOUSPAGE=" & PREVIOUSPAGE
  56.             pd = pd & "&__EVENTVALIDATION=" & EVENTVALIDATION
  57.             pd = pd & "&ctl04%24sysq=%B2%BB%CF%DE"
  58.             pd = pd & "&ctl04%24nf=%B2%BB%CF%DE"
  59.             pd = pd & "&ctl04%24xkml=%B2%BB%CF%DE"
  60.             pd = pd & "&ctl04%24zymc=%B2%BB%CF%DE"
  61.             pd = pd & "&ctl04%24pyfs=%B2%BB%CF%DE"
  62.             .Open "POST", url, False
  63.             .setRequestheader "Host", "zsw.bjtu.edu.cn"
  64.             .setRequestheader "User-Agent", "Mozilla/5.0 (Windows NT 5.1; rv:32.0) Gecko/20100101 Firefox/32.0"
  65.             .setRequestheader "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
  66.             .setRequestheader "Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3"
  67.             .setRequestheader "Accept-Encoding", "gzip, deflate"
  68.             .setRequestheader "Referer", "http://zsw.bjtu.edu.cn/JHFS/Default.aspx"
  69.             .setRequestheader "Connection", "keep-alive"
  70.             .setRequestheader "Content-Type", "application/x-www-form-urlencoded"
  71.             .send (pd)

  72.             html.body.innerhtml = .responsetext
  73.             Set tb = html.all.tags("tr")
  74.             For i = 0 To tb.Length - 1
  75.                 If tb(i).classname = "common_title" Then
  76.                     n = n + 1
  77.                     For j = 0 To tb(i).Cells.Length - 1
  78.                         Cells(n, j + 1) = tb(i).Cells(j).innertext

  79.                     Next
  80.                 End If
  81.             Next
  82.         Next
  83.     End With
  84. End Sub



  85. Sub 按钮2_单击()
  86. Range("a2:h65536").ClearContents

  87. End Sub
复制代码

北京交通大学.zip

13.37 KB, 下载次数: 69

TA的精华主题

TA的得分主题

发表于 2014-9-17 12:06 | 显示全部楼层
谢谢suwenkai大师的帮助。不过我将MSXML2.ServerXMLHTTP替换为MSXML2.XMLHTTP,其他的地方不用改,也能接收到正常的数据了,所以还是迷惑提取网页的几个对象到底有啥区别?

TA的精华主题

TA的得分主题

发表于 2014-9-17 12:11 | 显示全部楼层
作为一个新人,学习中有很多的知识都不清楚,会问一些比较初级的问题,请大师们不吝赐教。uwenkai大师您的代码中有很多对htmlfile对象的操作,这个能从哪儿得到帮助文件吗?

TA的精华主题

TA的得分主题

发表于 2014-10-25 10:16 | 显示全部楼层
折腾了很久,还是不知如何获取在其他页(首页除外)中做POST提交的VIEWSTATE等动态参数
总是重复导入第1页的信息。

点评

如果总是导入第1页,99%的可能是post提交的参数错误或缺失。你要把第一步查询动作和第二步翻页动作分开单独进行。  发表于 2014-10-25 18:32
如果总是导入第1页,99%的可能是post提交的参数错误或缺失。你要把第一步查询动作和第二步翻页动作分开单独进行。  发表于 2014-10-25 18:19

TA的精华主题

TA的得分主题

发表于 2014-10-26 18:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
suwenkai 发表于 2014-9-16 22:17
回91楼

参照您的代码,终于知道如何获取做POST提交的viewstate等动态参数了,非常感谢!
同时谢谢kangatang的点评。

TA的精华主题

TA的得分主题

发表于 2014-11-21 21:22 | 显示全部楼层
Cookie里面的参数很多,如何确定哪些是必要参数?必须传递啊啊?

点评

慢慢试  发表于 2014-11-21 21:26

TA的精华主题

TA的得分主题

发表于 2014-12-18 16:15 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
liucqa 发表于 2012-7-17 14:15
调用函数  Call getPostData(objWinhttp, URL) ,提取第一次POST需要的参数

2楼的代码中,EncodePostdata是转码函数吗?在哪里有?

TA的精华主题

TA的得分主题

发表于 2014-12-19 12:25 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
liucqa 发表于 2012-7-17 14:16
调用 getMultiPageData函数,通过Post获取首页数据和下一次做POST提交的VIEWSTATE等参数

再回首,似有所悟......
于是,Mark如附件:
网页采集(网页抓取)教程第二课.zip (1.57 MB, 下载次数: 182)

TA的精华主题

TA的得分主题

发表于 2014-12-26 13:22 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-18 17:21 , Processed in 0.037730 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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