一、正題前的嘮叨
第一篇實戰博客,閱讀量1000+,第二篇,閱讀量200+,兩篇文章相差近5倍,這個差異真的令我很費勁,截止今天,我一直在思考為什么會有這么大的差距,是因為干貨變少了,還是什么原因,一直沒想清楚,如果有讀者發現問題,可以評論寫下大家的觀點,當出現這樣的差距會是什么原因,謝謝大家。
二、分析汽車之家品牌Logo頁面
2.1分析頁面結構
首先我們打開汽車之家品牌Logo選擇頁 https://car.m.autohome.com.cn/,我們以華頌為例,實際上我們就是需要將class是item的里面的img的src(圖片路徑),和strong里面的text(品牌)獲取就行了,大家可以看到,這個其實很簡單,相比上次我們獲取頁面,獲取接口數據簡單多了,為什么要單獨拿一個作為一篇文章呢,就是因為這個地方還涉及到一個文件下載,這一塊之前都沒有提到過。
2.2頁面中的坑
最開始抓取的時候,我發現很多地方src都是空,我就很納悶為什么會這樣,后來斷點調試后才發現,汽車之家Logo圖片在頁面還未划到此處的時候,img是不會加載的,只是占一個位置在那,等到滾動條滾到哪,哪的圖片就會加載,所以此處抓取img的路徑時需要判斷一下
三、動手開發
3.1准備Processor
private class GetLogoInfoProcessor : BasePageProcessor //獲取Logo信息 { public GetLogoInfoProcessor() { } protected override void Handle(Page page) { List<LogoInfoModel> logoInfoList = new List<LogoInfoModel>(); var logoInfoNodes = page.Selectable.XPath(".//div[@id='div_ListBrand']//div[@class='item']").Nodes(); foreach (var logoInfo in logoInfoNodes) { LogoInfoModel model = new LogoInfoModel(); model.BrandName = logoInfo.XPath("./strong").GetValue(); model.ImgPath = logoInfo.XPath("./img/@src").GetValue(); if (model.ImgPath == null) { model.ImgPath = logoInfo.XPath("./img/@data-src").GetValue(); } if (model.ImgPath.IndexOf("https") == -1) { model.ImgPath = "https:" + model.ImgPath; } logoInfoList.Add(model); //page.AddTargetRequest(model.ImgPath); //Site設置DownloadFiles為TRUE就可以自動下載文件 } page.AddResultItem("LogoInfoList", logoInfoList); } }
3.2准備Pipeline
這個地方我沒用他原用的下載方法,自己寫了一個簡單的下載方法,因為我感覺他的下載方式直接down下來,不是很符合我的業務邏輯
private class PrintLogInfoPipe : BasePipeline { public override void Process(IEnumerable<ResultItems> resultItems, ISpider spider) { foreach (var resultItem in resultItems) { var logoInfoList = resultItem.GetResultItem("LogoInfoList") as List<LogoInfoModel>; foreach (var logoInfo in logoInfoList) { Console.WriteLine($"brand:{logoInfo.BrandName} path:{logoInfo.ImgPath}"); SaveFile(logoInfo.ImgPath, logoInfo.BrandName); } } } private void SaveFile(string url, string filename) { HttpRequestMessage httpRequestMessage = new HttpRequestMessage(); httpRequestMessage.RequestUri = new Uri(url); httpRequestMessage.Method = HttpMethod.Get; HttpClient httpClient = new HttpClient(); var httpResponse = httpClient.SendAsync(httpRequestMessage); string filePath = Environment.CurrentDirectory + "/img/"+ filename + ".jpg"; if (!File.Exists(filePath)) { try { string folder = Path.GetDirectoryName(filePath); if (!string.IsNullOrWhiteSpace(folder)) { if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } } File.WriteAllBytes(filePath, httpResponse.Result.Content.ReadAsByteArrayAsync().Result); } catch { } } httpClient.Dispose(); } }
存儲實體類
private class LogoInfoModel { public string BrandName { get; set; } public string ImgPath { get; set; } }
3.3構造爬蟲
static void Main(string[] args) { var site = new Site { CycleRetryTimes = 1, SleepTime = 200, //DownloadFiles = true, DotNetSpider中設置是否下載文件 Headers = new Dictionary<string, string>() { { "Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" }, { "Cache-Control","no-cache" }, { "Connection","keep-alive" }, { "Content-Type","application/x-www-form-urlencoded; charset=UTF-8" }, { "User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36"} } }; List<Request> resList = new List<Request>(); Request res = new Request(); res.Url = "https://car.m.autohome.com.cn/"; res.Method = System.Net.Http.HttpMethod.Get; resList.Add(res); var spider = Spider.Create(site, new QueueDuplicateRemovedScheduler(), new GetLogoInfoProcessor()) .AddStartRequests(resList.ToArray()) .AddPipeline(new PrintLogInfoPipe()); spider.ThreadNum = 1; spider.Run(); Console.Read(); }
3.4 Site中DownloadFiles 源碼分析
源代碼中HttpClientDownloader中源代碼會自動去判斷Site中的DownloadFiles是否允許下載文件,默認是false,如果不將DownloadFiles的值設置為true,那么對於非字符串格式的接口數據,直接會被忽略,如果大家感興趣,可以將我代碼中的兩行注釋取消,那么就可以看到DotnetSpider中的下載方式
四、執行結果
本次執行的結果,已經上傳到bilibili中,大家有興趣可以打開圍觀一下
https://www.bilibili.com/video/av24022630/
五、總結
這次我們將數據的抓取以及文件的下載進行了一個小綜合,也介紹了DotnetSpider原生的下載方式,以及我自己寫的一個下載方法,大家如果遇到類似的需求可以自己選擇符合自己業務邏輯的方法,希望這篇文章能夠幫助到大家,如果覺得哪里寫的不好,歡迎拍大板磚
三次博文源代碼我已經上傳Github,感興趣可以直接下載下來 https://github.com/FunnyBoyDeng/SpiderAutoHome
六、下期沒有預告
至於下期我還沒想好爬什么,歡迎大家留言說自己想要爬的東西
2018-05-27