最近在爬一个叫做"雅学资讯网"的网站的时候,在翻页的时候发现翻不动,做翻页请求时会报错。仔细查了以下发现跟ViewState和EVENTVALIDATION两个东西有关。(两个值的具体用法我写在最后,如果光为了解决爬虫问题可能不需要对这两个值有太深的理解,所以我先写下爬虫应该如何应对)
一、应对方法
在页面上我们可以找到这么一段div,其中value的值便是当前页面的ViewState
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTEyODcxMjQ1NjAPZBYCAgMPZBYEAgYPFgIeBFRleHQF9AM8dHI+PHRkIGhlaWdodD0iMTkiIGNsYXNzPSJ0ZXh0MSI+wrc8YSBocmVmPSJodG1sL3NjZGx1bi5odG1sIiB0YXJnZXQ9Il9ibGFuayI+U0NE5rqQ5pyf5YiK6K665paH6K6h566X5qCH5YeGPC9hPjwvdGQ+PHRkIGhlaWdodD0iMTkiIGNsYXNzPSJ0ZXh0MSI+wrc8YSBocmVmPSJodG1sL3NjZGNobi5odG1sIiB0YXJnZXQ9Il9ibGFuayI+U0NE5Lit5paH5rqQ5pyf5YiK562b6YCJ6L+H56iLPC9hPjwvdGQ+PC90cj48dHI+PHRkIGhlaWdodD0iMTkiIGNsYXNzPSJ0ZXh0MSI+wrc8YSBocmVmPSJodG1sL3NjaXNjZGx1bi5odG1sIiB0YXJnZXQ9Il9ibGFuayI+MjAwNH4yMDA55bm0U0NJ44CBU0NE5a2m56eR6Zeo6K665paH5pWwDQo8L2E+PC90ZD48dGQgaGVpZ2h0PSIxOSIgY2xhc3M9InRleHQxIj7CtzxhIGhyZWY9Imh0bWxcc2Npc2NkLmh0bWwiIHRhcmdldD0iX2JsYW5rIj4yMDA0fjIwMDnlubRTQ0njgIFTQ0TkuIDnuqflrabnp5HorrrmlofmlbA8L2E+PC90ZD48L3RyPmQCCg9kFgICAQ8WAh8ABQ8xMjIuMjM1LjIyNy4yMTBkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYCBQhidG5Mb2dpbgUIYnRuUmVzZXRtFvhkMyHYuQBS5+NctLObmaPtUA==" />
</div>
下面这一段是EVENTVALIDATION的
<div>
<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="90059987" />
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWBQLii7WQCAKl1bKzCQK1qbSRCwKC3IeGDAKgt7D9Cq786rV3YQHSWN8A2IZl0Z5gnwxM" />
</div>
简单来说我们把这个页面的html解析获取这两个值,然后在执行post请求时加到PostData属性里就可以了。
但是
在翻页的时候可能还会有一个坑,我们有时会需要子页面中的内容。这个时候子页面爬取的顺序就有点讲究了。
正确顺序在第三部分,不需要看我踩坑过程的直接看第三部分。
1、流水账顺序(坑)
如果我们按照下图这样的顺序,会发现我们在第一页子页c跳转到第二页的时候会失败。
-
1、 使用子页C的ViewState和EVENTVALIDATION进行请求
翻页这个指令要从第一页发出,所以需要第一页的属性进行请求。 -
2、在子页面直接使用第一页的ViewState和EVENTVALIDATION的进行请求
属性和页面一定要对应,也就是“子页C用第一页的属性”这种操作是不可行的。
2、改良流水账顺序(坑)
我们由上面知道了一定要第一页才能跳转第二页,那我们每次访问完子页面都返回一下可不可以呢?
答案是不可以
其实我们的第一页是搜索请求的来的,或者GET访问得来的,那第一页子页C跳转第一页还是可以实现的。但是到了第二页子页C跳转第二页的时候,我们就又跳不动了,我们需要第一页才能跳第二页。
-
当然你们一定不会想用这样的顺序吧哈哈(不过可能某些特殊情况真的需要这种..)。
3、先所有父页再所有子页(成功)
按照本身应该的一页跳二页,二页跳三页的顺序爬取(先不管子页面),再爬每一页时存储好该页的Html或者跳转子页面的信息,先把所有父页面爬好,再根据本地的信息爬所有子页面。
二、ViewState和EVENTVALIDATION的原理
1、ViewState
当请求某个页面时,ASP.NET把所有控件的状态序列化成一个字符串,然后做为窗体的隐藏属性送到客户端。当客户端把页面回传时,ASP.NET分析回传的窗体属性,并赋给控件对应的值。
2、EVENTVALIDATION
“id”属性为“__EVENTVALIDATION”的隐藏字段是ASP.NET 2.0的新增的安全措施。该功能可以阻止由潜在的恶意用户从浏览器端发送的未经授权的请求.
为了确保每个回发和回调事件来自于所期望的用户界面元素,ASP.NET运行库将在事件中添加额外的验证层。服务器端通过检验表单提交请求的内容,将其与“id”属性为“__EVENTVALIDATION”隐藏字段中的信息进行匹配。根据匹配结果来验证未在浏览器端添加额外的输入字段(有可能为用户在浏览器端恶意添加的字段),并且该值是在服务器已知的列表中选择的。ASP.NET运行库将在生成期间创建事件验证字段,而这是最不可能获取该信息的时刻。像视图状态一样,事件验证字段包含散列值以防止发生浏览器端篡改。