파이썬으로 웹 이미지 모아서 저장하기 - BeautifulSoup4, urllib

 파이썬을 이용해서 웹 이미지 URL(src)을 모은 뒤, 컴퓨터에 저장하는 방법입니다. 더 쉬운 방법도 있지만 연습도 할 겸, 크롤링할 때 자주 사용되는 모듈인 Beautifulsoup4를 사용할 것입니다. 보통 텍스트 데이터를 모을 때 많이 사용하는데 이미지도 모을 수 있지 않을까 싶어서 시도해 봤습니다. 이미지를 저장할 때는 파이썬에 기본으로 있는 urllib를 사용할 겁니다.
 연습할 사이트는 아직도 운영되고 있는 고전 온라인 게임 라그나로크 사이트입니다. 메뉴 중 룬미드가츠 도서관의 몬스터 이미지를 모아 볼 거예요.

 저번에는 이미지 저장할 때 셀레니움을 사용했는데, 셀레니움이랑 bs4는 느낌이 좀 다릅니다. 개인적으로 셀레니움이 직관적인 느낌이라 더 쉬웠지만, 속도는 bs4가 더 빠른 것 같습니다. bs4는 브라우저를 켜고 하는 게 아니라 그냥 링크를 넣으면 알아서 정보를 모아오는 것이라서요.
 구글 코랩에서도 이미지 링크를 모을 수 있지만 이미지를 PC에 저장하기엔 불편해서 그냥 PC에 설치되어 있는 파이썬을 사용하는 걸 추천합니다. 코랩에서 하실 거면 코랩에서 이미지를 저장하는 방법을 따로 검색해 보셔야 합니다. 아마 시간도 좀 오래 걸릴 것 같네요.

 다음 코드로 bs4 패키지를 설치해주세요.
pip install beautifulsoup4

 라크나로크 룬미드가츠 도서관의 몬스터로 들어가시면 페이지 수가 꽤 많은데요. 페이지를 누르다 보면 사이트 주소에 계속 바뀌는 숫자가 있을 겁니다. 3페이지에서는 3, 10페이지에서는 10 이런 식으로요. 보통 주소 맨 뒤에 있습니다.
 먼저 1페이지에 있는 몬스터 이미지를 모아보겠습니다.

 필요한 모듈을 불러오고 다음과 같이 작성합니다. url에 사이트 링크를 넣으시면 됩니다.
import requests
import urllib.request
from bs4 import BeautifulSoup

url = "https://ro.gnjoy.com/guide/runemidgarts/monsterlist.asp?curpage=1"

request = requests.get(url)
html = request.text

soup = BeautifulSoup(html, 'html.parser')
 이미지를 저장할 때 몬스터 이름으로 저장할 것이기 때문에, 페이지에서 몬스터의 이름을 찾는 코드부터 작성합니다. 요소를 찾을 때는 브라우저의 개발자 도구를 이용하시면 됩니다. 개발자 도구는 크롬 기준으로 F12를 누르면 나옵니다.
 요소 선택 도구로 이름이 적혀 있는 텍스트 부분을 클릭하니 <td class="left">가 나왔네요.
monster_name = soup.findAll("td", attrs = {"class" : 'left'}) #요소 위치
name_list = []
for line in monster_name:
  word_list = line.get_text().split(",") #단어들을 리스트로 저장
  for word in word_list:
    name_list.append(word.strip())
 코드 작성 후 제대로 수집되었는지 확인하고 싶다면, 마지막에 print(name_list)를 추가하면 됩니다.

 이제 몬스터 이미지 url을 찾을 것입니다. 이미지 코드는 <img src="이미지 링크(위치)" ~> 이런 식으로 적혀 있습니다. 저 src에 적혀있는 링크를 클릭하면, 크롬의 경우 해당 이미지가 있는 페이지가 뜹니다. 그럼 마우스 우클릭으로 저장할 수 있어요.
 이미지 링크를 모으려면 위의 class="left"처럼 해당 요소를 특정할 수 있는 속성을 찾아야 하는데요. 여기서 문제가 생겼습니다. 보통 텍스트의 경우 같은 요소는 속성이 똑같은 걸로 통일되어 있는데 이 사이트는 alt가 "(몬스터 이름) 이미지"로 되어 있더라고요. 식별할 수 있는 다른 속성이 없었습니다.

이미지 속성

 그래서 아까 위에서 모았던 몬스터 이름을 이용해 다음과 같이 코드를 작성했습니다.
for i in range(0,len(name_list)):
  imgUrl = soup.findAll('img', attrs={"alt" : name_list[i] +" 이미지"})
 이게 될까? 싶었는데 됩니다. 이렇게 모은 이미지 링크를 urllib를 이용해 다운 받으면 됩니다. 움직이는 이미지이므로 확장자는 GIF로 해줍니다. 이 때 중요한 것 중 하나는, 몬스터 이름의 특수 문자를 제거하는 것입니다. 몬스터 이름 중에 '?'가 들어간 게 있더라고요. 혹시 모르니까 띄어쓰기도 '_'로 바꿔줍니다.
※파일 이름에 사용할 수 없는 문자: \ / : * ? " < > |
for i in range(0,len(name_list)):
  imgUrl = soup.findAll('img', attrs={"alt" : name_list[i] +" 이미지"})
  name_list[i] = name_list[i].replace(" ", "_")
  name_list[i] = name_list[i].replace("?", "_")
  try:
    for image in imgUrl:
      urllib.request.urlretrieve(image['src'], 'mon'+ str(i+671) + '_' + name_list[i]+'.gif')
    except urllib.error.HTTPError:
      continue
 이제 다른 페이지의 이미지까지 받으려면 반복문을 사용해야 합니다. 처음에 있던 코드를 다음과 같이 수정합니다. 전체 반복문이기 때문에 수정하고 나서 다른 코드들에 모두 들여쓰기를 해주어야 합니다. 파이썬은 들여쓰기를 틀리면 실행이 제대로 되지 않습니다.
for num in range(1, 100):
  url = "https://ro.gnjoy.com/guide/runemidgarts/monsterlist.asp?curpage=" + str(num)
 반복문에 몇 페이지까지 모을 건지 입력하면 됩니다. 완성한 코드입니다.

import requests
import urllib.request
from bs4 import BeautifulSoup

name_list = []
for num in range(1,100):
  url = "https://ro.gnjoy.com/guide/runemidgarts/monsterlist.asp?curpage=" + str(num)
  
  request = requests.get(url)
  html = request.text

  soup = BeautifulSoup(html, 'html.parser')
#이름 찾기
  monster_name = soup.findAll("td", attrs = {"class" : 'left'})
  for line in monster_name:
    word_list = line.get_text().split(",")
    for word in word_list:
      name_list.append(word.strip())
#이미지 url 찾기
  for i in range(0,len(name_list)):
    imgUrl = soup.findAll('img', attrs={"alt" : name_list[i] +" 이미지"})
    name_list[i] = name_list[i].replace(" ", "_")
    name_list[i] = name_list[i].replace("?", "_")
    #이미지 다운로드
    try:
      for image in imgUrl:
          urllib.request.urlretrieve(image['src'], 'mon'+ str(i+1) + '_' + name_list[i]+'.gif')
    except urllib.error.HTTPError: #이미지가 없는 경우(링크에서 404 오류가 뜰 경우)
      continue

 그럼 mon1_이름.gif, mon2_이름.gif 이런 식으로 저장이 됩니다. 크롤링은 거의 텍스트 정보를 모아서 분석하고 결과를 도출하는 것이라 이미지를 모으는 게 쓸모 있을지는 잘 모르겠네요. 그냥 재미를 위해서 한 거니까 별 상관은 없지만요.
 다음에는 뭘 해야 할지 고민되네요. 취미라고 해도 목표가 있는 게 좋은데 도전할만한 걸 혼자 찾기가 쉽지 않습니다.

댓글 쓰기

0 댓글