Web Crawler 웹 크롤러
Web Crawling을 위해 자신이 직접 멀티쓰레드를 사용하여 웹 페이지들을 방문, 링크를 분석해 나가며
크롤링하는 코드를 작성할 수 있지만, 좀 더 간단하게는 Web Crawler 라이브러리를 사용할 수도 있다.
이번 아티클에서는 .NET용 Web Crawler의 하나인 Abot Web Crawler를 사용해 본다.
Abot Web Crawler
Abot은 오픈소스 웹 크롤러로서 C#에서 쉽게 웹 크롤링 기능을 사용할 수 있다.
Abot에 대한 코드와 설명은 Abot 깃허브를 참고한다.
(1) Abot 웹 크롤러를 사용하기 위해서는 먼저 VS 프로젝트에서 Abot Nuget 패키지를 설치한다.
PM> Install-Package Abot
(2) WebCrawler 객체 인스턴스를 생성한다. IWebCrawler 인터페이스를 구현하는 여러 웹 크롤러를 사용할 수 있는데,
아래 예제에서는 기본적인 PoliteWebCrawler 크롤러를 사용하였다.
(3) 웹 크롤러의 기본 옵션은 App.config에 지정하여야 한다. 아래 C# 코드 밑의 App.config 샘플처럼
configSections 섹션과 abot 섹션을 설정한다.
(주: Optional로 C# 코드에서 아래 예제처럼 옵션들을 지정할 수도 있는데,
이렇게 하면 App.config에 정의된 기본 옵션을 덮어쓰게 되고, WebCrawler 객체 인스턴스 생성시 옵션 객체를 전달하게 된다)
(4) Abot 웹 크롤러에는 여러 event를 제공하고 있는데, 일반적으로 웹 페이지 크롤링이 끝난 경우
호출되는 PageCrawlCompletedAsync 이벤트를 핸들링해 준다. 아래 예제에서는 크롤링이 시작할 때
호출되는 PageCrawlStartingAsync 이벤트도 핸들링해 주고 있다.
PageCrawlCompletedAsync 이벤트는 두번째 파라미터에서 PageCrawlCompletedArgs 아규먼트를 전달하는데,
PageCrawlCompletedArgs.CrawledPage 속성은 웹 크롤링된 웹페이지에 대한 정보를 가지고 있다.
CrawledPage.Content 속성은 실제 웹페이지 내용이고, CrawledPage.Content.Text은 HTML 문서를 문자열로 리턴하는 속성이다.
또한, 크롤링된 웹페이지의 URL 정보는 CrawledPage.Uri 속성에서 찾을 수 있다.
(5) 위와 같이 모든 설정이 셋업되었으면, 실제 크롤링을 위해 Crawl(url) 메서드를 호출한다.
이 메서드는 웹사이트 URL을 파라미터로 받아 해당 웹사이트에 대한 크롤링을 시작하고, 크롤링 결과를 위 (4)의 PageCrawlCompletedAsync
이벤트 핸들러에 전달한다.
아래 예제는 네이버 사이트에 대한 웹 크롤링을 해서,
using System;
using System.IO;
using Abot.Crawler;
using Abot.Poco;
namespace AbotCrawler
{
// Nuget: Install-Package Abot
class Program
{
static void Main(string[] args)
{
// 크롤러 인스턴스 생성
IWebCrawler crawler = new PoliteWebCrawler();
// 옵션과 함께 크롤러 인스턴스 생성할 경우
// var crawlConfig = new CrawlConfiguration();
// crawlConfig.CrawlTimeoutSeconds = 1000;
// crawlConfig.MaxConcurrentThreads = 10;
// crawlConfig.MaxPagesToCrawl = 10;
// crawlConfig.UserAgentString = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0";
// IWebCrawler crawler = new PoliteWebCrawler(crawlConfig);
// 이벤트 핸들러 셋업
crawler.PageCrawlStartingAsync += (s, e) =>
{
Console.WriteLine("Starting : {0}", e.PageToCrawl);
};
crawler.PageCrawlCompletedAsync += (s, e) =>
{
CrawledPage pg = e.CrawledPage;
string fn = pg.Uri.Segments[pg.Uri.Segments.Length - 1];
File.WriteAllText(fn, pg.Content.Text);
//var hdoc = pg.HtmlDocument; //HtmlAgilityPack HtmlDocument
Console.WriteLine("Completed : {0}", pg.Uri.AbsoluteUri);
};
// 크롤 시작
string siteUrl = "http://www.naver.com";
Uri uri = new Uri(siteUrl);
crawler.Crawl(uri);
}
}
}
/* App.config에 추가할 내용 */
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="abot" type="Abot.Core.AbotConfigurationSectionHandler, Abot"/>
</configSections>
<abot>
<crawlBehavior
maxConcurrentThreads="1"
maxPagesToCrawl="10"
maxPagesToCrawlPerDomain="0"
maxPageSizeInBytes="0"
userAgentString="Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
crawlTimeoutSeconds="0"
downloadableContentTypes="text/html, text/plain"
isUriRecrawlingEnabled="false"
isExternalPageCrawlingEnabled="false"
isExternalPageLinksCrawlingEnabled="false"
httpServicePointConnectionLimit="200"
httpRequestTimeoutInSeconds="15"
httpRequestMaxAutoRedirects="7"
isHttpRequestAutoRedirectsEnabled="true"
isHttpRequestAutomaticDecompressionEnabled="false"
isSendingCookiesEnabled="false"
isSslCertificateValidationEnabled="false"
isRespectUrlNamedAnchorOrHashbangEnabled="false"
minAvailableMemoryRequiredInMb="0"
maxMemoryUsageInMb="0"
maxMemoryUsageCacheTimeInSeconds="0"
maxCrawlDepth="100"
maxLinksPerPage="1000"
isForcedLinkParsingEnabled="false"
maxRetryCount="0"
minRetryDelayInMilliseconds="0"
/>
<authorization
isAlwaysLogin="false"
loginUser=""
loginPassword="" />
<politeness
isRespectRobotsDotTextEnabled="false"
isRespectMetaRobotsNoFollowEnabled="false"
isRespectAnchorRelNoFollowEnabled="false"
isIgnoreRobotsDotTextIfRootDisallowedEnabled="false"
robotsDotTextUserAgentString="abot"
maxRobotsDotTextCrawlDelayInSeconds="5"
minCrawlDelayPerDomainMilliSeconds="1000"/>
</abot>
</configuration>