为asp doPostBack()函数

时间:2018-01-31 14:12:35

标签: python asp.net web-scraping scrapy

tldr; 我试图覆盖服务器所需的隐藏字段,以便返回一个新的geocach页面失败( __ EVENTTARGET 属性),所以服务器返回一个空页面

Ps:我原来的帖子被关闭投票放弃了,所以我在第一篇文章中产生的大量编辑后重新发布。

我尝试使用Scrapy 1.5.0在一个着名的地理藏宝网站上废弃一些包含缓存的网页。

因为如果你想运行这个code,你需要一个帐户,我在网站上创建一个新的临时免费帐户进行一些测试:dumbuser密码为stackoverflow

A)流程的实际工作部分:

  • 首先,我通过登录页面进入网站(需要搜索页面):https://www.geocaching.com/account/login
  • 成功登录后,我在某些地理位置搜索项目(geocaches)(例如France, Haute-Normandie)。

这第一次搜索没有问题,我没有困难解析第一个geocaches。

B)流程中的问题部分:请求下一页

当我尝试模拟点击以转到geocaches的下一页时。例如,转到第1页到第2页。

enter image description here

网站使用ASP with synchronised state between client and server,因此我们需要在剪贴板期间转到page1然后转到page2然后转到page3等等,以便维护服务器之间生成的__VIEWSTATE变量(隐藏输入) FORM查询。

每个号码的链接(参见图片)都会调用javascript函数javascript:__doPostBack(...)的链接,在提交整个表单之前将其注入已存在的隐藏字段。

正如您在__doPostBack函数中看到的那样:

<script type="text/javascript">
//<![CDATA[
var theForm = document.forms['aspnetForm'];
if (!theForm) {
    theForm = document.aspnetForm;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
//]]>
</script>

例如: 因此,当您点击第2页链接时,javascript运行为javascript:__doPostBack('ctl00$ContentBody$pgrTop$lbGoToPage_2','')。表单随

一起提交
  • __EVENTTARGET = ctl00$ContentBody$pgrTop$lbGoToPage_2
  • __EVENTARGUMENT = ''

C)首先尝试模仿此行为:

为了废弃多个页面(此处限制为五个首页),我在此处尝试yield五个formRequest.from_response查询,只需手动覆盖此__EVENTTARGET __EVENTARGUMENT属性:

def parse_pages(self,response):

    self.parse_cachesList(response)

    ## EXTRACT NUMBER OF PAGES
    links = response.xpath('//td[@class="PageBuilderWidget"]/span/b[3]')
    print(links.extract_first())

    ## Try to extract page 1 to 5 for exemple
    for page in range(1,5):
        yield scrapy.FormRequest.from_response(
            response,
            formxpath="//form[@id='aspnetForm']",
            formdata=
{'__EVENTTARGET':'ctl00$ContentBody$pgrTop$lbGoToPage_'+str(page),
'__EVENTARGUMENT': '',
                      '__LASTFOCUS': ''},
            dont_click=True,
            callback=self.parse_cachesList,
            dont_filter=True
        )

D)结果:

服务器返回的页面是空的,所以我的策略有问题。

当我查看表单发布后服务器返回的生成的html代码时,__EVENTTARGET 永远不会被scrapy覆盖

<input id="__EVENTTARGET" name="__EVENTTARGET" type="hidden" value=""/>
<input id="__EVENTARGUMENT" name="__EVENTARGUMENT" type="hidden" value=""/>

E)问题:

你能帮助我理解为什么scrapy不会替换/覆盖__EVENTTARGET值吗?我的策略中模拟点击跟踪每个新页面的用户的问题在哪里?

此处可下载完整代码code

更新1:

使用fiddler,我终于发现问题与输入有关:ctl00$ContentBody$chkAll=Check All此输入由scrapy.FormRequest.from_response方法自动复制。如果我从POST请求中删除此属性,它可以工作。那么,我怎么能删除这个字段,我尝试空无结果:

result = scrapy.FormRequest.from_response(
            response,
            formname="aspnetForm",
            formxpath="//form[@id='aspnetForm']",
            formdata={'ctl00$ContentBody$chkAll':'',
                      '__EVENTTARGET':'ctl00$ContentBody$pgrTop$lbGoToPage_2',},
            dont_click=True,
            callback=self.parse_cachesList,
            dont_filter=True,
            meta={'proxy': 'http://localhost:8888'}
            )

1 个答案:

答案 0 :(得分:3)

解决使用大量耐心,fiddler工具调试并将POST查询重新发送到服务器!

更新1 一样,在我原来的问题中说,问题来自表单中的输入ctl00$ContentBody$chkAll

FormRequest发送的POST表单中的输入删除的方法很简单,我在commit here中找到了它。在None词典中将属性设置为formdata

    result = scrapy.FormRequest.from_response(
        response,
        formname="aspnetForm",
        formxpath="//form[@id='aspnetForm']",
        formdata={'ctl00$ContentBody$chkAll':None,
        '__EVENTTARGET':'ctl00$ContentBody$pgrTop$lbGoToPage_2',},
        dont_click=True,
        callback=self.parse_cachesList,
        dont_filter=True
        )