如何爬取asp.net动态网页?搞定可恶的动态参数,这一文告诉你!

这个asp网站是我的学校的电费查询系统,需要学校的内网才能查询,所以这文说下思路和我遇到的一些坑。我搞这个网站主要是为了方便查电费而已,其实也方便不了多少。而且这个asp网站还不是很容易爬,因为里面有两个可变的参数,会根据页面来变化。好了,先看看页面

这个网站需要先登陆进自己的宿舍才能进去,还有很烂的验证码,不过我实现到验证码写入的时候发现这个验证码是可以随便填的,这个就感觉有点垃圾。

这个登陆页面有很多坑,下面说下

1.

上面右边所指的就是两个动态变化的参数,怎么来的呢?是根据上一个页面来的,每个页面都会带有这两个参数,所以我们需要每次访问一次都需要匹配下这两个值就行动态更换,如果不跟换的话,会得不到数据,还会出现下面这个错误。

'236|error|500|回发或回调参数无效。在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page EnableEventValidation="true" %> 启用了事件验证。出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件。如果数据有效并且是预期的,则使用 ClientScriptManager.RegisterForEventValidation 方法来注册回发或回调数据以进行验证。|'

这个就说明你没有更换好上面所说的两个参数

注意:第一次访问这个网站是不会有宿舍楼层宿舍号这些数据的,需要进行匹配上面的两个可变参数再进行post才会有数据。

2.

在你选好你的宿舍楼层号之后表单数据就会出现变化

可以看到表单的参数顺序和上面的不一样了,所以在选好宿舍楼层之后我们需要把变单顺序改变后再把参数post出去,要不还会出现上面那个坑,就是回调参数无效

第一个箭头所指的参数也需要改变,不过第二个参数是txtname2,也就是每层楼的默认宿舍值,这个固定也没事,不会出错,时间的话还是需要根据自己访问时间来进行变化的,要不也会出现错误,还是同样的错误,也就是下面的这个错误,可想而知asp网站对这些参数是有很挑剔的要求。

236|error|500|回发或回调参数无效。在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page EnableEventValidation="true" %> 启用了事件验证。出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件。如果数据有效并且是预期的,则使用 ClientScriptManager.RegisterForEventValidation 方法来注册回发或回调数据以进行验证。|

3.

这个电费查询按钮,不是ajax,会有新的请求,而且是对同一个网址的不同请求方式,第一次请求时get请求,用于获取asp网页的那两个动态参数,第二次是将动态参数就行post发送出去,这样就会有数据了,如果你是第一次就post的话,会没有数据,网页还是会报错误,同样还是那个错误哈。下面是表单数据

self.data = {
           '__EVENTTARGET''RegionPanel2$Region1$Toolbar1$ContentPanel1$btnSelect',
           '__EVENTARGUMENT''',
           '__VIEWSTATE'self.data['__VIEWSTATE'],
           '__EVENTVALIDATION'self.data['__EVENTVALIDATION'],
           'hidJZ''jz'+name,
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$TextBox1': (datetime.now()-timedelta(days=30)).strftime('%Y-%m-%d'),
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$TextBox2': datetime.now().strftime('%Y-%m-%d'),
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$txtDBBH''',
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$ddlCZFS''----全部----',
           'RegionPanel2$Region1$toolbarButtom$pagesize''1',
           '__box_page_state_changed''false',
           '__2_collapsed''false',
           '__6_selectedRows''',
           '__box_disabled_control_before_postbac''__10',
           '__box_ajax_mark''true'
       }


坑说完了,说说部分代码的作用吧

def __get_value(self, html):  # 获取表单的两个参数__VIEWSTATE和__EVENTVALIDATION
       try:
           soup = BeautifulSoup(html, 'lxml')
           value = soup.select('input[type="hidden"]')
           values = [v for v in value if '/w' in str(v)]
           state = values[0]['value']
           action = values[1]['value']
           self.data['__VIEWSTATE'] = state
           self.data['__EVENTVALIDATION'] = action
       except IndexError as e:  # 证明这个不是首页,需要另外的规则
           match = re.search('__VIEWSTATE\|(.*?)\|.*?__EVENTVALIDATION\|(.*?)\|', html)
           self.data['__VIEWSTATE'] = match.group(1)
           self.data['__EVENTVALIDATION'] = match.group(2)
       except Exception as e:
           print('get_value', e)

这个就是获取两个动态参数的方法,每次根据html元素来获取

def __get_name(self, jz, html=None):  # 输入宿舍号
       if html:
           # 表单顺序需要改变
           self.data = {
               'ScriptManager1''UpdatePanel1|txtjz2',
               'hidtime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
               'Radio1''1',
               'txtjz2': jz,
               'txtname2''001001001001001',  # 这个初始化值可以随意,但不能为空
               'txtpwd2''',
               'txtyzm2''',
               '__EVENTTARGET''txtjz2',
               '__EVENTARGUMENT''',
               '__LASTFOCUS''',
               '__VIEWSTATE''',
               '__EVENTVALIDATION''',
               '__ASYNCPOST''true'
           }
           self.__get_value(html)  # 换下参数
           html = self.__get_html()
           if html:
               soup = BeautifulSoup(html, 'lxml')
               dormitory_num = soup.select('select[name="txtname2"] option')
               dormitory_num = [(p.text, p['value']) for p in dormitory_num]
               for index, p in enumerate(dormitory_num):
                   print(index, '宿舍号:', p[0])
               self.__get_value(html)
       while True:
           num = input('请输入你的宿舍,输入左边的编号即可')
           num = re.match('\d+', num)
           if num and int(num.group()) < len(dormitory_num):
               num = int(num.group())
               break
           print('请输入正确的宿舍编号')
       return dormitory_num[num][1]

这个是获取宿舍号,表单顺序需要改变

def __get_chapter(self):
       # 获取验证码
       url = 'http://172.18.2.42:8000/ValidateCode.aspx'
       response = requests.get(url, headers=self.headers)
       with open('code.jpg''wb'as f:
           f.write(response.content)
       image = Image.open('code.jpg')
       image.show()
       code = input('请输入验证码')
       return code

这个是获取验证码的方法,获取验证码是很简单的,就是找到请求的url进行请求就可以了。至于识别,我这里是手动输入,你也可以选择接入打码平台或者用深度学习模型来识别。

其他的就不多说了。

需要源码的可以在我的GitHub上找:https://github.com/SergioJune/gongzhonghao_code/blob/master/python_play/query.py

写在最后

如果这篇文章对你用的话,希望不要吝啬你的点赞哈!点赞和转发就是对我的最大支持,这样才有动力输出质量高的原创文章。

「点赞是一种态度!」

推荐文章:

我爬取了37000条球迷评论,知道了这场比赛的重要信息爬取《The Hitchhiker’s Guide to Python!》python进阶书并制成pdf


日常学python

代码不止bug,还有美和乐趣

猜你喜欢

转载自juejin.im/post/5b11ff916fb9a01e7a44bf1b
今日推荐