我正在开发一个非常具体的网络抓取应用程序,它需要登录到多个网站并从中检索一些数据。
我正在使用已通过覆盖以下方法了解cookie的WebClient:
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
var castRequest = request as HttpWebRequest;
if (castRequest != null)
{
castRequest.CookieContainer = this.CookieContainer;
}
return request;
}
我可以通过常规的POST / GET请求(通过webclient上的相应下载/上传方法)登录网站
目标网站使用ajax ASP.Net顶级表单,并且在您单击页面上的按钮后会启用一个状态变量。也就是说,当您单击按钮时,表单将被提交,状态会发生变化,然后在加载响应时它会获得我需要的信息。此时的状态修改也是持久的。如果我重新加载页面,甚至关闭选项卡并重新打开它,我需要的数据仍然存在,因为它与ASP会话相关联。一旦ASP会话到期,您必须先登录并再次单击该按钮,然后服务器才会发送我需要的数据。
我在点击按钮时通过Chrome开发者工具观看了提交的表单,然后我重新创建了表单提交,就像我在Chrome网络观看窗口中看到的一样,但它仍然无法正确修改视图状态。
所以我的问题是,如何模拟单击此按钮,以便服务器将修改视图状态并返回我需要的值。
我不能使用网络浏览器控件,但我可以使用html敏捷包,如果它使事情变得更容易(虽然我真的不想使用外部库)
按钮定义如下:
<form name="aspnetForm" method="post" action="enterurlhere..." id="aspnetForm">
<input type="image" name="ctl00$....." id="ctl00...." title="...." src="...." style="height:50px;border-width:0px;">
答案 0 :(得分:3)
如果您的目标是ASP.NET WebForms站点:
1)您必须先登录才能导航到所需的页面
2)在所需的页面上有一个UpdatePanel,让我们说一个文本框,你需要输入一些东西,然后提交那些信息,如果这些信息是正确的,你将得到&#34;你期望什么&#34;
我之前已经完成了各种抓取工具,因此将其中一个作为基础但是已经完全剥离,很多,没有错误记录,验证您已登录,验证您在请求时仍然登录页面,HtmlAgilityPack,结构,代码清洁,用户代理字符串随机化等,以保持简单,但你当然可以增强它:)无论如何,我已经在Visual Studio 2013中创建了一个Web项目(Web窗体)你可能知道它有一些登陆页面,包括用户注册等。然后你有&#34;管理帐户&#34;页面,显然需要用户进行身份验证。在那个页面上我添加了另一个div,然后在其中放置了UpdatePanel(这使得回发被ajaxified)。在UpdatePanel里面,我放置了文本框,一个按钮和一个文字服务器控件。在后面的代码中,我为该按钮添加了一个单击事件处理程序:如果用户输入等于,请说&#34; secret&#34;然后将一些文本放入文字中以表明操作成功。因此,应用程序必须首先登录,然后通过将密码提交到&#34;管理帐户&#34;来获取该秘密文本。页。
实际抓取者:
using Pokemon.BL.Utils;
using System;
using System.Text;
using System.Web;
namespace Pokemon.BL
{
sealed class UrlFetcher : IDisposable
{
private static readonly UrlFetcher _instance;
private CGWebClient _cgWebClient;
private string loginPostString = "__EVENTTARGET={0}&__EVENTARGUMENT={1}&__VIEWSTATE={2}&__VIEWSTATEGENERATOR={3}&__EVENTVALIDATION={4}&ctl00$MainContent$Email={5}&ctl00$MainContent$Password={6}&ctl00$MainContent$ctl05={7}";
private string secretPhrasePostString = "__EVENTTARGET={0}&__EVENTARGUMENT={1}&__VIEWSTATE={2}&__VIEWSTATEGENERATOR={3}&__EVENTVALIDATION={4}&__ASYNCPOST=true&ctl00$MainContent$btnGetSecretPhrase=Button&ctl00$ctl08=ctl00$MainContent$UpdatePanel1|ctl00$MainContent$btnGetSecretPhrase&ctl00$MainContent$txtSecret={5}";
private UrlFetcher()
{
_cgWebClient = new CGWebClient();
}
static UrlFetcher()
{
_instance = new UrlFetcher();
}
#region Methods
public void LoginToSite(string email, string password)
{
var loginUrl = "http://localhost:53998/Account/Login";
byte[] response = _cgWebClient.DownloadData(loginUrl);
var content = Encoding.UTF8.GetString(response);
string eventTarget = ExtractToken("__EVENTTARGET", content);
string eventArg = ExtractToken("__EVENTARGUMENT", content);
string viewState = ExtractToken("__VIEWSTATE", content);
string viewStateGen = ExtractToken("__VIEWSTATEGENERATOR", content);
string eventValidation = ExtractToken("__EVENTVALIDATION", content);
string postData = string.Format(
loginPostString,
eventTarget,
eventArg,
viewState,
viewStateGen,
eventValidation,
email,
password,
"Log in"
);
_cgWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
response = _cgWebClient.UploadData(loginUrl, "POST", Encoding.UTF8.GetBytes(postData));
_cgWebClient.Headers.Remove("Content-Type");
}
public void GetSecretPhrase()
{
var loginUrl = "http://localhost:53998/Account/Manage";
byte[] response = _cgWebClient.DownloadData(loginUrl);
var content = Encoding.UTF8.GetString(response);
string eventTarget = ExtractToken("__EVENTTARGET", content);
string eventArg = ExtractToken("__EVENTARGUMENT", content);
string viewState = ExtractToken("__VIEWSTATE", content);
string viewStateGen = ExtractToken("__VIEWSTATEGENERATOR", content);
string eventValidation = ExtractToken("__EVENTVALIDATION", content);
string postData = string.Format(
secretPhrasePostString,
eventTarget,
eventArg,
viewState,
viewStateGen,
eventValidation,
"secret"
);
_cgWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
_cgWebClient.Headers.Add("X-Requested-With", "XMLHttpRequest");
response = _cgWebClient.UploadData(loginUrl, "POST", Encoding.UTF8.GetBytes(postData));
_cgWebClient.Headers.Remove("Content-Type");
_cgWebClient.Headers.Remove("X-Requested-With");
Console.WriteLine(Encoding.UTF8.GetString(response));
}
#region IDisposable Members
public void Dispose()
{
if (_cgWebClient != null)
{
_cgWebClient.Dispose();
}
}
#endregion
private string ExtractToken(string whatToExtract, string content)
{
string viewStateNameDelimiter = whatToExtract;
string valueDelimiter = "value=\"";
int viewStateNamePosition = content.IndexOf(viewStateNameDelimiter);
int viewStateValuePosition = content.IndexOf(valueDelimiter, viewStateNamePosition);
int viewStateStartPosition = viewStateValuePosition + valueDelimiter.Length;
int viewStateEndPosition = content.IndexOf("\"", viewStateStartPosition);
return HttpUtility.UrlEncode(
content.Substring(
viewStateStartPosition,
viewStateEndPosition - viewStateStartPosition
)
);
}
#endregion
#region Properties
public static UrlFetcher Instance { get { return _instance; } }
#endregion
}
}
WebClient包装器:
using System;
using System.Collections.Generic;
using System.Net;
namespace Pokemon.BL.Utils
{
// http://codehelp.smartdev.eu/2009/05/08/improve-webclient-by-adding-useragent-and-cookies-to-your-requests/
public class CGWebClient : WebClient
{
private System.Net.CookieContainer cookieContainer;
private string userAgent;
private int timeout;
public System.Net.CookieContainer CookieContainer
{
get { return cookieContainer; }
set { cookieContainer = value; }
}
public string UserAgent
{
get { return userAgent; }
set { userAgent = value; }
}
public int Timeout
{
get { return timeout; }
set { timeout = value; }
}
public CGWebClient()
{
timeout = -1;
userAgent = "Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0";
cookieContainer = new CookieContainer();
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request.GetType() == typeof(HttpWebRequest))
{
((HttpWebRequest)request).CookieContainer = cookieContainer;
((HttpWebRequest)request).UserAgent = userAgent;
((HttpWebRequest)request).Timeout = timeout;
}
return request;
}
}
}
最后运行它:
UrlFetcher.Instance.LoginToSite("username", "password");
UrlFetcher.Instance.GetSecretPhrase();
UrlFetcher.Instance.Dispose();
这将秘密短语输出到控制台应用程序中。当然,您需要调整它以使其工作,例如,取决于您的目标站点运行的ASP.NET版本等等:) 希望这会有所帮助:)
答案 1 :(得分:-1)
我认为这不会在服务器端工作,因为客户端需要会话信息。为此,您可以实现一个Iframe控件,您可以在其中加载表单并调用服务器端或客户端调用以单击Iframe中的按钮并加载会话信息。