[Web] 재귀적으로 url 크롤링하기

업데이트:

개요

png

  • 예제 url
  • https://en.wikipedia.org/wiki/Kevin_Bacon


1. 기본 크롤링

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

#html = urlopen('https://en.wikipedia.org/wiki/Eric_Idle')
html = urlopen('https://en.wikipedia.org/wiki/Kevin_Bacon')
bs = BeautifulSoup(html, 'html.parser')
# 파싱
for link in bs.find('div',{'id':'bodyContent'}).findAll('a', href=re.compile("^(/wiki/)((?!:).)*$")):
    if 'href' in link.attrs:  # html이 가진 속성을 dict 형태로 반환
        print(link.attrs['href'])
/wiki/Kevin_Bacon_(disambiguation)
/wiki/Philadelphia
/wiki/Pennsylvania
/wiki/Kyra_Sedgwick
/wiki/Sosie_Bacon

생략..
  • ^(/wiki/) : /wiki/로 시작하는 것
  • (?!:) : : 와 일치하지 않는 것만
  • (.)*$ : .이 0회이상 반복되며 괄호()안의 표현으로 끝나야함

위 코드(정규식, find, findAll, .attrs 활용)를 이용해서 해당 페이지에서 다른 항목을 가리키는 모든 링크를 얻을 수 있다.


2. 함수를 이용한 재귀적 호출

이걸 바탕으로 사용자 정의함수를 만들어보자.

  1. 초기 페이지의 모든 항목 url을 긁어온다.
  2. 랜덤으로 1개의 url을 선택한다.
  3. 선택된 url로 다시 1번부터 반복시행.
  4. 더이상 이동할 url이 없을때 종료.
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import numpy as np

def getLinks(url):
    html = urlopen('https://en.wikipedia.org%s' % url)
    bs = BeautifulSoup(html, 'html.parser')
    url_list = bs.find('div',{'id':'bodyContent'}).findAll('a', href=re.compile("^(/wiki/)((?!:).)*$"))
    return url_list

links = getLinks('/wiki/Kevin_Bacon')
while len(links) > 0:
    new_url = links[np.random.randint(0, len(links))].attrs['href']
    links = getLinks(new_url)
    print(new_url)


3. 중복링크는 제외하기

위의 예에서는 페이지의 내부링크를 타고타고 들어갈때, 중복된 링크를 접속하는 경우를 고려하지 않았다.
이럴때 list 보다는 set 타입을 이용하는게 좋다.

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import numpy as np

pages = set()
def getLinks(url):
    global pages
    html = urlopen('https://en.wikipedia.org%s' % url)
    bs = BeautifulSoup(html, 'html.parser')
    for link in bs.find('div',{'id':'bodyContent'}).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')
/wiki/Kevin_Bacon_(disambiguation)
/wiki/Kevin_Bacon
/wiki/Philadelphia
/wiki/Philly_(disambiguation)
/wiki/Philly_Brown
/wiki/2016_Carolina_Panthers_season
/wiki/Ron_Rivera
/wiki/Ron_Rivera_(public_health)
/wiki/New_York_City,_New_York
/wiki/New_York_City_(disambiguation)
/wiki/City_of_New_York_(1885_ship)
/wiki/Norway
/wiki/Norway_(disambiguation)
/wiki/Norway,_Toronto
/wiki/Geographic_coordinate_system

... 생략

파이썬은 보통 재귀 호출을 1000회로 제한하기 때문에 재귀 카운터를 삽입하거나 방법을 강구해야 한다.

댓글남기기