使用分页刮取ASP.NET网站

时间:2015-04-19 08:14:40

标签: c# asp.net httpwebrequest

我正在尝试抓取一个具有分页功能的基本asp.net目录网站。

该网站有超过50个页面,在任何一个页面上最多包含10个分页链接。

我使用fiddler来帮助复制使用浏览器发布的所有参数,变量,表单字段,Cookie等。我在两个帖子之间看到的唯一区别是__EVENTVALIDATION值。

使用HttpWebRequest我总是拥有相同的价值,而浏览器每次点击都会有变化。

使用HttpWebRequest我正确地获取了10个第一页但是以下所有页面都将我重定向到主页。 Bellow是回复javascript,对于前10个之后的链接总是相同的。

javascript:__doPostBack('CT_Main_2$gvDirectorySearch$ctl53$ctl00$ctl11','')

为什么__EVENTVALIDATION不会随着HttpWebRequest而改变?

1 个答案:

答案 0 :(得分:3)

根据您的说明,它听起来像anti-forgery tokenanti-forgery token用于阻止cross-site request forgery (XSRF)攻击..

对于要利用防伪令牌的网站,它通常会在客户端的浏览器中设置一个cookie,并且它会期望与正在发布的表单中的参数具有相同的标记。 / p>

要克服它,您需要在后续请求中发送服务器设置的令牌,您还需要扫描HTML表单以获取相同的令牌,并将其包括在内。


修改

所以我深入挖掘并创建了一个ASP.NET WebForms网站并试图复制您的问题,但无法在我设法提取__EVENTVALIDATION字段的每个请求上...

如果您发现任何有用的代码,请点击这里...

void Main()
{
    string eventValidationToken = string.Empty;

    var firstResponse = this.Get(@"http://localhost:7428/Account/Login");

    firstResponse.FormValues["ctl00$MainContent$Email"] = "email@example.com";
    firstResponse.FormValues["ctl00$MainContent$Password"] = "password";

    string secondRequestPostdata = firstResponse.ToString();
    var secondResponse = this.Post(@"http://localhost:7428/Account/Login", secondRequestPostdata);

    Console.WriteLine (firstResponse.FormValues["__EVENTVALIDATION"]);
    Console.WriteLine (secondResponse.FormValues["__EVENTVALIDATION"]);
}


public FormData Get(string uri)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:7428/Account/Login");
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using (Stream stream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(stream))
    {
        return  new FormData(reader.ReadToEnd());
    }
}

public FormData Post(string uri, string postContent)
{
    byte[] formBytes = Encoding.UTF8.GetBytes(postContent);

    var request = (HttpWebRequest)WebRequest.Create("http://localhost:7428/Account/Login");
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = formBytes.Length;

    using (Stream stream = request.GetRequestStream())
    {
        stream.Write(formBytes, 0, formBytes.Length);
    }

    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using (Stream stream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(stream))
    {
        return new FormData(reader.ReadToEnd());
    }
}

public class FormData
{
    public FormData(string html)
    {
        this.Html = html;

        this.FormValues = new Dictionary<string, string>();
        this.FormValues["__EVENTTARGET"]                = this.Extract(@"__EVENTTARGET");
        this.FormValues["__EVENTARGUMENT"]              = this.Extract(@"__EVENTARGUMENT");
        this.FormValues["__VIEWSTATE"]                  = this.Extract(@"__VIEWSTATE");
        this.FormValues["__VIEWSTATEGENERATOR"]         = this.Extract(@"__VIEWSTATEGENERATOR");
        this.FormValues["__EVENTVALIDATION"]            = this.Extract(@"__EVENTVALIDATION");
        this.FormValues["ctl00$MainContent$Email"]      = string.Empty;
        this.FormValues["ctl00$MainContent$Password"]   = string.Empty;
        this.FormValues["ctl00$MainContent$ctl05"]      = "Log in";
    }

    public string Html { get; set; }

    private string Extract(string id)
    {
        return Regex.Match(this.Html, @"id=""" + id + @""" value=""([^""]*)")
                    .Groups[1]
                    .Value;
    }

    public Dictionary<string, string> FormValues { get;set; }

    public override string ToString()
    {
        var formData = this.FormValues.Select(form => HttpUtility.UrlEncode(form.Key) + "=" + HttpUtility.UrlEncode(form.Value));

        return string.Join("&", formData);
    }
}