<jupyter_start><jupyter_text>TEXT MINING for BEGINNER- 본 자료는 텍스트 마이닝을 활용한 연구 및 강의를 위한 목적으로 제작되었습니다.- 본 자료를 강의 목적으로 활용하고자 하시는 경우 꼭 아래 메일주소로 연락주세요.- 본 자료에 대한 허가되지 않은 배포를 금지합니다.- 강의, 저작권, 출판, 특허, 공동저자에 관련해서는 문의 바랍니다.- **Contact : ADMIN(<EMAIL>)**---  DAY 07. 동적 페이지 수집하기: 네이버 카페- Python을 활용해 가상의 브라우저를 띄워 웹페이지에서 데이터를 크롤링하는 방법에 대해 다룹니다.--- > **\*\*\* 주의사항 \*\*\***  본 자료에서 설명하는 웹크롤링하는 방법은 해당 기법에 대한 이해를 돕고자하는 교육의 목적으로 사용되었으며,  이를 활용한 대량의 무단 크롤링은 범죄에 해당할 수 있음을 알려드립니다.  1. 가상의 브라우저 실행하기: Chrome Driver---<jupyter_code># 가상의 브라우저를 컨트롤 할 수 있도록 도와주는 selenium 패키지를 설치합니다.
# 아래 주석을 해지하고 셀을 실행합니다.
# 설치는 한번만 수행하면 되며, 재설치시 Requirement already satisfied: ~ 라는 메시지가 출력됩니다.

#!pip install selenium
# Python 코드를 통해 가상의 브라우저를 띄우기 위해 selenium 패키지를 import 합니다.
import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By

# selenium을 활용해 브라우저를 직접 띄우는 경우, 실제 웹서핑을 할때처럼 로딩시간이 필요합니다.
# 로딩시간 동안 대기하도록 코드를 구성하기위해 time 패키지를 import 합니다.
import time

# Python 코드를 통해 웹페이지에 정보를 요청하기 위해 BeautifulSoup, urllib 패키지를 import 합니다.
from bs4 import BeautifulSoup
import requests
import urllib
# Chrome Driver를 호출합니다.
chrome_options = webdriver.ChromeOptions()

# 브라우저에 임의로 User-agent 옵션을 넣어 Python 코드로 접속함을 숨깁니다.
chrome_options.add_argument('--user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36"')

# Chrome Driver 파일의 경로를 지정하고 실행합니다.
# Chrome Driver는 아래 링크에서 다운로드 가능합니다.

# 본 Jupyter Notebook 파일과 동일한 경로에 Chrome Driver가 존재하는 경우 아래 경로를 그대로 사용합니다.

# Windows 운영체제
#driver = webdriver.Chrome(executable_path = "chromedriver", chrome_options=chrome_options)

# MAC, Linux 운영체제
driver = webdriver.Chrome(executable_path = "./chromedriver", chrome_options=chrome_options)<jupyter_output><empty_output><jupyter_text>Chrome Driver 다운로드 URL : http://chromedriver.chromium.org/downloads  2. 가상의 브라우저를 활용에 사이트 접속하기---<jupyter_code># 브라우저에서 URL에 해당하는 페이지로 이동합니다.
URL = "https://www.daum.net"
driver.get(URL)
# 실제 페이지가 불러와지는 시간을 고려해 sleep(SEC) 함수로 기다리는 시간을 지정해줍니다.
time.sleep(2)
# 네이버 메인페이지로 이동합니다.
URL = "https://www.naver.com"
driver.get(URL)
time.sleep(2)
# 네이버 카페에 접근하기 위해서는 로그인이 필요합니다.
# 네이버 로그인 페이지로 이동합니다.
# click() 함수로 원하는 요소(태그)를 클릭할 수 있습니다.
driver.find_element(By.CLASS_NAME, "lg_local_btn").click()
time.sleep(2)
# 네이버 로그인 페이지에서 아이디(ID)와 비밀번호(PW)를 입력합니다.
# 아이디와 비밀번호를 브라우저에서 직접 입력해도 됩니다.
ID = "여기에 ID를 입력합니다."
PW = "여기에 PW를 입력합니다."
driver.find_element(By.NAME, "id").send_keys(ID)
driver.find_element(By.NAME, "pw").send_keys(PW)
# 로그인 버튼을 클릭해 로그인합니다.
# 대부분의 경우 자동입력 방지문자 입력이 화면이 출력됩니다.
# 이 경우 브라우저에서 직접 로그인합니다.
# 직접 로그인 하는 경우 이 셀을 실행하지 않아도 됩니다.
driver.find_element(By.NAME, "frmNIDLogin").submit()
time.sleep(2)<jupyter_output><empty_output><jupyter_text>3. 네이버 카페 게시물 링크 수집하기---<jupyter_code># 수집할 카페 게시물의 링크주소를 저장할 리스트를 생성합니다.
post_list = []

# 브라우저에서 직접 내가 수집할 카페에 접속합니다.
# 카페 검색기능을 활용해 수집하고 싶은 내용을 검색합니다.
# 키워드, 기간, 정렬기준 등을 지정해 원하는 검색결과를 화면에 띄웁니다.
# 검색 후 게시물 리스트가 포함된 "진짜 URL"을 찾아냅니다.
# URL을 복사할 때 맨뒤에 "...%26search.page=3" 부분의 숫자(페이지번호)는 제거하고 입력합니다.
# 예시는 네이버 카페 "디젤매니아"에서 "청바지"라는 키워드로 검색된 게시물 URL 입니다.
# 게시물 열람이 가능한 계정으로 카페에 접근해야 수집이 가능합니다.
URL = "https://cafe.naver.com/dieselmania?" + \
      "iframe_url=/ArticleSearchList.nhn%3Fsearch.clubid=11262350" + \
      "%26search.media=0%26search.searchdate=all%26userDisplay=15" + \
      "%26search.option=0%26search.sortBy=date%26search.searchBy=1" + \
      "%26search.query=%C3%BB%B9%D9%C1%F6%26search.viewtype=title%26search.page="

# 몇 페이지 까지 게시물의 URL을 수집할지 지정합니다.
# 최대 페이지 수를 넘지 않도록 주의합니다.
page_limit = 2

# FOR 문을 활용해 페이지 번호를 반복합니다.
for page_num in range(1, page_limit+1):
    # 검색결과 페이지로 이동합니다.
    driver.get(URL + str(page_num))
    # 페이지에서 게시물 리스트가 포함된 프레임으로 이동합니다.
    driver.switch_to_frame(driver.find_element(By.NAME, "cafe_main"))
    # 게시물 태그를 모두 불러옵니다.
    elem = driver.find_elements(By.CLASS_NAME, "article")
    for e in elem:
        # 웹페이지의 하이퍼링크 URL은 항상 href 속성에 존재합니다.
        # href 속성에 저장된 URL을 불러와 post_list에 추가합니다.
        post_list.append(e.get_attribute("href"))
    # 아래 주석부분은 위 25~29번째 라인과 동일한 코드입니다.
    # 혹시 post_list에 URL이 저장되지 않는 경우 아래처럼 태그의 Class 속성을 "article"에서 "aaa"로 변경해줍니다.
    '''
    elem = driver.find_elements(By.CLASS_NAME, "aaa")
    for e in elem:
        post_list.append(e.find_element(By.TAG_NAME, "a").get_attribute("href"))
    '''
    # 페이지의 기본 프레임으로 이동합니다.
    driver.switch_to_default_content() 
    time.sleep(2)
# 총 몇개의 게시물 URL이 저장되었는지 확인합니다.
print("수집된 게시물 URL 개수 :", len(post_list))
# URL이 잘 저장되어 있는지 인덱싱을 통해 일부만 확인해봅니다.
print(post_list[0:5])
print(post_list[5])<jupyter_output>https://cafe.naver.com/ArticleRead.nhn?clubid=11262350&page=1&inCafeSearch=true&searchBy=1&query=%C3%BB%B9%D9%C1%F6&includeAll=&exclude=&include=&exact=&searchdate=all&media=0&sortBy=date&articleid=27289218&referrerAllArticles=true<jupyter_text>4. 네이버 카페 게시물 본문과 댓글 수집하기---<jupyter_code># 게시물 URL이 저장된 post_list에서 몇번째 부터(start) 몇번째 까지(end) URL에 접근할지 지정합니다.
start = 0
end = 3

# 게시물 내용을 저장할 파일을 생성합니다.
f = open("naver_cafe_dieselmania.txt", "w", encoding="utf-8")

# FOR 문을 활용해 페이지 URL을 반복합니다.
for url in post_list[start:end]:
    # 현재 수집이 진행중인 인덱스를 출력합니다.
    print(str(start) + "/" + str(len(post_list)), end="\r")
    start += 1
    # URL을 통해 게시물 페이지로 이동합니다.
    driver.get(url)
    # 페이지에서 게시물 내용이 포함된 프레임으로 이동합니다.
    driver.switch_to_frame(driver.find_element(By.NAME, "cafe_main"))
    
    # 페이지에서 태그의 속성을 활용해 원하는 부분을 불러옵니다.
    # 1. 게시물 제목
    elem = driver.find_element(By.CLASS_NAME, "tit-box")
    title = elem.find_elements(By.TAG_NAME, "td")[0].text
    # 2. 게시판 이름
    board_type = elem.find_elements(By.TAG_NAME, "td")[2].text
    # 3. 게시물 작성일자
    datetime = elem.find_element(By.CLASS_NAME, "fr")
    datetime = datetime.text
    # 4. 게시물 작성자(닉네임)
    user = driver.find_element(By.CLASS_NAME, "etc-box").find_element(By.TAG_NAME, "td")
    user = user.text
    # 5. 게시물 내용
    contents = driver.find_element(By.XPATH, "//*[@id=\"tbody\"]").text
    # 파일에서 게시물 구분을 줄단위로 하기위해 줄바꿈을 모두 제거합니다.
    content = contents.replace("\n", " ")
    # 파일에 수집한 게시물 내용을 기록합니다.
    f.write("POSTING" + "\t" + user + "\t" + datetime + \
            "\t" + board_type + "\t" + title + "\t" + content + "\n") 
    
    # 댓글을 모두 불러옵니다.
    reply_list = driver.find_elements(By.CLASS_NAME, "comm_cont")
    # FOR 문을 활용해 댓글을 모두 반복합니다.
    for reply in reply_list:
        # 6. 댓글 내용
        comment = reply.find_element(By.CLASS_NAME, "comm_body").text
        # 7. 댓글 작성자(닉네임)
        user_nik = reply.find_element(By.CLASS_NAME, "pers_nick_area").text.replace("작성자", "")
        # 8. 댓글 작성일자
        reply_date = reply.find_element(By.TAG_NAME, "span").text
        # 파일에 수집한 댓글 내용을 기록합니다.
        f.write("COMMENT" + "\t" + user_nik + "\t" + reply_date + \
                "\t" + board_type + "\t" + "None" + "\t" + comment + "\n")
    # 페이지의 기본 프레임으로 이동합니다.
    driver.switch_to_default_content()
    time.sleep(2)
f.close()
# Chrome Driver를 닫습니다.
driver.close()
# 파일에 저장된 카페 게시글 내용을 확인합니다.
f = open("naver_cafe_dieselmania.txt", encoding="utf-8")
for post in f:
    print(post.strip())
f.close()<jupyter_output>POSTING	ㄴl가사는그집(ccn1****)	2019.06.05. 03:24	디매iN 고민-상담	쿨맥스소재 청바지 여름에 진짜 시원한가요?	쿨맥스소재 청바지 여름에 진짜 시원한가요? 여름용으로 나온 청바지 다 얇게 만들어도 슬랙스나 치노보다 두께감 있어 한여름때 입을수 있을까 걱정되긴하더군요 선택지가 쿨맥스 소재 데님밖에 없네요
POSTING	카트리리(woxh****)	2019.06.05. 01:49	■디매iN 라이프■	베맥 3.0트블 이랑 청바지 잘 어울리나요?	궁금쓰
COMMENT	전체이용가	2019.06.05. 01:49	■디매iN 라이프■	None	심지어 슬랙스도 잘맞
COMMENT	주호민	2019.06.05. 01:49	■디매iN 라이프■	None	나쁘진않는데 베스트는아닌듯요
POSTING	라잌뎃(tkdv****)	2019.06.05. 01:47	디매iN 고민-상담	밑위 짧은 청바지 브랜드 추천해쥬세요	밑위짧은게 취향입니다 추천해주세요!
COMMENT	빈센트반코흥	2019.06.05. 01:48	디매iN 고민-상담	None	피스워커 겁나짧은득
COMMENT	마아아아아아아아동석	2019.06.05. 01:48	디매iN 고민-상담	None	유니클로
COMMENT	바이크매니아	2019.06.05. 01:52	디매iN 고민-상담	None	트루릴리전
{'fraction_non_alphanumeric': 0.12747252747252746, 'fraction_numerical': 0.02947640594699418, 'mean_word_length': 3.5372434017595307, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 17, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '555661', 'license': 'Apache-2.0', 'n_tokens_mistral': 4950, 'n_tokens_neox': 5977, 'n_words': 872, 'path': 'practice-note/07_text-mining-for-beginner_python-crawling-practice-2.ipynb', 'repo_name': 'fingeredman/text-mining-for-beginner', 'size': '7745'}