汽车之家汽车品牌Logo信息抓取 DotnetSpider实战[三]

一、正题前的唠叨

第一篇实战博客,阅读量1000+,第二篇,阅读量200+,两篇文章相差近5倍,这个差异真的令我很费劲,截止今天,我一直在思考为什么会有这么大的差距,是因为干货变少了,还是什么原因,一直没想清楚,如果有读者发现问题,可以评论写下大家的观点,当出现这样的差距会是什么原因,谢谢大家。

编者:web流量下降,手机流量增加,导致博客访问量不及预期,虽然每天给大家摘选有价值的文章,欢迎阅读原文去看看作者更多的文章。

二、分析汽车之家品牌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);

                var intervalPath = new Uri(url);

                string filePath = Environment.CurrentDirectory + "/img/";

                if (!File.Exists(filePath))

                {

                    try

                    {

                        string folder = Path.GetDirectoryName(filePath);

                        if (!string.IsNullOrWhiteSpace(folder))

                        {

                            if (!Directory.Exists(folder))

                            {

                                Directory.CreateDirectory(folder);

                            }

                        }


                        File.WriteAllBytes(filePath + filename + ".jpg", 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 

六、下期没有预告

 至于下期我还没想好爬什么,欢迎大家留言说自己想要爬的东西

相关文章:

原文地址: http://www.cnblogs.com/FunnyBoy/p/9029937.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321248.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

洛谷P1801 黑匣子 双堆套路的使用

题意 题目链接 题解 这道题本可以用Treap暴力求解出来&#xff0c;但是不够优雅&#xff0c;因为没有充分利用到题目中给的条件&#xff0c;那就是要求的ithith小的值的ii是单调递增的。我们用两个堆来维护,大顶堆和小顶堆。 大顶堆中的元素是排好序的前i&#x2212;1&qu…

2019.01.26【NOIP普及组】模拟赛C组总结

总结 这次比赛的得分是&#xff1a;10001060170 第一题想了一会&#xff0c;想到了方法&#xff0c;直接打出来&#xff0c;第二题不会&#xff0c;想水分&#xff0c;但没水到&#xff0c;第三题打了一个假的DP&#xff0c;10分&#xff0c;第四题用DP超时了&#xff0c;60分…

nssl1468-V【状压,数学期望,dfs】

正题 题目大意 nnn个球排成一排颜色不同&#xff0c;每次选择一个随机的[1..n][1..n][1..n]中的xxx&#xff0c;然后删掉第xxx个或第n−x1n-x1n−x1个数&#xff0c;求删kkk次之后删掉的白球最多&#xff0c;求删掉数量的期望值 解题思路 考虑状态压缩dpdpdp&#xff0c;定义第…

洛谷 一种堆套路 P1631序列合并、P2085最小函数值

题目链接 序列合并 最小函数值 题解 这两道题做法基本一样&#xff0c;是使用同一种套路解决的&#xff0c;这里用序列合并来举例说明。 序列合并要求出N2N2个和中最小的N个数。 我们用一个堆来维护我们需要的数&#xff0c;并且保证当前最小值一定在堆中。 把a和b排个序…

.NET Core 2.1 正式发布

这次更新包括对性能的改进&#xff0c;对运行时和工具的改进。还包含一种以 NuGet 包的形式部署工具的新方法。我们添加了一个名为 Span<T> 的新基元类型&#xff0c;它可以在没有内存分配的情况下对数据进行操作。还有许多其他新的 API&#xff0c;专注于密码学&#xf…

纪中培训总结(2019年1月21~31日)

Day 0&#xff08;21号&#xff09; 中午从家里出发&#xff0c;坐了两个小时的车&#xff08;堵得要命&#xff09;&#xff0c;过了虎门大桥&#xff0c;在一个服务站吃起了晚餐&#xff08;麦当劳的包&#xff09;&#xff0c;又坐了一个小时的车&#xff0c;终于到了&…

nssl1469-W【dp】

正题 题目大意 nnn个点的一棵树&#xff0c;每条边一个权值为0或1和一个目标权值&#xff08;0或1或者没有限制&#xff09;。每次可以将一个路径上的权值取反&#xff0c;求最小翻转数量和最小翻转路径长度。 解题思路 首先我们可以从序列的类似问题上知道一条边不会被翻转超…

[翻译] 比较 Node.js,Python,Java,C# 和 Go 的 AWS Lambda 性能

原文: Comparing AWS Lambda performance of Node.js, Python, Java, C# and GoAWS 最近宣布他们支持了 C&#xff03; (Net Core 2.0 版本) 和 Go 语言来实现 Lambda 功能。(译者注: AWS Lambda 是 AWS 推出的 Serverless 功能&#xff0c;请参阅这里或 Serverless 相关资料)做…

codeforces gym-101745 C-Infinite Graph Game 分块

题意 题目链接 给出一个顶点带权无向图。 定义访问操作&#xff1a;访问一个点&#xff0c;就要把与这个点相邻的点的权值全部都加到答案里去&#xff0c;然后给这个顶点的权值/2。现在给出一个无穷的访问序列中的一个循环节&#xff0c;求最终答案的极限是多少。 注意&…

P5579-[PA2015]Siano【线段树】

正题 题目链接:https://www.luogu.com.cn/problem/P5579 题目大意 nnn个树&#xff0c;第iii个每天长高aia_iai​米。 mmm次修剪&#xff0c;第iii次在did_idi​天&#xff0c;将高度为bib_ibi​的部分修剪掉 求每次修剪掉的高度 解题思路 按照aia_iai​排序后我们知道每次修…

【结论】立体井字棋(jzoj 2124)

立体井字棋 题目大意&#xff1a; 在一个nnn的正方体中&#xff0c;由n个格子连成一条直线的方案数&#xff08;多少种可能用n个格子连成一条直线&#xff09; 样例输入 2 样例输出 28 数据范围限制 对于30%的数据&#xff0c; n<10&#xff1b; 对于100%的数据&am…

ASP.NET Core Identity 实战(3)认证过程

如果你没接触过旧版Asp.Net Mvc中的 Authorize 或者 Cookie登陆&#xff0c;那么你一定会疑惑 认证这个名词&#xff0c;这太正式了&#xff0c;这到底代表这什么&#xff1f;获取资源之前得先过两道关卡Authentication & Authorization要想了解Identity中用户登录之后&…

codeforces gym-101745 D-Stamp Stamp Stamp动态规划

题解 一道很不错的动态规划问题&#xff0c;首先这些印章一定是s的子串。 我们可以枚举s的子串然后进行check。 如何check&#xff0c;成了这道题的关键。 由于盖章的顺序不知道&#xff0c;所以我们可以使用动态规划的方法。 我们定义状态&#xff1a; dp[i][j]dp[i][j]…

【图论】【最短路】【SPFA】【USACO题库】2.4.4 Bessie Come Home回家(jzoj 1274)

Bessie Come Home回家 题目大意: 有n条路连接着一些牧场&#xff0c;每个牧场由‘a-z’&#xff08;没羊&#xff09;和‘A-Y’&#xff08;有一头羊&#xff09;&#xff0c;问哪个有羊的牧场离‘Z’最近 INPUT FORMAT 第 1 行: 整数 P(1< P<10000),表示连接牧场(谷…

nssl1470-X【并查集,素数】

正题 题目大意 将nnn个数分为222个非空的集合&#xff0c;要求两个集合内数的乘积的gcdgcdgcd为111。求方案数 解题思路 拥有相同质因子的数一定要在同一组&#xff0c;枚举质因数然后将拥有的数都用并查集合并然后用联通块数量来求即可。 codecodecode #include<cstdio&…

尝鲜.net core2.1 ——编写一个global tool

本文内容参考微软工程师Nate McMaster的博文.NET Core 2.1 Global Tools用过npm开发都知道&#xff0c;npm包都可以以全局的方式安装&#xff0c;例如安装一个http-server服务&#xff0c;可以使用npm i http-server -g来将http-server包安装到全局环境。安装完之后&#xff0c…

codeforces gym-101755 D-Transfer Window 二分图匹配、递归

题目 题目链接 题意 告诉了n名球员的交换关系&#xff0c;你现在拥有k名球员&#xff0c;你想要其他k名球员(有的在自己队里)。 输出一种交换方案。 题解 第一步、求闭包。 我们需要在原来的交换矩阵上跑可达闭包&#xff0c;即G[i][j]G[i][j]的含义是jj是否能通过i&quo…

【最短路】【Dijkstra】【图论】最小花费(jzoj 2125)

最小花费 题目大意&#xff1a; n个人&#xff0c;一些人之间可以相互转账&#xff0c;但又手续费x%,问A转给B100元至少要多少钱 样例输入 3 3 1 2 1 2 3 2 1 3 3 1 3 样例输出 103.07153164 数据范围限制 对于所有数据&#xff0c; 1 < n <2000。 解题思路…

jzoj1471-Y【bitset,dp,状压】

正题 题目大意 nnn个点mmm条边&#xff0c;边上是0/10/10/1&#xff0c;求有多少种不同的长度为ddd的路径序列 解题思路 我们将ddd分为两半&#xff0c;定义fi,j,sf_{i,j,s}fi,j,s​表示从iii出发到jjj&#xff0c;路径序列状态sss是否可行。 然后我们可以用bitsetbitsetbits…

Comet OJ-栈的数据结构题【线段树】

正题 题目链接:https://cometoj.com/contest/79/problem/E?problem_id4207 题目大意 nnn个栈&#xff0c;要求支持操作 l∼rl\sim rl∼r区间内的栈压入一个数l∼rl\sim rl∼r区间内的栈弹出一个数求第xxx个栈内第kkk个数 解题思路 对于每个询问我们其实就是要求在他之前的第…