2018년 4월 4일 수요일

,

네이버 텍스트 크롤링 예제 (파이썬)


네이버 텍스트 크롤링 예제 (파이썬)

본 내용은 네이버를 타겟으로 텍스트 크롤링 전체 과정을 좀더 구체적으로 설명하기 위한 예입니다. R을 이용한 크롤링 예제는 크롤링 세부 과정이 상당 부분 함수 속에 숨어 있어, 이 과정을 일일이 파악하기에는 어려움이 있습니다. 때문에 구체적인 방법 하나하나를 모두 파악하기 위해서 프로그래밍 언어인 파이썬 예제를 가지고 설명하고자 합니다. 파이썬을 모르더라도 각 코드별 의미를 설명한 각주를 보면서 어떤 과정으로 크롤링을 해야 하는지 구체적인 아이디어를 이해하면 어떤 소프트웨어를 이용해 크롤링을 하건 도움이 될 것입니다. 

아래 화일을 다운받으려면 아래 클릭해서 파이썬 화일을 다운 받으세요. 
                                                         * 파이썬 코드 작성: JLab 허성우, 김보성        
2019년 작성한 코드로 업데이트가 필요합니다. 현 시점 사이트 크롤링을 위해서는 코드 내용 이해후 최근 사이트 특징에 맞게 수정이 필요합니다. 

# 특정 불로그(타겟사이트)에서 반복해서 나타나는 특정 정보 추출해, 특정 csv화일에 저장하기. 
   # 특정 사이트 (현재 예는 네이버)에서 특정 키워드로 검색된 내용 중 일부 정보 추출하기
   # 추출 대상: 글제목(->Field1), 작성자명 (->Field2), 글내용 (->Field3), 기타 등등
   # output: CrwaledText.csv 화일에 자동 저장됨.
   # 주의사항: 컴에 크롬이 설치되어 있어야 함.
   
######## Step 1 web text scraping시 항상 쓰는 library 부르기
from selenium import webdriver  # selenium모듈에서 webdriver 함수 준비 (가상크롬 설정)
from bs4 import BeautifulSoup   # bs4모듈에서 웹문자 추출 용 beautifulsoup 부르기
import urllib.request         # url가져오기 준비
import re                       # request(url가져오기) 
import time                    # ...
import numpy as np         # 과학 계산, 다차원 배열을 처리 참고 http://pythonstudy.xyz/python/article/402-numpy-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

import csv                      # csv화일 만들기용 모듈

"""step 1: 우선 위 패키지 파이썬 사용 환경 설정해야 함. 
   selenium 화일 다운로드하고 https://www.seleniumhq.org/download/ 
         해당 화일(selenium-server-standalone-3.11.0.jar)을 특정 폴더에 이동후 그 경로를 파이썬에 지정해주기
   pip 필요한데 어떤 경우는 기본으로 내장되어 추가 절차 필요 없으나, 따로 설치해야 할 수도 있듬. (pc마다 환경에 따라 다름) 
   
   pip (또는 pip3) install re 
   pip (또는 pip3) install bs4
   pip (또는 pip3) install time
   pip (또는 pip3) install numpy
         pip (또는 pip3) install "모듈명"으로 bs4, re, time, numpy를  cmd창에서 설치해야 함. 
   """

####### step 2: 타겟사이트 주소 변수 생성, fishing keyword와 검색 결과 중 몇 페이지까지 크롤링할 지 필요한 정보 입력창에서 입력하기 

hyperlink = re.compile(r'.*href="(.*)" target.*') #특정 사이트 지정할 변수 정의
"""특정 사이트 주소를 담을 변수명 hyperlink 만들기(지정). 실제 타겟사이트 주소url은 아래
             driver.get("https://section.blog.naver.com/Search/Post.nhn?pageNo="+actualPage+"&rangeType=ALL&orderBy=sim&keyword="+target) 부분에서 수정하시오."""

target = input("Enter a fishing keyword : ") #타겟사이트에서 검색할 fishing 키워드 입력요청 (예 -> target

maxPages = input("Enter the maximim page number of this websites for crawling: ") #크롤링 몇페이지까지 읽을 지 페이지 수 요청->maxPage 

   # CrawledText = input("Enter the name of the output file: (eg output.csv)") # 나중에 저장화일명도 입력토록 수정하자.
   

####### 크롤링한 웹페이지에서 수집할 내용들을 담기 위한 각 변수(field) 지정하기(현재 3개만 지정되어 있음)
"""메인타이틀 변수 지정하기: (예 ng-bind-html="post.title"> 뒤부터 </span>표현 사이 것 추출해 main title이라는 변수 지정하기 """
   #  포맷: r' 추출직전표현 (.*) 추출끝이후부분 .*')   r' 시작, (.*) 추출부분 .*' 마지막
maintitle = re.compile(r'ng-bind-html="post.title">(.*)</span>.*') # 변경해야할 부분 ng-bind-html="post.title">   에서 시작해 </span>전까지 추출
Field2RE = re.compile(r'<em class="name_author">(.*)</em>.*')    #변경해야할 부분 Field2 찾기 (예 <em class="name_author"> 뒤부터 </em>표현 사이 것 추출해 field2에 넣기 지정
Field3RE=re.compile(r'ng-if="post.contents" target="_blank">(.*)</a>.*') # 변경해야할 부분 ng-if="post.contents" target="_blank"> 뒤 부터 </a>까지.

#가상 크롬 구동하기 (Selenium 구동... 컴이 자동으로 크롬으로 해당 페이지 읽도록하기 위해 필요
driver=webdriver.Chrome("C:/Users/ATIV/Downloads/chromedriver_win32/chromedriver")
   # 변경해야할 부분. 컴마다 환경 다르므로 왼쪽 폴더 위치를 selenium-server-standalone-3.11.0 화일이 있는 폴더명으로 대체할 것
driver.set_window_size(1120,800)

#driver.get("https://section.blog.naver.com/Search/Post.nhn?pageNo=1&rangeType=ALL&orderBy=sim&keyword="+target) 

time.sleep(2) #시간 주어서 프로그램 작동 시간이 긴 경우 skip하는 걸 막기 위함. 느린 컴의 경우에는 이것 더 길게 조정해야 함.

isFinished = False #루프 조건 판단용 변수
row = 1 # 루프시작 1로 시작


with open('CrwaledText.csv', 'w', newline='') as f:
    # 항상 CrwaledText.csv라는 output 화일 만들어 열고 쓰기 (w) 준비 * with open('저장화일명', 'w=쓰기모드') as f (변수 f에 넣기) 
    # 쓰기변수 writer라고 변수 지정
    writer = csv.writer(f)
    writer.writerow( ['Field1', 'Field2', 'Field3','Field4', 'Field5'] ) #저잘 화일의 칼럼별 해당 변수 지정해주기 """
    
    #while not isFinished: 루프시작
    for page in range( int(maxPages) ):    #최대페이지 maxPages내에서 페이지 1부터 page넣기 페이지번호수변수를 정수화한 뒤 해야 함 기본은 string이므로 """
        """ actual page 링크에서 페이지 가져오기""" 
        actualPage = str(page + 1) # actualPage=1로 시작 (range는 0시작하므로 1 더하기후 시작 """
        print ("VIEWING PAGE N "+actualPage) #과정 보여주기  글씨에 페이지 숫자 첨가"""

        #타겟 사이트(예 네이버 혼밥 55페이지)의 55페이지 화면의 소스 코드를 텍스트형태로 가져와서 driver변수에 넣기  
        driver.get("https://section.blog.naver.com/Search/Post.nhn?pageNo="+actualPage+"&rangeType=ALL&orderBy=sim&keyword="+target)
            # 변경해야할것 타겟 사이트 url을 위처럼 수정해 넣을 것
            #만약 타겟 사이트 url오른쪽인 경우 예: https://section.blog.naver.com/Search/Post.nhn?pageNo=55&rangeType=ALL&orderBy=sim&keyword=혼밥" 55페이지 키워드 혼밥인 경우 """
        
        time.sleep(3)

        #파싱 시작 (크롤한 전체 소스 글에서 필요한 항목들 따기)
        """ 1 추출한 총 페이지 문자열(->driver)을 가지고 BeautifulSoup이 지정한 데이타 형태(파싱용)로 문자열 soup에 저장"""
        soup = BeautifulSoup(driver.page_source, "html.parser") #파싱용으로 형태 정해 soup에 다시 내용 넣기
        
        """2 가져온 소스코드 중 특정 메시지 1건 (예 혼밥 개인 글 1건(제목 저자 시간 내용등의 1뭉치) 잘라오기
             이 내용은 각각 div class =" "형태로 구성되고 이때 원하는 내용의 소스 코드에서 " "에 해당 내용을 이용해 찾을 수 있다.
             네이버는 list_search_post 임(이것 직접 네이버에서 소스코드 보고 확인해야 함)
             소스코드에서 원하는 곳 커서로 찾고 해당 소스 코드에서 <div class=의 " ...." 부분을 아래 list_serach_post에 교체할 것"""
        # 개인글 1건 찾아 link에 담기 
        link = soup.find_all("div", {"class":"list_search_post"}) #(해당하는 글 시작 부분 상응하는 전체  클라스 "list_search_post" 안의 내용을 find_all로 찾아 link에 넣기
        for posts in link:  #link에 있는 한건 글을 post 넣기

            time.sleep(0.33)
            
            #첫번째 뽑을 내용 찾아서 FIELD1에 넣기
            z = str(posts) #글을 스트링으로 변환해 z담기 
            url = hyperlink.search(z).group(1).strip() # 특정 url 다시 만들고 
            Field1 = maintitle.search(z).group(1).strip() #메인타이틀을 field1에 넣기

                #검색 키워드가 bold 처리되어 있으면 소스코드에 strong 표시 나오는데 이것 제거 
            if '<strong class="search_keyword">' in Field1:
                
                m = re.search(r'(.*)<strong class="search_keyword">(.*)</strong>(.*)', Field1)
                Field1 = m.group(1) + m.group(2) + m.group(3)


            introURL = urllib.request.urlopen(url) 
            soupURL = BeautifulSoup(introURL, "html.parser") 
            linkURL = soupURL.find_all("span", {"class":"title"}) # 블로그 제목 부분 주소 linkURL에 넣기.
            """소스코드 보고 제목 부분이 <span class="title" ng....="post.title" 나오는 부분인 경우 TITLE을 넣은 것. 이것 변형해야 함. 다음은 TIT) """

                       
            #두번째, 세번째 추출 항목을 각 Field2, FIELD3등에 넣기 (r'<em class="name_Field2">(.*)</em>.*' 에서 바로 사이에 있는 데이터 추출 가능 
            Field2=Field2RE.search(z).group(1).strip() 
            Field3=Field3RE.search(z).group(1).strip()
            """ 변경할 것 4, 5번째 항목 넣을 려면 위에서 범위 지정 부분 넣고 여기에서 추가하면 됨)"""

            """ 추출한 항목들을 INFORMATIONㅇ라는 변수에 담고  """
            information = [Field1, Field2, Field3]

            #print(Field1) 디버깅용 (추출 내용 화면 출력하기)
            #print(Field2)
            #print(Field3)
            writer.writerow( [information] ) # 추출 정보 메트릭스 내용 쓰기
Share this post: