본문 바로가기
Study/Python

Python을 이용한 Web Crawling

by Jamie Lim 2020. 5. 28.
* 이 실습은 공부에만 사용하였습니다 

< 도전 과제 >

1. 웹툰 최신화 이미지 다운로드 크롤러 만들기
2. 웹툰 최신 10화 이미지 다운로드 크롤러 만들기

1. 기본 개념

  1) 크롤링(crawling)이란?

    크롤링이란 웹 크롤러에서 출발한 말로 인터넷 상의 페이지를 수집해 분류하고 저장한 후 나중에 쉽게 찾아볼 수 있도로 도와주는 일종의 봇이다.

 

  2) 크롤링에 필요한 모듈

     (1) urllib

        - URL 처리 모듈로 URL 작업을 위한 여러 모듈을 모아놓은 패키지다

 

        - 파이썬에서 웹과 관련한 데이터들을 손쉽게 이용할 수 있도록 도와준다

 

        - urllib는 내장된 라이브러리에 있어 따로 설치하지 않아도 사용이 가능하다

 

        - urllib에는 총 4가지 종류의 모듈이 있다. 우리는 그중 requet만 사용할 예정이다

          · URL을 열고 읽기를 도와주는 request

          · request에 의해 발생한 예외를 다루는 error

          · URL 구문 분석을 도와주는 parse

          · robots.txt 파일을 분석하기 위한 robotparser

 

        - urllib.request

 

import urllib.request

 

          ·  URL을 가져오기 위한 파이썬 모듈

          ·  모듈은 기본 & 다이제스트 인증, 수정, 쿠키 등과 같은 복잡한 환경을 처리해 URL을 가져오는 것을 도와주는 기능을 함

          ·  웹툰 크롤러를 만들 때 사용할 함수는 urlopen과 build_opener이다

 


            ▶ urlopen : 웹 페이지에서 얻은 데이터에 대한 객체를 반환해준다

 

result = urllib.request.urlopen("http://www.naver.com")
print(result)

# 결과 => <http.client.HTTPResponse object at 0x000002753E729548>

       

 

            ▶ build_opener

 

opener = urllib.request.build_opener()
opener.addheaders=[('User-Agent','Mozilla/5.0')]
urllib.request.install_opener(opener)

 

                ≫  단일 함수 호출로 오퍼너 객체를 만드는 것이다

                ≫  사용자가 직접 처리기에 대해 만들 수 있다

                ≫  같이 사용하는 install_opener를 통해 build_opener로 만든 오프너를 기본 오프너로 만들 수 있다

                ≫  opener가 현재 어떤 브라우저를 이용해 접근할지 정할 수 있는데 이는 addheaders를 통해 User-Agert 헤더에 값을 넣을 수 있다

 

 

User-Agent : 
사용자를 대신해 일을 수행하는 소프트웨어 agent이다. 헤더 필드로 전달되어 소프트웨어 업체, 버전을 식별하기도 한다
브라우저 User-Agent String
Mac OS
Chrome
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
Mac OS
Firefox
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:64.0) Gecko/20100101 Firefox/64.0
Mac OS
Safari
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.2 Safari/605.1.15
iOS
Chrome
Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/71.0.3578.89 Mobile/15E148 Safari/605.1
Android
Chrome
Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G950N/KSU3CRJ1 Build/R16NW) pleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36
Windows
IE11
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko
Windows
Edge
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134
Windows
Chrome
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
Windows
Firefox
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0

                

 

     (2) Beautifulsoup

        - 파이썬 패키지 중 하나로 HTML이나 XML 문서를 파싱할 때 사용한다. 이를 통해 추출한 데이터들을 사용할 수 있게 도와줌

 

        - python 2.7과 python 3에서 사용 가능

 

        - HTML, XML 문서를 읽고 해석해 태그명, 속서영, 속성값, 앨리먼트 내용을 분리해주는 프로그램이다

 

        - 주어진 정보를 내가 원하는 대로 가공해 서버에서 원하는 때 불러올 수 있도록 도와준다

 

        - urllib 모듈과는 다르게 따로 설치가 필요하다 (python 디렉토리 cmd창에서 Scripts 폴더로 이동해 설치한다)

pip install beautifulsoup4

 

 

        - 이 모듈을 이용해 원하는 페이지를 파싱할 수 있다

# html은 urllib.urlopen을 통해 요청한 페이지다

result = BeautifulSoup(html.read(), "html.parser")

 

           * parsing

              · 어떤 페이지에서 내가 원하는 데이터를 특정 패턴이나 순서로 추출해 정보로 가공하는 것

              · 문법적으로 해부라는 뜻으로 기계어를 번역한다고 이해할 수 있음

              · 일련의 문자열을 의미 있는 토큰으로 분해해 토큰들로 이루어진 Parse tree를 만드는 과정

 

 

     (3) os

        - Operating System의 약자로 운영체제에서 제공되는 여러 기능을 파이썬에서 수행할 수 있게 해준다

 

        - urllib 모듈처럼 내장된 모듈이기 때문에 다로 설치가 필요없다

 

        - 이번 과제에서 사용할 주요 함수

 

          · getcwd() : 현재 경로를 알려줌

path = os.getcwd()
print(path)

# 결과 => C:\Users\jamie\Desktop\SWING\2학년 1학기\3. python\swing_python

 

          · chdir() : 원하는 디렉토리로 이동

# 원하는 디렉토리로 이동
os.chdir("week 4")
path = os.getcwd()
print(path)

# 결과 => C:\Users\jamie\Desktop\SWING\2학년 1학기\3. python\swing_python\week 4


# 이전 디렉토리로 이동
os.chdir("..")
path = os.getcwd()
print(path)

# 결과 => C:\Users\jamie\Desktop\SWING\2학년 1학기\3. python\swing_python

 

          · mkdir() : 현재 지정된 경로에 새로운 디렉토리 생성

os.mkdir("hello")  # 현재 경로에 hello라는 이름의 디렉토리 생성
os.chdir("hello")  # 새로 만든 hello 디렉토리로 이동
os.mkdir("world")  # 현재 경로인 hello 디렉토리에 world라는 이름의 디렉토리 생성

 

새로 생성된 디렉토리
hello 디렉토리 안에 생성된 디렉토리

 


2. 웹툰 최신 이미지 다운로드 크롤러 만들기

  - 원하는 웹툰 페이지에서 가장 최신에 올라온 화의 웹툰 이미지들을 다운로드하는 크롤러이다.

 

  1) 웹툰 제목 가져오기

    - 원하는 웹툰 페이지 URL로 요청하고 파싱하여 웹툰 제목 추출하기

 

웹툰 소스코드

# 크롤링할 웹툰 선택해 주소로 웹 페이지 요청
html = urllib.request.urlopen("https://comic.naver.com/webtoon/list.nhn?titleId=694946&weekday=mon")

result = BeautifulSoup(html.read(), "html.parser")  # 요청한 웹 페이지 파싱

# 웹툰 이름 불러오기  split()하면 리스트에 웹툰 이름과 QTT가 저장됨 그중 [0]이 웹툰 제목
name = result.find("div", {"class", "detail"}).find("h2").text.split()[0]

 

 

  2) 웹툰 제목으로 디렉토리 생성

   - 만약 웹툰 제목의 디렉토리가 이미 있다면 생성하지 않음

 

# 파일을 저장하고 싶은 경로로 이동하기
os.chdir("week 4")
path = os.getcwd()
if not os.path.isdir(name): # 만약 만들려는 폴더 (웹툰 제목인 폴더)가 없다면 폴더 생성
    os.mkdir(name)
os.chdir(name)  # 만든(혹은 만들어져 있던) 폴더로 경로 이동

 

생성된 디렉토리

 

 

  3) 가장 최신화 URL 가져오기

    - 가장 최신화의 URL a태그에 있는 'href'의 값이다

    - 가져온 URL 앞에 "https://comic.naver.com"을 붙여

 

웹툰 소스코드

# 웹툰 에피소드 하나의 url찾기 (한 화만 가져오므로 findAll이 아닌 find로 하나만 찾기)
newEpi = result.find("td", {"class", "title"})

# 원하는 에피소드 주소로 요청하고 파싱하기
newEpi_html = urllib.request.urlopen("https://comic.naver.com" + newEpi.a['href']) 
newEpi_result = BeautifulSoup(newEpi_html.read(), "html.parser")

 

 

  4) 웹툰 이미지 URL 가져오기

웹툰 이미지에 대한 소스코드

# div의 class가 wt_viewer인 가장 첫번째가 웹툰 이미지 영역임
img = newEpi_result.find("div", {"class", "wt_viewer"})

imgUrl = img.findAll("img")  # class가 wt_viewer인 영역에서 img만 모두 가져오기 -> 웹툰 이미지

 

  5) 네이버에게 봇이 아님을 보여주기

    - 네이버와 같은 대형 사이트는 urllib.request 모듈을 이용해 접근한 것을 봇이라고 판단하여 403 에러를 발생시킴

    - 403 에러는 요청이 금지되엇다는 의미로 이미지에 접근하는 것을 막아 당연히 다운로드도 불가능하게 된다

 

403 요청 금지 에러

opener = urllib.request.build_opener()
opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
urllib.request.install_opener(opener)

 

  6) 파일에 이미지 저장하기

    - urlretrieve()는 현재 경로에 url 주소에 대한 이미지를 지정한 이름으로 저장하는 기능을 수행한다

    - 현재 이미지 이름은 1부터 시작해 +1씩 시켰다. 또한, 확장자명을 뒤에 붙여주어야 한다

num = 1  # 이미지 이름 변수

for url in imgUrl:  # 찾은 imgUrl이 있을 때까지 반복
    save = str(num) + ".jpg"  # 이미지 이름 + 확장자명 하나로 저장
    urllib.request.urlretrieve(url.get("src"), save)  # 이미지 url을 통해 다운로드
    print(str(num) + "번째 이미지 저장 성공")  # 성공했다는 의미의 문자열 출력
    num = num + 1  # 이미지 이름 + 1

print("이미지 저장 완료")  # 이미지 다운로드가 모두 완료되면 완료했다는 문자열 출력

 

지정한 경로에 이미지들 저장

    - 현재 지정된 경로에 웹툰 이미지들을 차례대로 .jpg 확장자로 저장한다

 

 

 


3. 웹툰 최신 10화 이미지 다운로드 크롤러 만들기

  - 웹툰 이미지를 다운받는 방법은 위 방법과 같은 방식이다

  - 다른 점은 한 화에 대한 폴더가 아닌 최신 10화에 대한 이미지를 다운 받을 때 각 페이지에 요청하고 파싱해 각 화별 폴더를 만들어야 하는 것이다

  - 경로 지정과 봇이 아님을 보여주는 코드는 위와 같기에 생략하겠다

 

  1) 각 화의 제목 가져오기

    - 위 과제에서는 한 화에 대한 정보만 가져왔으면 됐지만 이번 과제에서는 최신 10화에 대한 정보를 모두 가져와야함

    - find()가 아닌 findAll()로 첫 페이지에있는 10화에 대한 정보를 모두 가져온다

# 웹툰 에피소드 하나의 url찾기 (첫 페이지의 최신 10화를 가져오므로 모두 가져와야 함 -> findAll 사용)
newEpi = result.findAll("td", {"class", "title"})

 

  2) 각화에 대한 이미지 다운로드

    - 각 화에 대한 제목으로 폴더를 만들고 그 화에 대한 이미지를 각 폴더에 저장한다

    - 전체적인 틀은 같기 때문에 주석을 통해 첫 과제와 다른 부분들만 설명하겠다

# 화마다 해당 화 제목으로 파일 생성후 경로 이동 (첫 페이지에 있는 화수가 끝날 때 까지 반복)
for epi in newEpi:
    epi_title = epi.text.split("\n")[1]  # 해당 화의 제목 가져오기
    if not os.path.isdir(epi_title):  # 제목으로 만들어진 폴더가 있는지 확인 후 없으면 폴더 생성
        os.mkdir(epi_title)

    os.chdir(epi_title)  # 만든(혹은 만들어져 있던) 폴더로 경로 이동

    epi_html = urllib.request.urlopen("https://comic.naver.com" + epi.a['href']) 
    epi_result = BeautifulSoup(epi_html.read(), "html.parser

    img = epi_result.find("div", {"class", "wt_viewer"}) 
    imgUrl = img.findAll("img")

    num = 1
    print(epi_title + " 이미지 저장 시작")  
    for url in imgUrl:  
        save = str(num) + ".jpg"  
        urllib.request.urlretrieve(url.get("src"), save)
        print(str(num) + "번째 이미지 저장 성공")  
        num = num + 1
    
    print(epi_title + " 이미지 저장 완료\n\n
    os.chdir("..")  # 다음 화의 폴더로 이동하기 위해 현재 경로에서 이전 디렉토리로 이동

print("모든 이미지 저장 완료")

 

각 화의 제목으로 디렉토리 생성

 

총 10편의 에피소드의 이미지들이 각 화별 폴더에 저장됨

 

 

* 다운로드한 웹툰 이미지는 실습이 끝난 뒤에 모두 삭제하였습니다.

 

< 출처 >

위키피디아 https://en.wikipedia.org/wiki/Parsing
Python.org https://docs.python.org/3/library/urllib.html=
Chrome.com https://developer.chrome.com/multidevice/user-agent
네이버 블로그 https://blog.naver.com/ued_123/221552494873

 

User Agent Strings - Google Chrome

Chrome Extend the Browser What are Extensions? Get Started Tutorial Overview Manifest Format Manage Events Design User Interface Content Scripts Declare Permissions and Warn Users Give Users Options Developer Guide Reach Peak Performance Protect User Priva

developer.chrome.com

 

'Study > Python' 카테고리의 다른 글

Python으로 게임 매크로 만들기  (0) 2020.06.06
[Python] 문자열과 리스트 함수 문법  (0) 2020.04.12

댓글