接下来一段时间,我会花些时间研究C#玩转爬虫 的方法及其实践。 话不多说,开始吧~ 一般来说: 设计并实现一个爬虫 的步骤是: 模拟登录 -> 模拟发送request请求 -> 取回response数据 -> 提取所需信息并将其进行重新组织 -> 存入DB或文件中 -> 后期处理或展示 流程图当然,有时还需要适当地应对所抓取目标站点的反爬虫策略 ,也就是大家常说的反反爬 ! 下文以抓取豆瓣音乐 为例来具体说明: 比如,我们在豆瓣音乐中搜索"摇滚"后爬取相关内容,然后写入csv文件中。 目标网址是: https://music.douban.com/tag/摇滚?start=0&type=T
抓取大概分为如下几个步骤: 获取页数每一页中都可以看到总的页数,直接取第1页 的就好。 byte[] buffer = webclient.DownloadData("https://music.douban.com/tag/%E6%91%87%E6%BB%9A?start=0&type=T"); // utf-8, gb2312, gbk, utf-1...... string html = System.Text.Encoding.GetEncoding("utf-8").GetString(buffer); 借助以上两行代码,就可以看到该网址Response的HTML字符串(debug时上面一行代码中html 的值)为: 我们选用模式串 ">[0-9][0-9]{0,}</a>" 进行匹配,由于下面的页码是从第一页算起的,选最大页数就是总页数。 相应的函数GetTotalCount 如下: private static int GetTotalCount(System.Net.WebClient webclient, int startIdx) { //html下载 /* https://music.douban.com/tag/%E6%91%87%E6%BB%9A?start=0&type=T */
byte[] buffer = webclient.DownloadData("https://music.douban.com/tag/%E6%91%87%E6%BB%9A?start=" + startIdx + "&type=T"); // utf-8, gb2312, gbk, utf-1...... string html = System.Text.Encoding.GetEncoding("utf-8").GetString(buffer);
MatchCollection pageCount_matches = new Regex(">[0-9][0-9]{0,}</a>").Matches(html);
if (pageCount_matches.Count == 0) return 0;
string tempPageNum = pageCount_matches[pageCount_matches.Count - 1].Value; int.TryParse(tempPageNum.Replace("</a>", string.Empty).Substring(1), out int lastPageNum);
return lastPageNum; } 获取当前页的数据用与上一步相同的方法 byte[] buffer = webclient.DownloadData("https://music.douban.com/tag/%E6%91%87%E6%BB%9A?start=0&type=T"); // utf-8, gb2312, gbk, utf-1...... string html = System.Text.Encoding.GetEncoding("utf-8").GetString(buffer); debug时可得到当前页对应的HTML字符串: 我们选用模式串 "<p class=\"pl\">([\\s\\S]*?)</p>" 进行匹配,可得到如下格式的内容: 刺猬 / 2018-01-08 / 单曲 / 数字(Digital) / 摇滚 ,
接着进行split可得到一个记录的各个属性。 具体的函数GetCurrentPageRecords 如下: private static void GetCurrentPageRecords(System.Net.WebClient webclient, int startIdx) { byte[] buffer = webclient.DownloadData("https://music.douban.com/tag/%E6%91%87%E6%BB%9A?start=" + startIdx + "&type=T"); // utf-8, gb2312, gbk, utf-1...... string html = System.Text.Encoding.GetEncoding("utf-8").GetString(buffer);
// Console.WriteLine(html);
// html分析 // 通过正则获取到需要的数据 // <p class="pl">刺猬 / 2018-01-08 / 单曲 / 数字(Digital) / 摇滚</p> MatchCollection musicItem_matches = new Regex("<p class=\"pl\">([\\s\\S]*?)</p>").Matches(html);
int count = musicItem_matches.Count;
for (int i = 0; i < count; i++) { string item = musicItem_matches[i].Result("$1"); string[] strArr = item.Trim().Split('/');
Record record = new Record { SongName = strArr[0], Date = strArr.ElementAtOrDefault(1), Album = strArr.ElementAtOrDefault(2), Type = strArr.ElementAtOrDefault(3), Topic = strArr.ElementAtOrDefault(4) };
_records.Add(record); } } 获取所有页的数据https://music.douban.com/tag/摇滚?start=0&type=T
第一页的start=0,每页20条,于是后面每一页的start是前一页start的值+20 写入csvRecord.cs using System; using System.Collections.Generic; using System.Text;
namespace CsSpider { public class Record { public string SongName { get; set; } public string Date { get; set; } public string Album { get; set; } public string Type { get; set; } public string Topic { get; set; } } }
// 举例: 万能青年旅店 / 2010-11-12 / 专辑 / CD / 摇滚 if (_records.Count > 0) { var writer = new StreamWriter(_filename);
using (var csv = new CsvWriter(writer)) { csv.WriteRecords(_records); Console.WriteLine("导出完成."); } } 解决乱码问题 只需要给上述writer 设置Encoding即可~ if (_records.Count > 0) { var writer = new StreamWriter(_filename, false, System.Text.Encoding.UTF8); // 设置Encoding,防止乱码
using (var csv = new CsvWriter(writer)) { csv.WriteRecords(_records); Console.WriteLine("导出完成."); } } 运行结果最后得到的CSV文件如下: 接下来,会发现一个问题: 如果多执行几次,前面的HTML字符串会变成下面这种内容: <script>var d=[navigator.platform,navigator.userAgent,navigator.vendor].join("|");window.location.href="https://sec.douban.com/a?c=3d001f&d="+d+"&r=https%3A%2F%2Fmovie.douban.com%2Fsubject%2F26590960%2F";</script> 说明此时,你触发了豆瓣的反作弊功能。如果再多执行几次,会出现 403 Error. 解决办法是模拟登录,这个留在下一篇文章再说,敬请关注! 完整代码已经放入github: CsSpider · yanglr/csharp_spider https://github.com/yanglr/csharp_spider/tree/master/spider-test/CsSpider 欢迎star、fork或拉取使用和研究!!!
|