Data Science/자연어 처리 (NLP)

BeautifulSoup를 활용한 웹 크롤링(Web Crawling) - Python3, Windows 10 (2)

 

아래 글에서 이어지는 내용이다.

foreverhappiness.tistory.com/27

 

BeautifulSoup를 활용한 웹 크롤링(Web Crawling) - Python3, Windows 10 (1)

아마 웹 크롤링이라는 용어는 Data Science 분야가 활성화되면서 많이 떠오르고 있을 것이다. 크롤링 (Crawling)이란, 스크래핑 (Scraping)이라고도 하는데, 웹 페이지의 특정 부분을 가져

foreverhappiness.tistory.com

 

정규 표현식을 사용하여 문자 필터링을 할 때는 re 모듈을 사용한다.

별도의 설치는 필요 없으며 filtering 함수를 다음과 같이 만든다.

 

# 문자열에서 원하는 문자만 필터링하는 함수이다.
def filtering(string: str) -> str:
    # 필터링을 위해 re 모듈을 사용하였으며
    # 해당 정규 표현식은 한글만 추출한다.
    # findall 함수는 string에서 정규 표현식에 해당하는 부분을 추출해내며
    # compile 함수를 통해 list 형식으로 반환시켜준다.
    string = re.compile('[가-힣]+').findall(string)

    # join 함수를 통해 list의 모든 요소들을 공백으로 구분하여 하나의 문자열로 반환한다.
    return ' '.join(string)

 

정규 표현식에 대한 자세한 내용은 여기서 다루지 않을 것이다.

 

추후에 Python 문법을 정리하면서 생각나면 링크를 걸겠다.

 

filtering 함수는 각 행을 읽어 들여 row_list에 저장하는 과정에서 사용한다.

filtering 함수를 적용한 최종 프로그램은 다음과 같다.

 

# -*- encoding: utf-8 -*-
from urllib.request import urlopen
from bs4 import BeautifulSoup
import csv
import re


# 문자열에서 원하는 문자만 필터링하는 함수이다.
def filtering(string: str) -> str:
    # 필터링을 위해 re 모듈을 사용하였으며
    # 해당 정규 표현식은 한글만 추출한다.
    # findall 함수는 string에서 정규 표현식에 해당하는 부분을 추출해내며
    # compile 함수를 통해 list 형식으로 반환시켜준다.
    string = re.compile('[가-힣]+').findall(string)

    # join 함수를 통해 list의 모든 요소들을 공백으로 구분하여 하나의 문자열로 반환한다.
    return ' '.join(string)


# 웹 페이지로부터 데이터를 크롤링한 후 데이터를 csv파일로 저장하는 함수
def get_csv() -> None:
    # 크롤링 후 저장할 csv 파일을 경로로 지정
    # mode를 'w' (write)로 선언
    # newline을 사용하지 않으면 열과 열 사이의 비어있는 열이 하나 생긴다.
    file_name = open('D:\crawling\crawling_data.csv', 'w', encoding='utf-8-sig', newline='')

    # csv 모듈을 사용하여 지정한 파일의 writer 객체를 가져온다.
    wr = csv.writer(file_name)

    for page_num in range(1, 6771):
        # 크롤링 할 홈페이지의 주소를 url 변수에 담는다.
        url = 'https://icis.me.go.kr/chmCls/chmClsView.do?hlhsn_sn=' + str(page_num)
        
        # BeautifulSoup 객체 생성
        # urlopen 함수를 통해 지정한 주소에 접근할 수 있다.
        # parser의 종류는 기본적으로 BeautifulSoup에서 제공하는 html.paser을 사용한다.
        obj = BeautifulSoup(urlopen(url), 'html.parser')

        if page_num == 1:
            row_list = []           # csv 파일에 들어갈 열(row) 하나의 리스트이다.

            # find_all 함수에 두 개의 파라미터가 들어가있다.
            # 첫 번째 파라미터는 메타 태그, 두 번째 파라미터는 class name이다.
            for item in obj.find_all('div', 's_title'):
                row_list.append(filtering(str(item.find_all(text=True))))

            # writerow 함수를 통해 열(row)를 삽입한다.
            wr.writerow(row_list)

        row_list = []
        for item in obj.find_all('td', 'td_left td_wrap_max'):
            row_list.append(filtering(str(item.find_all(text=True))))

        wr.writerow(row_list)

    file_name.close()


if __name__ == '__main__':
    get_csv()

 

pandas를 사용한 프로그램도 역시 동일한 형태로 적용된다.

 

# -*- encoding: utf-8 -*-
from urllib.request import urlopen
from bs4 import BeautifulSoup
import pandas as pd
import re


# 문자열에서 원하는 문자만 필터링하는 함수이다.
def filtering(string: str) -> str:
    # 필터링을 위해 re 모듈을 사용하였으며
    # 해당 정규 표현식은 한글만 추출한다.
    # findall 함수는 string에서 정규 표현식에 해당하는 부분을 추출해내며
    # compile 함수를 통해 list 형식으로 반환시켜준다.
    string = re.compile('[가-힣]+').findall(string)

    # join 함수를 통해 list의 모든 요소들을 공백으로 구분하여 하나의 문자열로 반환한다.
    return ' '.join(string)


# 웹 페이지로부터 데이터를 크롤링한 후 데이터를 csv파일로 저장하는 함수
def get_text() -> None:
    # pandas 모듈을 사용하게 되면 pandas에서 제공하는 DataFrame 객체의 형태로 저장하고 읽어들일 수 있다.
    # DataFrame에 저장할 각 행을 리스트 형태로 df_list에 담는다.
    df_list = []

    # 첫 번째 행에 해당하는 요소들을 title_list에 담을 것이다.
    title_list = []

    for page_num in range(1, 6771):
        # 크롤링 할 홈페이지의 주소를 url 변수에 담는다.
        url = 'https://icis.me.go.kr/chmCls/chmClsView.do?hlhsn_sn=' + str(page_num)

        # BeautifulSoup 객체 생성
        # urlopen 함수를 통해 지정한 주소에 접근할 수 있다.
        # parser의 종류는 기본적으로 BeautifulSoup에서 제공하는 html.paser을 사용한다.
        obj = BeautifulSoup(urlopen(url), 'html.parser')

        if page_num == 1:
            # find_all 함수에 두 개의 파라미터가 들어가있다.
            # 첫 번째 파라미터는 메타 태그, 두 번째 파라미터는 class name이다.
            for item in obj.find_all('div', 's_title'):
                title_list.append(filtering(str(item.find_all(text=True))))

        row_list = []
        for item in obj.find_all('td', 'td_left td_wrap_max'):
            row_list.append(filtering(str(item.find_all(text=True))))

        df_list.append(row_list)

    # pandas 모듈의 DataFrame 객체를 통해 csv 파일에 입력할 데이터 프레임을 만든다.
    # 이 때, 첫 행은 columns로 각 열에 대한 정보를 표시할 수 있다.
    df = pd.DataFrame(df_list, columns=title_list)

    # 간단하게 to_csv 함수로 경로를 지정해주면 csv 파일로 변환시켜준다.
    # 그냥 변환시키면 자동으로 각 행에 대한 인덱스가 0부터 지정된다.
    # 이를 제거하려면 index 속성을 False로 준다. 필요에 따라 True 혹은 리스트로 지정해줄 수 있다.
    df.to_csv('D:\crawling\crawling_pandas_data.csv', index=False, encoding='utf-8-sig')


if __name__ == '__main__':
    get_text()

이제 기본적인 내용들은 모두 끝났다.

 

이제 추가적으로 알아두면 좋은 몇 가지 내용들을 소개하고자 한다.

 

만약 encoding으로 utf-16을 사용하고 싶다면 csv 모듈을 사용한 코드에서 file_name과 wr을 다음과 같이 수정하면 된다.

 

file_name = open('D:\crawling\crawling_data.csv', 'w', encoding='utf-16', newline='')
wr = csv.writer(file_name, delimiter="\t")

pandas를 사용한다면 df.to_csv 부분을 다음과 같이 바꿔주면 된다.

df.to_csv('D:\crawling\crawling_pandas_data.csv', index=False, encoding='utf-16', sep='\t')

 


 

이제 parser에 대한 내용을 다루고자 한다.

지금까지는 BeautifulSoup에서 지원하는 "html.parser"를 사용했지만 이보다 더 빠른 해석기가 있다.

바로 "lxml"이라는 것이다.

 

하지만 별도의 설치가 필요하므로 시작 버튼 옆의 검색창에 "CMD" 혹은 "명령 프롬프트"를 입력 후 실행시켜주자.

 

그리고 다음과 같이 입력한다.

 

pip install lxml

 

설치가 완료되었으면 이제 html.parser 부분에 다음과 같이 lxml을 사용할 수 있다.

 

obj = BeautifulSoup(urlopen(url), 'lxml')

 

lxml은 속도가 매우 빠르고 xml로 제작된 웹 페이지는 html parser로 해석이 안되기 때문에 lxml을 사용해야 한다.

이외에도 필요에 따라 다를 수 있는데 html5lib parser도 있다.

 

pip install html5lib

 

속도가 매우 느려 쓸 데가 있을지 모르겠지만 방식은 똑같으니 필요하다면 별도의 설치를 통해 사용하면 된다.

 


 

BeautifulSoup 모듈을 사용한 웹 페이지 크롤링이 끝났다.

이제 이렇게 뽑아낸 데이터를 어떻게 가공할 것인가 어떻게 처리를 할 것인가 생각해볼 필요가 있다.

 

BeautifulSoup에 대해 더 자세한 내용을 알고 싶다면 아래 링크를 참고하길 바란다. (한글 문서도 있다.)

https://www.crummy.com/software/BeautifulSoup/bs4/doc/

 

Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation

Non-pretty printing If you just want a string, with no fancy formatting, you can call unicode() or str() on a BeautifulSoup object, or a Tag within it: str(soup) # ' I linked to example.com ' unicode(soup.a) # u' I linked to example.com ' The str() functio

www.crummy.com

 

다음 글에서는 크롤링한 데이터로 형태소 분석을 통해 DTM(Document-Term Matrix, 문서 단어 행렬)을 만드는 방법을 알아보겠다.