65.9K
CodeProject 正在变化。 阅读更多。
Home

半生成爬虫

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2012年6月23日

CPOL

4分钟阅读

viewsIcon

22198

downloadIcon

620

利用 Visual Studio Web Test Framework 来满足您的爬虫需求...

半生成爬虫

利用 VS Web Test Framework 为您创建爬虫。



目录

引言

好吧,我这辈子写过很多爬虫……比我想象的还要多。所以为了保持我的
热情,我创造了新的方法,用更少的时间做同样的事情!

在本文中,您将学习如何利用 Web Test Framework 和录制器
来创建网站爬虫。(**Visual Studio Ultimate** 版本才有,专业版或高级版没有)

也许您已经读过我关于
浏览器自动化
的文章。


如果您读过,我将使用相同的用例示例。

如果您还没有读过,这里有一个提醒:在本文结束时,您将拥有一个
应用程序,它将为我的文章投票!

这个过程快速而简单


喝咖啡是其中最难的部分。

用例:自动为本文投票 5 次

鉴于我的
浏览器自动化
文章获得的投票数,我决定使用相同的技巧来提高我的
在这里的投票数。


这个项目将为我投票!我是一个自恋的人。

所以,用一个经典的爬虫,您可能会说

  • 向 https://codeproject.org.cn/Articles/338036/BrowserAutomationCrawler 发送 GET 请求
  • 向操作 “submitLogin” 发送带有登录参数和密码参数的 POST 请求
  • 保存 cookie
  • 使用 cookie 向操作 “Vote” 发送 POST 请求 vote=5, articleId=MyArticleId

这可能会奏效,但问题是我完全虚构了参数和操作名称,所以
您需要 Fiddler 来正确地微调请求。(而且取决于
网站,这可能非常非常困难,尤其是对于 AJAX 操作)

另一种做同样事情的方法是说

  • 转到 https://codeproject.org.cn/Articles/338036/BrowserAutomationCrawler
  • 如果存在“登出”,则表示您已登录,

    else


    等待我点击“登录”(这样我就可以手动填写电子邮件和密码)
  • 然后点击“投票 5”选项
  • 在评论文本框中填入“5分,尼古拉斯很棒,感谢您的工作! 微笑 | <img src= " />”
  • 点击投票按钮

这就是我对浏览器自动化文章的做法。

现在我有了新的方法

  • 用 Web Test 录制打开 IE
  • 点击,点击,点击
  • 生成代码
  • 修改爬虫的自定义属性中的登录/密码部分
    类。

所以,首先,您需要创建一个新的控制台项目来存放代码
GeneratedCrawler.Sample.

然后创建一个新的测试项目,我将其命名为 GeneratedCrawler.Tests


在此测试项目中,右键单击项目/添加/新建测试,然后选择一个新的
Web Performance Test,我将其命名为 CodeProjectVoter


然后 IE 中的浏览器会话打开……

浏览到 CodeProject,并找到这篇文章的链接,登录,为我投票 5 次,并附带一段
精彩的评论……

如果您的浏览器在启动时已登录 CodeProject,您需要先
登出,停止录制,然后从头开始。


如果您已登录,我们的爬虫将无法生成成功登录 CodeProject 所需的代码

别忘了点击投票!!


您可以看到我用了另一篇文章……这是因为鸡生蛋、蛋生鸡
问题:创建我文章中的文章……当我注意到我的
思绪卡住了。

然后您可以停止录制,然后生成代码。


现在这是诀窍……生成的代码对大量的 DLL 具有严重的依赖关系
并且与 MSTest 绑定。


这段代码很难在您自己的项目中运行,除非直接使用 MSTest.exe……


所以我反编译了 MSTest 的 DLL,查看了内部情况,并创建了一个项目,其中包含相同的类,删除了所有依赖项。

LightWebTestFramework 就此诞生。

所以,首先,将测试项目中的生成代码复制到前面创建的控制台项目中:GeneratedCrawler.Sample

显然,代码无法编译,因为 GeneratedCrawler.Sample 没有引用任何 MSTest 程序集……改为引用 LightWebTestFramework

然后使用 LightWebTestFramework 命名空间而不是 Microsoft 的。


现在在您的代码中调用爬虫。

class Program
{
	static void Main(string[] args)
	{
		new CodeProjectVoterCoded().Execute();
	}
}

但是等等……我们忘了将登录和密码指定为爬虫的属性。

public class CodeProjectVoterCoded : WebTest
{
	public CodeProjectVoterCoded()
	{
		this.PreAuthenticate = true;
	}
 
	public string Login
	{
		get;
		set;
	}
	public string Password
	{
		get;
		set;
	}

更新 program.cs…

class Program
{
	static void Main(string[] args)
	{
		new CodeProjectVoterCoded()
			{
				Login = "slashene@gmail.com",
				Password = "blabla"
			}.Execute();
	}
}

然后只需在 CodeProjectVoterCoded 中找到在录制步骤期间使用的登录/密码在哪里出现,
并用您的属性替换它们。


然后您可以随意将其他属性泛化…… 

清理一些您不需要依赖的请求(例如 ScoreCard Research 请求)……然后您就拥有了完整的爬虫。

static void Main(string[] args)
{
	new CodeProjectVoterCoded()
		{
			Login = "slashene@gmail.com",
			Password = "blabla",
			ArticleId = 409009,
			Vote = 5,
			Comment = "5 for me, great work Nicolas !!!"
		}.Execute();
} 

这是最终完全生成然后自定义的爬虫的完整代码 : 

namespace GeneratedCrawler.Tests
{
	using System;
	using System.Collections.Generic;
	using System.Text;
	//using Microsoft.VisualStudio.TestTools.WebTesting;
	//using Microsoft.VisualStudio.TestTools.WebTesting.Rules;
	using LightWebTestFramework;
	using LightWebTestFramework.Rules;
	using System.Web;


	public class CodeProjectVoterCoded : WebTest
	{
		public CodeProjectVoterCoded()
		{
			this.PreAuthenticate = true;
		}


		public string Login
		{
			get;
			set;
		}
		public string Password
		{
			get;
			set;
		}
		public int ArticleId
		{
			get;
			set;
		}
		public int Vote
		{
			get;
			set;
		}
		public string Comment
		{
			get;
			set;
		}
		public override IEnumerator<webtestrequest> GetRequestEnumerator()
		{
			// Initialize validation rules that apply to all requests in the WebTest
			if((this.Context.ValidationLevel >= ValidationLevel.Low))
			{
				ValidateResponseUrl validationRule1 = new ValidateResponseUrl();
				this.ValidateResponse += new EventHandler<validationeventargs>(validationRule1.Validate);
			}
			if((this.Context.ValidationLevel >= ValidationLevel.Low))
			{
				ValidationRuleResponseTimeGoal validationRule2 = new ValidationRuleResponseTimeGoal();
				validationRule2.Tolerance = 0D;
				this.ValidateResponseOnPageComplete += new EventHandler<validationeventargs>(validationRule2.Validate);
			}

			WebTestRequest request1 = new WebTestRequest("https://codeproject.org.cn/");
			WebTestRequest request1Dependent1 = new WebTestRequest("http://b.scorecardresearch.com/b");
			request1Dependent1.ThinkTime = 24;
			request1Dependent1.QueryStringParameters.Add("c1", "2", false, false);
			request1Dependent1.QueryStringParameters.Add("c2", "13507173", false, false);
			request1Dependent1.QueryStringParameters.Add("ns__t", "1340383504029", false, false);
			request1Dependent1.QueryStringParameters.Add("ns_c", "utf-8", false, false);
			request1Dependent1.QueryStringParameters.Add("c8", "CodeProject%20-%20Your%20Development%20Resource", false, false);
			request1Dependent1.QueryStringParameters.Add("c7", "http%3A%2F%2Fwww.codeproject.com%2F", false, false);
			request1Dependent1.QueryStringParameters.Add("c9", "", false, false);
			request1.DependentRequests.Add(request1Dependent1);
			ExtractHiddenFields extractionRule1 = new ExtractHiddenFields();
			extractionRule1.Required = true;
			extractionRule1.HtmlDecode = true;
			extractionRule1.ContextParameterName = "1";
			request1.ExtractValues += new EventHandler<extractioneventargs>(extractionRule1.Extract);
			yield return request1;
			request1 = null;

			WebTestRequest request2 = new WebTestRequest("https://codeproject.org.cn/script/Membership/LogOn.aspx");
			request2.Method = "POST";
			request2.ExpectedResponseUrl = "https://codeproject.org.cn/";
			request2.QueryStringParameters.Add("rp", "%2f", false, false);
			FormPostHttpBody request2Body = new FormPostHttpBody();
			request2Body.FormPostParameters.Add("FormName", this.Context["$HIDDEN1.FormName"].ToString());
			request2Body.FormPostParameters.Add("Email", Login);
			request2Body.FormPostParameters.Add("Password", Password);
			request2.Body = request2Body;
			yield return request2;
			request2 = null;

			WebTestRequest request4 = new WebTestRequest("https://codeproject.org.cn/Script/Ratings/Ajax/RateItem.aspx");
			request4.QueryStringParameters.Add("obid", ArticleId.ToString(), false, false);
			request4.QueryStringParameters.Add("obtid", "2", false, false);
			request4.QueryStringParameters.Add("obstid", "1", false, false);
			request4.QueryStringParameters.Add("rvv", Vote.ToString(), false, false);
			request4.QueryStringParameters.Add("rvc", HttpUtility.UrlEncode(Comment), false, false);
			yield return request4;
			request4 = null;
		}
	}
} 

如果登录/密码错误,您不会收到任何异常或崩溃,只是不起作用,我留给您处理。 微笑 | :)  

如果您需要任何信息以满足您自己的需求,请不要忘记生成的爬虫是 WebTest 的子类,它带有一些很酷的属性。

结论 

能力越大,责任越大,我希望您能为正义而爬取! 

© . All rights reserved.