| |
|
난이도 : 중급 M. Tim Jones, Consultant Engineer, Emulex
2007 년 4 월 17 일 웹 스파이더(Web spider)는 인터넷을 크롤링 하며 정보를 수집하고, 필터링 하며, 사용자를 위한 정보를 한데 모으는 소프트웨어 에이전트입니다. 일반 스크립팅 언어와 웹 모듈을 사용하면 웹 스파이더를 쉽게 구현할 수 있습니다. 이 글에서는 리눅스�용 스파이더와 스크래퍼를 구현하여 웹 사이트를 크롤링 하며 정보를 모으는 방법을 설명합니다. 스파이더(spider)는 특정 목적을 위해 특정한 방법으로 인터넷을 크롤링(crawl) 하는 프로그램이다. 이 프로그램의 목적은 정보를 수집하거나 웹 사이트의 구조와 유효성을 파악하는 것이다. 스파이더는 Google과 AltaVista 같은 현대적인 검색 엔진의 기초가 된다. 이러한 스파이더들은 웹에서 자동으로 데이터를 검색하여, 검색어에 가장 잘 맞는 웹 사이트의 내용을 인덱싱 하는 다른 애플리케이션에 전달한다. | 에이전트로서의 웹 스파이더
웹 스파이더와 스크래퍼는 소프트웨어 로봇 또는 에이전트(1980년대 초, Alan Kay에 의해 만들어진 단어)의 또 다른 형태이다. Alan이 만든 에이전트라는 개념은 컴퓨터 세계에서의 사용자용 프록시였다. 이 에이전트에는 목표와, 그 목표에 대한 작업이 주어질 수 있었다. 이것이 어떤 한계에 도달하면 사용자에게서 어드바이스를 요청할 수 있고 계속적으로 그 목표를 수행할 수 있었다. 오늘날 에이전트는 자율성(autonomy), 적응성(adaptiveness), 통신, 다른 에이전트와의 협업(collaboration) 같은 애트리뷰트들로 구분된다. 에이전트 이동성(mobility)과 개성(personality) 같은 기타 애트리뷰트들은 오늘날 에이전트 연구의 목표이다. 이 글에서 설명하는 웹 스파이더는 에이전트 분류법에서 Task-Specific Agents로 분류된다. |
|
스파이더와 비슷한 것으로 웹 스크래퍼(Web scraper)가 있다. 스크래퍼는 스파이더의 한 유형으로서, 웹에서 제품이나 서비스 비용 같은 특수한 내용이 스크래핑 대상이 된다. 한 가지 사용 예제로는 가격 비교가 있는데, 해당 제품의 가격을 파악하여 본인 제품의 가격을 조정하고, 이에 따라 광고를 하는 것이다. 스크래퍼는 많은 웹 소스들에서 데이터를 모으고 그 정보를 사용자에게 제공한다. 생물학적인 동기 스파이더의 본질을 생각할 때, 고립성이 아닌 환경과의 인터랙션에 맞추어 이를 생각하게 된다. 스파이더는 자신의 길을 보고 감지하며, 한 장소에서 또 다른 장소로 의미 있는 방식으로 이동한다. 웹 스파이더도 비슷한 방식으로 작동한다. 웹 스파이더는 고급 언어로 작성된 프로그램이며, Hypertext Transfer Protocol (HTTP) 같은 네트워킹 프로토콜을 사용하여 환경과 인터랙팅 한다. 스파이더가 여러분과 통신하기 원한다면, Simple Mail Transfer Protocol (SMTP)을 사용하여 이메일 메시지를 보낼 수 있다. 스파이더는 HTTP 또는 SMTP 로 국한되지 않는다. 일부 스파이더는 SOAP 또는 Extensible Markup Language Remote Procedure Call (XML-RPC) 프로토콜 같은 웹 서비스를 사용한다. 다른 스파이더는 Network News Transfer Protocol (NNTP)을 통해 뉴스 그룹과 소통하거나, Really Simple Syndication (RSS) 피드로 흥미로운 뉴스 아이템들을 찾는다. 대부분의 스파이더는 본질적으로 명암 강도(light-dark intensity)와 움직임의 변화만 볼 수 있지만, 웹 스파이더들은 많은 유형의 프로토콜들을 사용하여 보고 감지할 수 있다.
스파이더와 스크래퍼의 애플리케이션 | 스파이더의 눈과 다리
웹 스파이더가 인터넷을 보고 움직이는 주요 수단은 HTTP이며, HTTP는 메시지 중심 프로토콜로서, 이곳에서 클라이언트는 서버와 연결되어 해당 요청을 수행하며, 서버는 응답을 제공한다. 각각의 요청과 응답은 헤더와 바디로 구성되고, 헤더는 상태 정보와 바디의 내용에 대한 디스크립션을 제공한다. HTTP는 세 가지 기본적인 유형의 요청을 제공한다. 첫 번째가 HEAD 인데, 이것은 서버에 있는 자산에 대한 정보를 요청한다. 두 번째는 GET 으로서 파일 또는 이미지 같은 자산을 요청한다. 마지막으로, POST 요청은 클라이언트가 웹 페이지를 통해(일반적으로 웹 폼을 통해) 서버와 인터랙팅 할 수 있다. |
|
웹 스파이더와 스크래퍼는 유용한 애플리케이션이고, 따라서 좋든 나쁘든, 여러 가지 다양한 유형의 사용법이 있다. 이러한 기술을 사용하는 몇 가지 애플리케이션에 대해 살펴보도록 하자. 검색 엔진 웹 크롤러(crawler) 웹 스파이더는 인터넷 검색을 쉽고 효율적으로 만든다. 검색 엔진은 많은 웹 스파이더들을 사용하여 인터넷 상의 웹 페이지들을 크롤링 하고, 콘텐트를 리턴하며, 이를 인덱싱 한다. 이것이 완료되면, 검색 엔진은 로컬 인덱스를 빠르게 검색하여 검색에 맞는 가장 합당한 결과를 찾는다. Google은 PageRank 알고리즘을 사용하는데, 검색 결과의 웹 페이지 랭크(rank)는 얼마나 많은 페이지들이 여기에 링크되어 있는지를 나타내는 것이다. 이것은 투표(vote)로서도 작동하는데, 높은 투표를 가진 페이지들은 가장 높은 랭크를 얻는다. 이와 같이 인터넷을 검색하는 것은 웹 콘텐트와 인덱서를 통신하는데 있어서 대역폭과 결과를 인덱싱 하는 전산 비용 관점에서 볼 때 비용이 많이 든다. 많은 스토리지가 이와 같은 것을 필요로 하지만, Google이 Gmail 사용자들에게 1,000 메가바이트의 스토리지를 제공한다고 생각한다면 이것은 문제도 아니다. 웹 스파이더는 일련의 정책을 사용하여 인터넷 상의 흐름을 최소화 한다. Google은 80억 개 이상의 웹 페이지들을 인덱싱 한다. 실행 정책은 크롤러가 인덱서로 어떤 페이지들을 가져오는지, 웹 사이트로 가서 이를 다시 체크하는 빈도수는 어느 정도인지에 대한 politeness 정책을 정의한다. 웹 서버는 robot.txt라고 하는 파일을 사용하여 크롤러를 차단할 수 있다. 기업용 웹 크롤러 표준 검색 엔진 스파이더와 마찬가지로, 기업용 웹 스파이더는 일반인이 사용할 수 없는 콘텐트를 인덱싱 한다. 예를 들어, 기업들은 사원들이 사용하는 내부 웹 사이트를 갖고 있다. 이러한 유형의 스파이더는 로컬 환경으로 제한된다. 검색이 제한되기 때문에 더 많은 전산 파워가 사용되며, 전문화 되고 보다 완벽한 인덱스가 가능하다. Google은 한 단계 더 나아가서 데스크탑 검색 엔진을 제공하여 여러분 개인용 컴퓨터의 콘텐트를 인덱싱 한다. 전문화된 크롤러 콘텐트를 압축하거나 통계를 만들어 내는 등, 특수한 크롤러도 있다. 압축 크롤러는 웹 사이트를 크롤링 하면서, 콘텐트를 로컬로 가져와서 장기적인 저장 미디어에 저장되도록 한다. 이것은 백업용으로 사용될 수 있고, 더 크게는 인터넷 콘텐트의 스냅샷을 만들기도 한다. 통계는 인터넷 콘텐트와 무엇이 부족한지를 이해하는데 도움이 된다. 크롤러는 얼마나 많은 웹 서버들이 실행되는지, 특정 유형의 웹 서버들이 얼마나 많은지, 사용할 수 있는 웹 페이지 수, 깨진 링크의 수(HTTP 404 error, page not found 등을 리턴함) 등을 규명하는데 사용된다. 기타 전문적인 크롤러에는 웹 사이트 체커(checker)도 있다. 이 크롤러는 소실된 콘텐트를 찾고, 모든 링크들을 검사하며, 여러분의 Hypertext Markup Language (HTML)이 유효한지를 확인한다. 이메일을 모으는 크롤러 이제 어두운 쪽으로 가보도록 하자. 불행하게도, 일부 썩은 사과들이 인터넷을 망치고 있다. 이메일을 모으는 크롤러들은 이메일 주소가 있는 웹 사이트를 검색하여 대량의 스팸을 생성하는데 사용한다. 포스티니(Postini) 보고서(2005년 8월)에 따르면, 포스티니(Postini) 사용자들의 모든 이메일 메시지들의 70%가 스팸 이라고 한다. 이메일 모으기는 가장 흔한 크롤러 동작 메커니즘 중 하나이다. 이 글에서는 이 마지막 크롤러 예제를 설명한다. 지금까지, 웹 스파이더와 스크래퍼를 설명했다. 다음 네 가지 예제들은 Ruby와 Python 같은 현대적인 스크립팅 언어를 사용하여 리눅스용 스파이더와 스크래퍼를 구현하는 방법을 설명하겠다.
예제 1: 일반 스크래퍼 이 예제를 통해 주어진 웹 사이트에 대해 어떤 종류의 웹 서버가 실행되는지를 규명하는 방법을 설명하겠다. 이것은 매우 재미있고, 정부, 학계, 업계에서 어떤 종류의 웹 서버를 사용하는지도 알 수 있다. Listing 1은 HTTP 서버를 규명하기 위해 웹 사이트를 스크래핑 하는 Ruby 스크립트이다. Net::HTTP 클래스는 HTTP 클라이언트와 GET , HEAD , POST HTTP 메소드를 실행한다. HTTP 서버에 요청을 보낼 때 마다, HTTP 메시지 응답의 일부에서는 콘텐트가 제공되는 서버를 나타낸다. 그 사이트에서 페이지를 다운로드 하기 보다는, HEAD 메소드를 사용하여 루트 페이지('/')에 대한 정보를 얻는다. HTTP 서버가 성공적인 응답을 보내는 한("200" 응답 코드로 나타남), 응답의 각 라인을 반복하면서 server 키를 검색하고, 이것을 찾으면 값을 프린트 한다. 이 키의 값은 HTTP 서버를 나타내는 스트링이다. Listing 1. 간단한 메타데이터 스크래핑을 위한 Ruby 스크립트(srvinfo.rb)
#!/usr/local/bin/rubyrequire 'net/http'# Get the first argument from the command-line (the URL)url = ARGV[0]begin # Create a new HTTP connection httpCon = Net::HTTP.new( url, 80 ) # Perform a HEAD request resp, data = httpCon.head( "/", nil ) # If it succeeded (200 is success) if resp.code == "200" then # Iterate through the response hash resp.each {|key,val| # If the key is the server, print the value if key == "server" then print " The server at "+url+" is "+val+"\n" end } endend |
srvinfo 스크립트를 사용하는 방법을 설명하는 것 외에도, Listing 2는 많은 정부, 학계, 비즈니스 웹 사이트에서 가져온 결과들도 보여준다. Apache (68%)부터 Sun과 Microsoft� Internet Information Services (IIS)까지 다양하다. 서버가 리포팅 되지 않은 경우도 있다. 미크로네시아(Federated States of Micronesi)는 구 버전의 Apache를 실행하고 있고(이제 업데이트가 필요하다.), Apache.org는 첨단을 달리고 있다는 사실이 흥미롭다. Listing 2. 서버 스크래퍼의 사용 예제
[mtj@camus]$ ./srvrinfo.rb www.whitehouse.gov The server at www.whitehouse.gov is Apache[mtj@camus]$ ./srvrinfo.rb www.cisco.com The server at www.cisco.com is Apache/2.0 (Unix)[mtj@camus]$ ./srvrinfo.rb www.gov.ru The server at www.gov.ru is Apache/1.3.29 (Unix)[mtj@camus]$ ./srvrinfo.rb www.gov.cn[mtj@camus]$ ./srvrinfo.rb www.kantei.go.jp The server at www.kantei.go.jp is Apache[mtj@camus]$ ./srvrinfo.rb www.pmo.gov.to The server at www.pmo.gov.to is Apache/2.0.46 (Red Hat Linux)[mtj@camus]$ ./srvrinfo.rb www.mozambique.mz The server at www.mozambique.mz is Apache/1.3.27 (Unix) PHP/3.0.18 PHP/4.2.3[mtj@camus]$ ./srvrinfo.rb www.cisco.com The server at www.cisco.com is Apache/1.0 (Unix)[mtj@camus]$ ./srvrinfo.rb www.mit.edu The server at www.mit.edu is MIT Web Server Apache/1.3.26 Mark/1.5 (Unix) mod_ssl/2.8.9 OpenSSL/0.9.7c[mtj@camus]$ ./srvrinfo.rb www.stanford.edu The server at www.stanford.edu is Apache/2.0.54 (Debian GNU/Linux) mod_fastcgi/2.4.2 mod_ssl/2.0.54 OpenSSL/0.9.7e WebAuth/3.2.8[mtj@camus]$ ./srvrinfo.rb www.fsmgov.org The server at www.fsmgov.org is Apache/1.3.27 (Unix) PHP/4.3.1[mtj@camus]$ ./srvrinfo.rb www.csuchico.edu The server at www.csuchico.edu is Sun-ONE-Web-Server/6.1[mtj@camus]$ ./srvrinfo.rb www.sun.com The server at www.sun.com is Sun Java System Web Server 6.1[mtj@camus]$ ./srvrinfo.rb www.microsoft.com The server at www.microsoft.com is Microsoft-IIS/6.0[mtj@camus]$ ./srvrinfo.rb www.apache.orgThe server at www.apache.org is Apache/2.2.3 (Unix) mod_ssl/2.2.3 OpenSSL/0.9.7g |
이것은 유용한 데이터이고, 정부와 학교들이 자신들의 웹 서버로 무엇을 사용하는지를 알 수 있어서 재미있다. 다음 예제에서는 보다 덜 유용한 주식 시세 스크래퍼를 설명하겠다.
예제 2: 주식 시세 스크래퍼 이 예제에서는, 간단한 웹 스크래퍼(스크린 스크래퍼(screen scraper))를 구현하여 주식 시세 정보를 모으도록 하겠다. 다음과 같이 응답 웹 페이지에 한 패턴을 활용하는 방식을 사용할 것이다. Listing 3. 주식 시세용 웹 스크래퍼
#!/usr/local/bin/rubyrequire 'net/http'host = "www.smartmoney.com"link = "/eqsnaps/index.cfm?story=snapshot&symbol="+ARGV[0]begin # Create a new HTTP connection httpCon = Net::HTTP.new( host, 80 ) # Perform a HEAD request resp = httpCon.get( link, nil ) stroffset = resp.body =~ /class="price">/ subset = resp.body.slice(stroffset+14, 10) limit = subset.index('<') print ARGV[0] + " current stock price " + subset[0..limit-1] + " (from stockmoney.com)\n"end |
이 Ruby 스크립트에서, HTTP 클라이언트를 서버로 연결하고(이 경우, www.smartmoney.com), (&symbol=<symbol> 을 통해) 사용자에 의해 전달된 것처럼 주식 시세를 요청하는 링크를 구현한다. 나는 HTTP GET 메소드를 사용하여 이 링크를 요청하고(전체 응답 페이지를 가져오기 위해서), class="price"> 를 검색하고 바로 뒤에 주식의 현재 시세가 바로 나타난다. 이것은 웹 페이지에서 재단되어 사용자에게 디스플레이 된다. 주식 시세 스크래퍼를 사용하기 위해, 관심 있는 주식 심볼을 가진 스크립트를 호출한다. (Listing 4) Listing 4. 주식 시세 스크래퍼의 사용 예제
[mtj@camus]$ ./stockprice.rb ibmibm current stock price 79.28 (from stockmoney.com)[mtj@camus]$ ./stockprice.rb intlintl current stock price 21.69 (from stockmoney.com)[mtj@camus]$ ./stockprice.rb ntnt current stock price 2.07 (from stockmoney.com)[mtj@camus]$ |
예제 3: 주식 시세 스크래퍼와 통신하기 예제 2의 주식 시세용 웹 스크래퍼는 매력적이지만, 이 스크래퍼가 주식 시세를 늘 모니터링 하고, 관심 있는 주식이 오르거나 하락할 때 여러분에게 알려주도록 한다면 더욱 유용할 것이다. 기다림을 끝났다. Listing 5에서, 웹 스크래퍼를 업데이트 하여 주식을 지속적으로 모니터링 하고 주가 변동이 있을 때 이메일 메시지를 보내도록 하였다. Listing 5. 이메일 알림을 보낼 수 있는 주식 스크래퍼
#!/usr/local/bin/rubyrequire 'net/http'require 'net/smtp'## Given a web-site and link, return the stock price#def getStockQuote(host, link) # Create a new HTTP connection httpCon = Net::HTTP.new( host, 80 ) # Perform a HEAD request resp = httpCon.get( link, nil ) stroffset = resp.body =~ /class="price">/ subset = resp.body.slice(stroffset+14, 10) limit = subset.index('<') return subset[0..limit-1].to_fend## Send a message (msg) to a user.# Note: assumes the SMTP server is on the same host.#def sendStockAlert( user, msg ) lmsg = [ "Subject: Stock Alert\n", "\n", msg ] Net::SMTP.start('localhost') do |smtp| smtp.sendmail( lmsg, "rubystockmonitor@localhost.localdomain", [user] ) endend## Our main program, checks the stock within the price band every two# minutes, emails and exits if the stock price strays from the band.## Usage: ./monitor_sp.rb <symbol> <high> <low> <email_address>#begin host = "www.smartmoney.com" link = "/eqsnaps/index.cfm?story=snapshot&symbol="+ARGV[0] user = ARGV[3] high = ARGV[1].to_f low = ARGV[2].to_f while 1 price = getStockQuote(host, link) print "current price ", price, "\n" if (price > high) || (price < low) then if (price > high) then msg = "Stock "+ARGV[0]+" has exceeded the price of "+high.to_s+ "\n"+host+link+"\n" end if (price < low) then msg = "Stock "+ARGV[0]+" has fallen below the price of "+low.to_s+ "\n"+host+link+"\n" end sendStockAlert( user, msg ) exit end sleep 120 endend |
Ruby 스크립트는 다소 길지만, Listing 3의 주식 스크래핑 스크립트를 기반으로 구현한 것이다. 새로운 함수 getStockQuote 는 주식 스크래핑 함수를 캡슐화 한다. 또 다른 함수인 sendStockAlert 는 메시지를 이메일 주소로 보낸다. (두 개 모두 사용자가 정의한 것이다.) 주 프로그램은 그저 반복적으로 주식 시세를 확인하고, 변동이 있는지를 체크하고, 사용자에게 이메일 알림을 보내는 것이다. 서버에 부담을 주고 싶지 않았기 때문에 주식 시세를 체크하는 사이에 딜레이를 적용했다. Listing 6은 주식 시세 모니터링 실행 예제이다. 2분 마다 주식이 체크되고 프린트 된다. 주가가 상한선을 넘으면, 이메일 알림이 보내지고 스크립트가 종료한다. Listing 6. 주식 모니터 스크립트 데모
[mtj@camus]$ ./monitor_sp.rb ibm 83.00 75.00 mtj@mtjones.comcurrent price 82.06current price 82.32current price 82.75current price 83.36 |
결과 이메일은 그림 1과 같다. 스크립팅 된 데이터의 소스에 링크가 걸려있다. 그림1. Listing 5의 Ruby 스크립트에서 보낸 이메일 알림
이제 스크래퍼를 떠나서 웹 스파이더의 구조에 대해 살펴보도록 하자.
예제 4: 웹 사이트 크롤러 마지막 예제에서는 웹 사이트를 크롤링 하는 웹 스파이더에 대해 설명하도록 하겠다. 보안을 위해 사이트 밖에 머무르지 않고, 대신 하나의 웹 페이지만 탐구하도록 하겠다. 웹 사이트를 크롤링 하고, 이 안에서 제공되는 링크를 따라가려면, HTML 페이지를 파싱해야 한다. 웹 페이지를 성공적으로 파싱할 수 있다면 다른 리소스에 대한 링크를 구분할 수 있다. 어떤 것은 로컬 리소스(파일)을 지정하고, 다른 것은 비 로컬 리소스(다른 웹 페이지에 대한 링크)를 나타낸다. 웹을 크롤링 하려면, 주어진 웹 페이지로 시작하여, 그 페이지에 있는 모든 링크를 파악하고, 이들을 to-visit 큐에 대기시킨 다음, to-visit 큐에서 첫 번째 아이템을 사용하여 이 프로세스를 반복한다. 이것은 breadth-first traversal(너비 우선 순회)이다. (발견된 첫 번째 링크를 통해 나아가는 것과는 대조적이다. 이것은 depth-first behavior(깊이 우선 순회)라고 한다.) 비 로컬(non-local) 링크를 피하고 로컬 웹 페이지로만 탐색한다면 웹 크롤러에게 하나의 웹 사이트를 제공한다. (Listing 7) 이 경우, 나는 Ruby에서 Python으로 전환하여 Python의 유용한 HTMLParser 클래스를 활용한다. Listing 7. Python 웹 사이트 크롤러 (minispider.py)
#!/usr/local/bin/pythonimport httplibimport sysimport refrom HTMLParser import HTMLParserclass miniHTMLParser( HTMLParser ): viewedQueue = [] instQueue = [] def get_next_link( self ): if self.instQueue == []: return '' else: return self.instQueue.pop(0) def gethtmlfile( self, site, page ): try: httpconn = httplib.HTTPConnection(site) httpconn.request("GET", page) resp = httpconn.getresponse() resppage = resp.read() except: resppage = "" return resppage def handle_starttag( self, tag, attrs ): if tag == 'a': newstr = str(attrs[0][1]) if re.search('http', newstr) == None: if re.search('mailto', newstr) == None: if re.search('htm', newstr) != None: if (newstr in self.viewedQueue) == False: print " adding", newstr self.instQueue.append( newstr ) self.viewedQueue.append( newstr ) else: print " ignoring", newstr else: print " ignoring", newstr else: print " ignoring", newstrdef main(): if sys.argv[1] == '': print "usage is ./minispider.py site link" sys.exit(2) mySpider = miniHTMLParser() link = sys.argv[2] while link != '': print "\nChecking link ", link # Get the file from the site and link retfile = mySpider.gethtmlfile( sys.argv[1], link ) # Feed the file into the HTML parser mySpider.feed(retfile) # Search the retfile here # Get the next link in level traversal order link = mySpider.get_next_link() mySpider.close() print "\ndone\n"if __name__ == "__main__": main() |
이 크롤러의 기본 디자인은 첫 번째 링크를 로딩하여 큐를 검사하는 것이다. 이 큐는 next-to-interrogate 큐로서 작동한다. 링크가 체크되면, 발견된 새로운 링크들이 같은 큐에 로딩된다. 먼저, Python의 HTMLParser 클래스에서 miniHTMLParser 라고 하는 새로운 클래스를 이끌어 낸다. 이 클래스는 몇 가지 일을 수행한다. 먼저, 시작 HTML 태그를 만날 때 마다 콜백 메소드(handle_starttag )를 사용하는 나의 HTML 파서이다. 나는 또한 이 클래스를 사용하여 크롤링에서 발견된 (get_next_link ) 링크에 액세스 하고 이 링크에서 나타난 파일(이 경우, HTML 파일)을 가져온다. 두 개의 인스턴스 변수들이 이 클래스 안에 포함되는데, viewedQueue 에는 지금까지 조사된 링크가 포함되어 있고, instQueue 는 조사 될 링크들을 나타내고 있다. 여러분도 보듯, 클래스 메소드는 단순하다. get_next_link 메소드는 instQueue 가 비어있는지 여부를 확인하고 리턴한다. 그렇지 않으면, 다음 아이템이 pop 메소드를 통해 리턴된다. gethtmlfile 메소드는 HTTPConnectionK 를 사용하여 사이트로 연결하고 정해진 페이지의 내용을 리턴한다. 마지막으로 handle_starttag 는 웹 페이지의 모든 시작 태그에 호출된다. (feed 메소드를 통해 HTML 파서로 피딩(feed) 된다.) 이 함수에서, 링크가 비 로컬 링크(http를 포함하고 있을 경우)인지 여부, 이것이 이메일 주소인지 여부(mailto), 링크에 이것이 웹 페이지라는 것을 나타내는 'htm'이 포함되었는지의 여부를 검사한다. 또한, 전에 한번도 방문한 적 없는 곳인지를 확인하고, 그렇지 않을 경우, 링크는 my interrogate에 로딩되고 큐에 나타난다. main 메소드는 단순하다. 나는 새로운 miniHTMLParser 인스턴스를 만들고 사용자 정의 사이트(argv[1] )와 링크(argv[2] )로 시작한다. 링크의 콘텐트를 가져다가, 이것을 HTML 파서에 피딩하고, 다음에 방문할 링크가 있다면 그 다음 링크를 가져온다. 방문할 링크가 있는 한 루프는 계속된다.
웹 스파이더를 호출하려면, 웹 사이트 주소와 링크를 제공한다. ./minispider.py www.fsf.org /
이 경우, Free Software Foundation(자유 소프트웨어 재단)에서 루트 파일을 요청하고 있다. 이 명령어의 결과는 Listing 8과 같다. 요청 큐에 추가된 새로운 링크와 비 로컬 링크 같은 무시된 링크를 볼 수 있다. 리스팅 밑에, 루트에서 발견된 그 링크에 대한 질의를 볼 수 있다. Listing 8. minispider 스크립트의 결과
[mtj@camus]$ ./minispider.py www.fsf.org /Checking link / ignoring hiddenStructure ignoring http://www.fsf.org ignoring http://www.fsf.org ignoring http://www.fsf.org/news ignoring http://www.fsf.org/events ignoring http://www.fsf.org/campaigns ignoring http://www.fsf.org/resources ignoring http://www.fsf.org/donate ignoring http://www.fsf.org/associate ignoring http://www.fsf.org/licensing ignoring http://www.fsf.org/blogs ignoring http://www.fsf.org/about ignoring https://www.fsf.org/login_form ignoring http://www.fsf.org/join_form ignoring http://www.fsf.org/news/fs-award-2005.html ignoring http://www.fsf.org/news/fsfsysadmin.html ignoring http://www.fsf.org/news/digital-communities.html ignoring http://www.fsf.org/news/patents-defeated.html ignoring /news/RSS ignoring http://www.fsf.org/news ignoring http://www.fsf.org/blogs/rms/entry-20050802.html ignoring http://www.fsf.org/blogs/rms/entry-20050712.html ignoring http://www.fsf.org/blogs/rms/entry-20050601.html ignoring http://www.fsf.org/blogs/rms/entry-20050526.html ignoring http://www.fsf.org/blogs/rms/entry-20050513.html ignoring http://www.fsf.org/index_html/SimpleBlogFullSearch ignoring documentContent ignoring http://www.fsf.org/index_html/sendto_form ignoring javascript:this.print(); adding licensing/essays/free-sw.html ignoring /licensing/essays ignoring http://www.gnu.org/philosophy ignoring http://www.freesoftwaremagazine.com ignoring donate ignoring join_form adding associate/index_html ignoring http://order.fsf.org adding donate/patron/index_html adding campaigns/priority.html ignoring http://r300.sf.net/ ignoring http://developer.classpath.org/mediation/OpenOffice2GCJ4 ignoring http://gcc.gnu.org/java/index.html ignoring http://www.gnu.org/software/classpath/ ignoring http://gplflash.sourceforge.net/ ignoring campaigns adding campaigns/broadcast-flag.html ignoring http://www.gnu.org ignoring /fsf/licensing ignoring http://directory.fsf.org ignoring http://savannah.gnu.org ignoring mailto:webmaster@fsf.org ignoring http://www.fsf.org/Members/root ignoring http://www.plonesolutions.com ignoring http://www.enfoldtechnology.com ignoring http://blacktar.com ignoring http://plone.org ignoring http://www.section508.gov ignoring http://www.w3.org/WAI/WCAG1AA-Conformance ignoring http://validator.w3.org/check/referer ignoring http://jigsaw.w3.org/css-validator/check/referer ignoring http://plone.org/browsersupportChecking link licensing/essays/free-sw.html ignoring mailto:webmasterChecking link associate/index_html ignoring mailto:webmasterChecking link donate/patron/index_html ignoring mailto:webmasterChecking link campaigns/priority.html ignoring mailto:webmasterChecking link campaigns/broadcast-flag.html ignoring mailto:webmasterdone[mtj@camus]$ |
이 예제는 웹 스파이더의 크롤링 단계를 나타내고 있다. 이 파일이 클라이언트에 의해 읽혀진 후에, 페이지의 콘텐트가 검사된다.
리눅스 스라이더링(spidering) 툴 두 개의 스크래퍼와 스파이더를 구현하는 방법을 배웠다. 이러한 기능을 제공하는 리눅스 툴도 있다. Web get을 뜻하는 wget 명령어는 웹 사이트를 반복적으로 실행하고 관심 내용을 가져오는 유용한 명령어이다. 웹 사이트, 관심이 있는 내용, 기타 관리 옵션들을 지정할 수 있다. 이 명령어는 파일들을 여러분의 로컬 호스트로 가져온다. 예를 들어, 다음 명령어는 여러분이 정의한 URL로 연결하여 세 단계만 반복하여 mp3, mpg, mpeg, 또는 avi 확장자를 가진 파일을 가져온다. wget -A mp3,mpg,mpeg,avi -r -l 3 http://<some URL>
curl 명령어도 비슷한 방법으로 작동한다. 계속해서 많은 것들이 활발히 개발되고 있다. 이와 비슷한 다른 명령어로는 snarf , fget , fetch 등이 있다.
법적 문제 웹 스파이더를 사용하는 인터넷에서의 데이터 마이닝에 대한 소송들이 있었고, 잘 처리되지 않고 있다. Farechase, Inc.는 최근 American Airlines로부터 스크린 스크래핑과 관련하여 고소를 당했다. 이 소송은 American Airlines의 사용자 계약에 위반되는 데이터를 모았다는 점이 소송에 걸렸다. 소송이 실패하자, American Airlines는 불법 침해를 주장했고 이것은 성공을 거두었다. 다른 소송 건으로는 스파이더와 스크래퍼가 합법적 사용자의 대역폭을 가져가는 것과 관련한 것이었다. 모두가 근거 있는 소송들이고 Politeness 정책들을 수립하는 것이 더욱 중요해지고 있다. (참고자료)
맺음말 웹의 크롤링과 스크래핑은 재미도 있고 이롭기도 하다. 하지만, 앞서 언급한 것처럼, 법적인 문제도 있다. 스파이더링이나 스크래핑을 할 때, 서버에서 사용할 수 있는 robots.txt 파일을 준수하고, 이것을 여러분의 Politeness 정책들에 추가하도록 한다. SOAP 같은 새로운 프로토콜들은 스파이더링을 더욱 쉽게 만들고, 일반 웹 작동에는 영향을 덜 준다. 시맨틱 웹 같은 노력이 스파이더링을 더욱더 단순화 하기 때문에 스파이더링의 솔루션과 방식은 계속해서 성장할 전망이다. 기사의 원문보기
참고자료 교육
제품 및 기술 얻기
토론
필자소개 | | | M. Tim Jones는 임베디드 소프트웨어 아키텍트이며, GNU/Linux Application Programming, AI Application Programming, BSD Sockets Programming from a Multilanguage Perspective의 저자이기도 하다. 정지 우주선용 커널부터 임베디드 시스템 아키텍처와 네트워킹 프로토콜 개발까지 광범위한 개발 경험을 갖고 있다. 현재 Emulex Corp. (Longmont, Colorado)의 자문 엔지니어이다. |
|