Scrapy:FormRequest不自动填充ASP.net隐藏字段

7 投票
1 回答
2341 浏览
提问于 2025-04-18 06:04

我正在使用Scrapy来抓取一些需要登录才能访问的内容。这个网站是用ASP.net做的,ASP里面有一些看不见的字段到处都是(比如__VIEWSTATE__EVENTTARGET)。

当我调用FormRequest.from_response(response,...的时候,我本以为它会自动从响应中读取这些看不见的字段,并把它们填到formdata这个字典里——这也是Scrapy的FormRequest文档上说的应该做到的事情。

但是如果真是这样,那为什么登录过程只有在我明确列出这些字段并填充它们的时候才有效呢?

class ItsyBitsy(Spider):
    name = "itsybitsy"
    allowed_domains = ["website.com"]
    start_urls = ["http://website.com/cpanel/Default.aspx"]

    def parse(self, response):
        # Performs authentication to get past the login form
        sel = Selector(response)
        return [FormRequest.from_response(response,
        formdata={
        'tb_Username':'admin',
        'tb_Password':'password',

        # The following fields should be auto populated, right?
        # So why does removing 'em break the login (w/500 Server Error)
        '__VIEWSTATE':
              sel.xpath("//input[@name='__VIEWSTATE']/@value").extract(),
        '__EVENTVALIDATION':
              sel.xpath("//input[@name='__EVENTVALIDATION']/@value").extract(),
        '__EVENTTARGET': 'b_Login'

        },
        callback=self.after_login,
        clickdata={'id':'b_Login'},
        dont_click=True)]

    def after_login(self, response):
        # Mmm, scrumptious
        pass

编辑:添加表单HTML

<form id="form1" action="Default.aspx" method="post" name="form1">
<div>
<input type="hidden" value="" id="__EVENTTARGET" name="__EVENTTARGET">
<input type="hidden" value="" id="__EVENTARGUMENT" name="__EVENTARGUMENT">
<input type="hidden" value="/wEPDwULLTE2OTg2NjA1NTAPZBYCAgMPZBYGAgMPD2QWAh4Kb25rZXlwcmVzcwUlcmV0dXJuIGNsaWNrQnV0dG9uKGV2ZW50LCAnYl9Mb2dpbicpO2QCBQ8PZBYCHwAFJXJldHVybiBjbGlja0J1dHRvbihldmVudCwgJ2JfTG9naW4nKTtkAgcPD2QWAh4Hb25jbGljawUPcmV0dXJuIGxvZ2luKCk7ZGRKt/WTOQThVTxB9Y0QcIuRqylCIw==" id="__VIEWSTATE" name="__VIEWSTATE">
</div>

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


<div>

<input type="hidden" value="/wEWBAK0o8DDCQLxz5rcDwLF8dCIDALHyYWSA+rA4VJNaEpFIycMDHQPUOz393TI" id="__EVENTVALIDATION" name="__EVENTVALIDATION">
<input type="text" onkeypress="return clickButton(event, 'b_Login');" size="28" class="textfield-text" id="tb_Username" name="tb_Username">
<input type="password" onkeypress="return clickButton(event, 'b_Login');" size="28" class="textfield-text" id="tb_Password" name="tb_Password">
<a href="javascript:__doPostBack('b_Login','')" class="button-link" id="b_Login" onclick="return login();">Login</a>
</form>

1 个回答

9

根据源代码Scrapy使用以下CSS选择器来解析表单中的输入内容:

descendant::textarea|descendant::select|descendant::input[@type!="submit" and @type!="image" and @type!="reset"and ((@type!="checkbox" and @type!="radio") or @checked)]

换句话说,你所有的隐藏输入项都被成功解析出来(并且在后续请求中发送),这些输入的值等于value属性的内容。所以,Scrapy在这方面做得很好。

使用from_response()进行登录不成功,是因为__EVENTTARGETvalue属性是空的。如果你用真实的浏览器登录,__EVENTTARGET的参数值会通过JavaScript的__doPostBack()函数设置为b_Login。而Scrapy无法处理JavaScript(不能调用js函数),所以__EVENTTARGET被发送时是空值,这就导致了登录失败。

__EVENTARGUMENTvalue也是空的,但实际上在__doPostBack()函数中被设置为一个空字符串,所以在这里并没有影响。

希望这能帮到你。

撰写回答