代码下载地址:
https://github.com/happlyfox/FoxCrawler/tree/master/%E5%AD%A6%E4%B9%A0%E7%A4%BA%E4%BE%8B/YouKuCrawler/YouKuDotnetSpider2Async
基于文章三我们实现了爬虫框架单页面应用程序的代码,那么在这一章节我们将使用框架进行内容分页和多线程的操作
首先附上代码
public class YouKuCrawer
{
private static readonly string _url = "http://list.youku.com/category/video/c_0.html";
/// <summary>
/// 得到所有的类别
/// </summary>
public static List<VideoType> GetVideoTypes()
{
//加载web内容
var web = new HtmlWeb();
var doc = web.Load(_url);
//内容解析-获得所有的类别
var allTypes = doc.DocumentNode.SelectNodes("//*[@id='filterPanel']/div/ul/li/a").ToList();
//类别列表中去掉【全部】这个选项
var typeResults = allTypes.Where((u, i) => { return i > 0; }).ToList();
var reList = new List<VideoType>();
foreach (var node in typeResults)
{
var href = node.Attributes["href"].Value;
reList.Add(new VideoType
{
Code = href.Substring(href.LastIndexOf("/") + 1, href.LastIndexOf(".") - href.LastIndexOf("/") - 1),
Name = node.InnerText
});
}
return reList;
}
/// <summary>
/// 得到当前类别的总页数
/// </summary>
public static int GetPageCountByCode(string code)
{
var web = new HtmlWeb();
var doc = web.Load($"http://list.youku.com/category/show/{code}.html");
//分页列表
var pageList = doc.DocumentNode.CssSelect(".yk-pages li").ToList();
//得到倒数第二项
var lastsecond = pageList[pageList.Count - 2];
return Convert.ToInt32(lastsecond.InnerText);
}
}
因为所有的页面内容都相同,只是网站地址(url)不同,所以我首先得到所有的地址集合,然后赋给框架,让框架识别。
// 添加初始采集链接
// 定义采集的 Site 对象, 设置 Header、Cookie、代理等
var site = new Site { EncodingName = "UTF-8" };
foreach (var node in YouKuCrawer.GetVideoTypes())
{
//得到当前类别总分页数
var pageCount = YouKuCrawer.GetPageCountByCode(node.Code);
for (int pageIndex = 1; pageIndex <= pageCount; pageIndex++)
{
site.AddStartUrl($"http://list.youku.com/category/show/{node.Code}_s_1_d_1_p_{pageIndex}.html");
}
}
首先定时采集的site对象,然后site对象添加需要解析的相同的url。在上述操作完成后,我们开始进行“解析器”类和“管道”类的书写。
解析器类
public class YoukuPipeline : BasePipeline
{
public override void Process(IEnumerable<ResultItems> resultItems, ISpider spider)
{
var resultItem= resultItems.FirstOrDefault();
foreach (VideoContent entry in resultItem.GetResultItem("VideoResult"))
{
Console.WriteLine($"{entry.Title}\t\t{entry.Href}");
}
}
}
管道类
public class YoukuPipeline : BasePipeline
{
public override void Process(IEnumerable<ResultItems> resultItems, ISpider spider)
{
var resultItem= resultItems.FirstOrDefault();
foreach (VideoContent entry in resultItem.GetResultItem("VideoResult"))
{
Console.WriteLine($"{entry.Title}\t\t{entry.Href}");
}
}
}
最后对定义的内容进行整理
public static void CustmizeProcessorAndPipeline()
{
// 定义采集的 Site 对象, 设置 Header、Cookie、代理等
var site = new Site { EncodingName = "UTF-8" };
// 添加初始采集链接
foreach (var node in YouKuCrawer.GetVideoTypes())
{
//得到当前类别总分页数
var pageCount = YouKuCrawer.GetPageCountByCode(node.Code);
for (int pageIndex = 1; pageIndex <= pageCount; pageIndex++)
{
site.AddStartUrl($"http://list.youku.com/category/show/{node.Code}_s_1_d_1_p_{pageIndex}.html");
}
}
Spider spider = Spider.Create(site,
// 使用内存调度
new QueueDuplicateRemovedScheduler(),
// 为优酷自定义的 Processor
new YoukuPageProcessor())
//为优酷自定义的 Pipeline
.AddPipeline(new YoukuPipeline());
spider.Downloader = new HttpClientDownloader();
spider.ThreadNum = 10;
spider.EmptySleepTime = 3000;
// 启动爬虫
spider.Run();
}
线程定义
spider.ThreadNum = 10;
只需要通过自己的要求来进行赋值,框架自动识别内容优化线程操作。很方便