Crawling 시작하기

Koo·2023년 8월 7일
post-thumbnail
  • crawling의 핵심은 재귀
  • crawling은 web page에서 url을 가져오고, page를 검사하여 다른 url을 찾는 과정을 무한히 반복
  • web crawler를 사용할 때는 대역폭에 주의를 기울여야 함
  • target server의 부하를 줄일 방법에 대해 생각해야 함

단일 도메인 내 이동

page 내에 있는 a tag의 href 속성을 모두 검색하여 출력

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen('http://en.wikipedia.org/wiki/Kevin_Bacon')
bsObj = BeautifulSoup(html, 'html.parser')

for link in bsObj.findAll('a'):
	if 'href' in link.attrs:
    print(link.attrs['href'])

이렇게 사용하면 관심 있어 하는 항목 이외의 페이지 링크가 무수히 많이 포함됨

link들은 id가 bodyContent인 div 안에 존재
URL에는 세미콜론이 포함되어 있지 않음
URL은 /wiki/로 시작됨

import re

html = urlopen('http://en.wikipedia.org/wiki/Kevin_Bacon')
bsObj = BeautifulSoup(html, 'html.parser')

for link in bsObj.find('div', {'id': 'bodyContent'}).findAll('a',
							href=re.compile('^(/wiki/)((?!:).)*$)):
	if 'href' in link.attrs:
    print(link.attrs['href'])

함수로 표현하면,

import random

def getLinks(articleUrl):
	html = urlopen('http://en.wikipedia.org' + articleUrl)
    bsObj = BeautifulSoup(html, 'html.parser')
    
    return bsObj.find('div', {'id': 'bodyContent'}).findAll('a',
    				href=re.compile('^(/wiki/)((?!:).)*$'))

links = getLinks('/wiki/Kevin_Bacon')
while len(links) > 0:
	newArticle = links[random.randint(0, len(links) - 1)].attrs['href']
    print(newArticle)
    links = getLinks(newArticle)
  • 프로그램은 wikipedia의 Kevin_Bacon page에서 시작하여 a tag들 중 랜덤하게 하나를 선택하여 재귀적으로 page를 순회
  • 순회만 하고 별도의 데이터를 저장하지 않기 때문에 데이터를 저장하는 과정이 필요
  • 이미 순회한 url은 탐색에서 제외해야하기 때문에 set을 이용해 중복을 제거
pages = set()

def getLinks(pageUrl):
	global pages

	html = urlopen('http://en.wikipedia.org' + articleUrl)
    bsObj = BeautifulSoup(html, 'html.parser')
    for link in bsObj.findAll('a', href=re.compile('^(/wiki/)')):
    	if 'href' in link.attrs:
        	if link.attrs['href'] not in pages:
            	newPage = link.attrs['href']
                print(newPage)
                pages.add(newPage)
                getLinks(newPage)

getLinks('/wiki/Kevin_Bacon')

python에서는 재귀적으로 함수호출을 최대 1,000회까지 할 수 있다

from sys import setrecursionlimit
setrecursionlimit(10**8)

setrecursionlimit을 이용하면 재귀호출의 제한값을 늘릴 수 있다

전체 사이트에서 데이터 수집

  • 단순히 순회하는 것이 아닌 tag의 내용을 수집
  • "페이지 제목, 첫번째 문단"을 수집하는 scraper
    1. 제목은 항상 <h1> tag 안에 존재
    2. body 텍스트는 div#bodyContent tag 안에 존재
pages = set()

def getLinks(pageUrl):
	global pages
    html = urlopen('http://en.wikipedia.org' + pageUrl)
    bsObj = BeautifulSoup(html, 'html.parser')
    try:
    	print(bsObj.h1.get_text())
        print(bsObj.find(id='mw-content-text').findAll('p')[0]
    except AttributeError:
    	print('This page is missing something!')
    for link in bsObj.findAll('a', href=re.compile('^(/wiki/)')):
    	if 'href' in link.attrs:
        	if link.attrs['href'] not in pages:
            	newPage = link.attrs['href']
                print('-' * 30 + '\n' + newPage)
                pages.add(newPage)
                getLinks(newPage)

getLinks('')

예외 handler에는 여러 행을 넣는 것은 위험.
1. 어떤 행에서 예외가 발생했는지 알 수 없다
2. 하나의 line에서 예외가 발생하면 뒤에 모든 line들도 실행되지 않게된다

Internet Crawling

외부링크를 이용하는 crawler를 만들기 전에는 다음에 대해 점검해야 한다

  • 수집하려는 데이터가 어떤 것인지
    • 정해진 사이트만 수집해야하는지? 모든 사이트를 방문해야 하는지
  • crawler가 특정 web site에 도달하면 바로 새 web site로 이동할 것인지 현재 web site에서 파고들 것인지
  • 특정 site를 scrap에서 제외시킬 것인지
    • 비 영어권 콘텐츠도 수집이 필요할지
  • ...

Crawling Program 작성 시 주의사항

  • 실제 코드를 작성하기 전 그 코드가 무슨 일을 하는지 다이어그램을 그려보거나 메모
  • 점검 내용과 예외처리에 대해 고려
  • 함수를 작성할 때, 해당 페이지에서 어떠한 동작을 하는 함수를 만들면 리팩토링하기에 유리
profile
스터디를 해보자

0개의 댓글