ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • BeautifulSoup4를 이용한 파이썬 크롤링
    Programming & Machine Learning/Python X 머신러닝 2018. 3. 26. 00:53

    데이터 분석에 활용할만한 충분한 데이터를 가지고 있지 않은 경우,


    우리가 할 수 있는 가장 만만한 방법은 웹 데이터를 이용하는 것이다. 


    많은 경우, ResufulAPI 서버에서 자원을 얻어서 활용하기도 하지만, 사실 그건 데이터를 이미 가지고 있는 것과 마찬가지다.


    그래서 크롤링을 활용해서 실제 데이터 분석에 활용하는 경우가 점점 많아지고 있다.









    1. 웹에 대한 이해




    크롤링을 시작하려면 먼저 웹 기본 원리에 대한 이해가 필요하다.




    웹이란 기본적으로 인터넷의 하위 개념이다.




    인터넷으로 불리는 공간에서의 통신 방법은 규약이 필요하다. 


    서로 이해할 수 있는 언어로 이루어져 있어야 하고, 물리적인 연결 및 전송도 필요하다.


    그러한 통신 규약 중 하나가 HTTP라는 것이다.


    우리가 '웹' 이라고 부르는 것은 일반적으로 HTTP 통신을 통해 인터넷 상의 다른 정보를 요청하여 가져오는 것이고, 


    그것의 결과를 보여주는 것이 바로 크롬이나 익스플로러 같은 '웹 브라우저' 이다.





    웹의 통신 규약, 즉 HTTP 프로토콜은 위의 그림과 같은 형태로 주고받아진다.


    웹 크롤링이란, 바로 이런 웹의 언어를 가져온 뒤 그 속에서 원하는 정보를 취합하는 것이라고 할 수 있다.


    여기서 알아야 할 또 한가지는,


    웹에서는 일반적으로 HTML, CSS, Javascript 같은 파일의 형태로 그런 응답에 요청한다는 것이다.


    파이썬이나 R을 비롯한 여러 언어의 크롤러들은 바로 이 파일을 parsing하고, 해석하여 데이터를 추출하는 것이다.





    지금 보고있는 이 웹 페이지 역시, HTML과 각종 파일들로 구성되어진 페이지이다.


    이 페이지의 자원을 가지고 있는 서버에 파일들을 요청하면, 그 응답을 웹 브라우저가 해석하여 보여주는 것이다.


    Mac 운영체제의 경우 : option + command + I,


    윈도우 운영체제의 경우 : Ctrl + Shift + I  혹은  F12 을 누르면 브라우저의 개발자 도구에서 이를 확인할 수 있다.












    2. 크롤링의 방법




    크롤링은 크게 3가지 방법으로 나뉜다.


    HTTP의 GET방식으로 데이터를 얻어오는 크롤링 방법, 

    POST 방법으로 데이터를 얻어오는 크롤링 방법,

    그리고 Javascript등 동적으로만 구성된 페이지를 Selenium 같은 패키지로 강제로 실행하여 데이터를 얻어오는 방법이 있다.


    사실상 크롤링의 주체는 HTTP 통신이라고 봐도 무방하고, 


    파이썬의 BeautifulSoup4 패키지 같은 경우는 HTML Parser라고 보는 것이 더 정확할 것이다.







    1) GET 방식의 크롤링


    특정 URL의 웹 페이지에 있는 HTML 정보를 가져온다고 보면 된다.

    아래의 예제는 벅스뮤직 사이트의 음원차트를 가져오는 예제이다.


    # -*- coding: utf-8 -*-
    import requests
    from bs4 import BeautifulSoup
    import re
    
    req = requests.get('https://music.bugs.co.kr/chart')
    html = req.content
    soup = BeautifulSoup(html, 'lxml') # pip install lxml
    list_song = soup.find_all(name="p", attrs={"class":"title"})
    list_artist = soup.find_all(name="p", attrs={"class":"artist"})
    
    # 곡명 추출
    for index in range(0, len(list_song)):
        title = list_song[index].find('a').text
        print(index+1, ' : ', title)
        if index == 100:
            break
    
    # 피처링 제거
    for index in range(0, len(list_song)):
        title = list_song[index].find('a').text
        print(index+1, ' : ', title.split("(")[0])
        if index == 100:
            break
    
    # csv로 저장
    import csv
    
    with open('melon_chart.csv', 'w', encoding='utf-8') as file:
        writer = csv.writer(file, delimiter=',')
        writer.writerow(['rank', 'song', 'artist'])
        for index in range(0, len(list_song)):
            title = list_song[index].find('a').text
            artist = list_artist[index].find('a').text
            writer.writerow([index+1, title, artist])
            if index == 100:
                break
    
    # 저장된 파일 pd로 읽기
    import pandas as pd
    datas = pd.read_csv('melon_chart.csv')


    2) POST 방식의 크롤링


    특정 URL의 웹 페이지는 POST 방식으로 데이터를 얻어와야 한다.

    python의 request 패키지를 이용하여 헤더에 추가적인 정보를 붙이고, post 방식으로 데이터를 가져올 수 있다.


    아래의 예제는 네이버 API 중, 음성합성 API를 POST 방식으로 가져오는 예제이다. 

    엄밀히 말하자면 웹 크롤링은 아니지만, HTTP 통신에 데이터를 추가하여 POST 방식으로 데이터를 얻어오는 예제이다.

    이 코드를 돌려보려면 개발자 아이디로 가입하여 API 인증을 완료해야 한다.


    # -*- coding: utf-8 -*-
    
    import os
    import sys
    import urllib.request
    
    client_id = "Your Client_ID" # Client_ID 입력
    client_secret = "Your_Client_Password" # Client_Password 입력
    
    encText = urllib.parse.quote("원하는 음성 내용 입력.")
    data = "speaker=mijin&speed=0&text=" + encText;
    
    url = "https://openapi.naver.com/v1/voice/tts.bin"
    request = urllib.request.Request(url)
    request.add_header("X-Naver-Client-Id", client_id)
    request.add_header("X-Naver-Client-Secret", client_secret)
    response = urllib.request.urlopen(request, data=data.encode('utf-8'))
    rescode = response.getcode()
    
    if(rescode==200):
        print("TTS mp3 저장")
        response_body = response.read()
        with open('fastcampus.mp3', 'wb') as f:
            f.write(response_body)
    else:
        print("Error Code:" + rescode)



    3) 크롤링의 간단 활용


    네이버 뉴스 중 특정 카테고리를 선정하여 해당 카테고리의 현재 뉴스 키워드를 크롤링하고 ,

    wordcloud 기법으로 시각화하는 예제이다.


    이 코드를  실행해보기 위해서 konlpy, JPype1-py3 패키지가 설치되어야 한다.

    패키지를 설치하기 이전에 다음의 프로그램들이 현재 컴퓨터 환경에 설치되어 있어야 한다.


    - C 컴파일러 (MacOS : Xcode Builder, Windows : MS Visual Studio C++ 14.0 ~), JAVA, JAVA SDK


    #!/usr/bin/env python3 # -*- coding: utf-8 -*- import requests from bs4 import BeautifulSoup import re import ast # 뉴스기사 리스트 크롤링 base_url = 'http://news.naver.com/main/list.nhn?mode=LS2D&mid=shm&sid1=100&sid2=269' req = requests.get(base_url) html = req.content soup = BeautifulSoup(html, 'lxml') # pip install lxml newslist = soup.find(name="div", attrs={"class":"newsflash_body"}) newslist_atag = newslist.find_all('a') url_list = [] for a in newslist_atag: url_list.append(a.get('href')) # 텍스트 정제 함수 def text_cleaning(text): result_list = [] for item in text: cleaned_text = re.sub('[a-zA-Z]', '', item) cleaned_text = re.sub('[\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]', '', cleaned_text) result_list.append(cleaned_text) return result_list def removeNumberNpunct(doc): text = ''.join(c for c in doc if c.isalnum() or c in '+, ') text = ''.join([i for i in text if not i.isdigit()]) return text # 각 기사에서 텍스트만 정제하여 추출 req = requests.get(url_list[0]) html = req.content soup = BeautifulSoup(html, 'lxml') text = '' doc = None for item in soup.find_all('div', id='articleBodyContents'): text = text + str(item.find_all(text=True)) text = ast.literal_eval(text) doc = text_cleaning(text[9:]) word_corpus = (' '.join(doc)) word_corpus = removeNumberNpunct(word_corpus) # 텍스트에서 형태소 추출 -> pip install konlpy, jpype1, Jpype1-py3 from konlpy.tag import Twitter from collections import Counter nouns_tagger = Twitter() nouns = nouns_tagger.nouns(word_corpus) count = Counter(nouns) # 형태소 워드 클라우드로 시각화 -> pip install pytagcloud, webbrowser # Mac OS : /anaconda/envs/{envname}/lib/python3.6/site-packages/pytagcloud/fonts # Windosw OS : C:\Users\USER\Anaconda3\envs\{envname}\Lib\site-packages\pytagcloud\fonts

    # 위 경로에 {your_korean_font}.ttf 파일 옮기기 import random import pytagcloud import webbrowser ranked_tags = count.most_common(40) taglist = pytagcloud.make_tags(ranked_tags, maxsize=80) pytagcloud.create_tag_image(taglist, 'wordcloud.jpg', size=(900, 600), fontname='Korean', rectangular=False)




    이 외에도 html이 아닌 javascript로 구성된 페이지나, 로그인이 필요한 페이지 등이 있지만 예외적인 경우이고 


    Selenium이라는 패키지를 잘 활용하면 매우 쉽기 때문에 생략한다.

    댓글

분노의 분석실 Y.LAB