使用分页抓取 ASP.NET 个网站
Scrape ASP.NET website with paging
我正在尝试抓取一个具有分页功能的基本 asp.net 目录网站。
该网站有 50 多个页面,其中任何一页最多包含 10 个分页链接。
我正在使用 fiddler 来帮助复制使用浏览器 posted 的所有参数、变量、表单字段、cookie 等。我看到两个 post 之间的唯一区别是 __EVENTVALIDATION
值。
使用 HttpWebRequest 我总是有相同的值,同时通过浏览器每次点击它的变化。
使用 HttpWebRequest,我正确地获得了前 10 个页面,但是所有以下页面都将我重定向到主页。波纹管是 post 返回 javascript 前 10 个链接之后的链接始终相同。
javascript:__doPostBack('CT_Main_2$gvDirectorySearch$ctl53$ctl00$ctl11','')
知道为什么 __EVENTVALIDATION
不随 HttpWebRequest 改变吗?
根据你的描述,这听起来像一个 anti-forgery token
,一个 anti-forgery token
用于防止 cross-site request forgery (XSRF)
攻击..
对于利用防伪令牌的站点,它通常会在客户端的浏览器中设置一个 cookie,并且它会期望使用与所发布表单中的参数完全相同的令牌。
为了解决这个问题,您需要发送服务器在后续请求中设置的令牌,您还需要扫描 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);
}
}
我正在尝试抓取一个具有分页功能的基本 asp.net 目录网站。
该网站有 50 多个页面,其中任何一页最多包含 10 个分页链接。
我正在使用 fiddler 来帮助复制使用浏览器 posted 的所有参数、变量、表单字段、cookie 等。我看到两个 post 之间的唯一区别是 __EVENTVALIDATION
值。
使用 HttpWebRequest 我总是有相同的值,同时通过浏览器每次点击它的变化。
使用 HttpWebRequest,我正确地获得了前 10 个页面,但是所有以下页面都将我重定向到主页。波纹管是 post 返回 javascript 前 10 个链接之后的链接始终相同。
javascript:__doPostBack('CT_Main_2$gvDirectorySearch$ctl53$ctl00$ctl11','')
知道为什么 __EVENTVALIDATION
不随 HttpWebRequest 改变吗?
根据你的描述,这听起来像一个 anti-forgery token
,一个 anti-forgery token
用于防止 cross-site request forgery (XSRF)
攻击..
对于利用防伪令牌的站点,它通常会在客户端的浏览器中设置一个 cookie,并且它会期望使用与所发布表单中的参数完全相同的令牌。
为了解决这个问题,您需要发送服务器在后续请求中设置的令牌,您还需要扫描 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);
}
}