전 시간에는 파이썬에서 셀레니움의 라이브러리를 불러와 드라이브를 호출 하여 네이버를 연결하는 작동법 까지 포스팅을 해 봤습니다.
이전 포스팅은 이 포스팅 제일 아래 링크를 연결해 두겠습니다.
이번 포스팅 에서는 검색어를 입력 후 조회 된 페이지를 크롤링 하여 필요한 데이터를 수집하여 데이터화 하는 방법을 구현해 보도록 하겠습니다.
대신 한정적으로 "VIEW" 탭의 첫 페이지만 크롤링 해 보도록 하겠습니다.
조회를 하게 코딩 해 봅니다.
1. 네이버 메일 화면에서 검색 어 입력하는 input 박스의 name 또는 id 를 확인 합니다.
1-1. 네이버 웹사이트 화면에서 F12 를 눌러 개발자 툴을 엽니다.
개발자 툴에서 왼쪽 편에 보면 아래오 같은 아이콘이 생성이 되고 화면에서 검색어 창을 선택 할 수 있게 된다.
마우스 클릭을 하게 되면 검생어 입력 input 의 정보를 개발자 툴에서 보여 준다.
둘다 같습니다.
이제 셀레니움에서 이 input에 "나이키" 를 입력 하게 합니다.
위에 프로그램을 실행 하게 되면 아래 처럼 나이키를 검색 하게 됩니다.
이제 VIEW탭으로 이동을 해서 조회된 첫 페이지 대상들을 변수에 담아 보겠습니다.
뷰 탭으로 이동 할때는 xpath 를이용한 이동을 해보도록 하겠습니다.
어려운거 없이 개발자 도구에서 view 탭의 xpath를 복사해서 셀레니움에 복사한 xpath 를 넣어 주기만 하면 이동이 됩니다.
초록생경로가 xpath 경로 입니다.
자 이제 view 탭의 첫 페이지 리스트 대상을 변수에 입력해 보겠습니다.
view 탭은 sc_new sp_nreview _au_view_tab _svp_list _prs_rvw 이란 큰 클래스에 각 포스팅들이 나열이 되어 있습니다.
그 아래로 list 클래스로 묶인 포스팅 리스트가 있습니다.
제일 중요한 li 테그의 bx _svp_item 클래스 의 data-cr-rank 속성들이 1부터 증가를 하는 것으로 확인이 됩니다.
1페이지당 30포스팅 까지 발생을 하고 추가적으로 발생되는건 + 30건씩 조회가 되는 것을 확인 했습니다.
그러면 반복문을 1부터 30까지 발생시켜 해당 url을 추출 하고 이동하여 테스트를 추출 합니다.
텍스트를 추출 하는 건 beautifulsoup 를 이용하여 진행 합니다.
웹상의 택스트를 정형화 하여 추출 하는것을 도와 주는 모듈 입니다.
url 접속을 도와주는 requests 모듈도 설치 한다.
전체 소스 코드는 아래와 같습니다.
카페, 블로그, 포스트 로 이루어진 VIEW 탭은 각기 별로 분기처리하는 로직이 필요하여 소스가 지저분해져 있습니다.
정형화 하고 함수로 정의 하는 부분은 나중에 정리해서 따로 포스팅 하도록 하겠습니다.
from cgitb import text
import selenium
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from time import sleep
from bs4 import BeautifulSoup
from urllib.parse import quote
import requests
import time
#접속 url
URL_TMP = ''
#검색어
SEARCHWORD = "나이키"
#찾을 단어
MACHINGWORD = "버블검"
# 조회 한 페이지의 피드 리스트 저장할 리스트 선언
POSTINGLIST = list()
# 저장할 파일
f = open('C:/dev/test.txt', 'w', encoding='utf-8')
driver = webdriver.Firefox(executable_path='C:\dev\python\geckodriver.exe')
#driver = webdriver.Chrome(executable_path='C:\dev\python\chromedriver.exe')
driver.set_window_position(0, 0)
driver.set_window_size(100, 1000)
#네이버로 이동
driver.get(url=URL)
#사이트이름 매칭 확인
assert "NAVER" in driver.title
#input id = query, name = query -> "나이키 입력"
#searchName = driver.find_element_by_id("query")
searchName = driver.find_element_by_xpath("//*[@id='query']")
searchName.send_keys(SEARCHWORD)
searchName.submit()
#view 탭으로 이동 한다.
driver.implicitly_wait(100)
viewChage = driver.find_element_by_xpath("/html/body/div[3]/div[1]/div/div[2]/div[1]/div/ul/li[2]/a")
print(viewChage.text)
viewChage.click()
#반복
# 첫페이지에서 조회된 대상을 변수에 저장한다.
# 첫 페이지 대상은 1부터 30까지의 대상이다.
# 20210117 기준 xpath 는 /html/body/div[3]/div[2]/div/div[1]/section/div/div[2]/panel-list/div/more-contents/div/ul/li[1]/div[1]/div/a
# 여기서 li의 [n]번 값이 증가 한다.
#for n in range(1, 31):
for n in range(1, 31):
pth_tmp = "/html/body/div[3]/div[2]/div/div[1]/section/div/div[2]/panel-list/div/more-contents/div/ul/li[{0}]/div[1]/div/a".format(n)
#print(pth_tmp)
POSTINGLIST.append(pth_tmp)
print("-"*50)
for i in POSTINGLIST:
driver.switch_to.window(driver.window_handles[0])
postSearch = driver.find_element_by_xpath(i) # 1~30까지 포스팅 페이지를 담는다.
print(postSearch.get_attribute("href"))
URL_TMP = postSearch.get_attribute("href")
postSearch.click() # 이동한다.
driver.implicitly_wait(100) # 로딩될때까지 대기
webpage = requests.get(postSearch.get_attribute("href"))
soup = BeautifulSoup(webpage.content, "html.parser")
print("-"*50)
#url이 블로그일 경우
if "blog.naver" in postSearch.get_attribute("href"):
print("블로그")
print("encoding = " + webpage.encoding)
webpage.encoding = 'UTF-8'
soup = BeautifulSoup(webpage.content, "html.parser")
if soup.find("div", attrs={"class":"se-main-container"}):
text = soup.find("div", attrs={"class":"se-main-container"}).get_text()
text = text.replace("\n","") #공백 제거
print("블로그")
print(text)
elif soup.find("p", attrs={"class":"se_textarea"}):
text = soup.find("p", attrs={"class":"se_textarea"}).get_text()
text = text.replace("\n","") #공백 제거
print("블로그")
print(text)
elif soup.find("div", attrs={"class":"ArticleContentBox"}):
text = soup.find("div", attrs={"class":"ArticleContentBox"}).get_text()
text = text.replace("\n","") #공백 제거
print("블로그")
print(text)
elif soup.find("div", attrs={"id":"postViewArea"}):
text = soup.find("div", attrs={"id":"postViewArea"}).get_text()
text = text.replace("\n","") #공백 제거
print("블로그")
print(text)
else:
print("블로그 확인불가")
text = soup
f.write('블로그\n')
f.write(str(text))
f.write('\n')
#url이 post일 경우
elif "post.naver" in postSearch.get_attribute("href"):
print("포스트")
#print(soup)
print(postSearch.get_attribute("href"))
webpage = requests.get(postSearch.get_attribute("href"))
print("encoding = " + webpage.encoding)
soup = BeautifulSoup(webpage.content, "html.parser", from_encoding='ANSI')
f.write("포스트11111111111111111111111\n")
f.write(postSearch.get_attribute("href") + "\n")
f.write(str(webpage.encoding))
f.write('\n')
f.write("포스트22222222222222222222222\n")
if soup.find("div", attrs={"class":"se-main-container"}):
text = soup.find("div", attrs={"class":"se-main-container"}).get_text()
text = text.replace("\n","") #공백 제거
print("포스트1")
print(text)
elif soup.find("p", attrs={"class":"se_textarea"}):
text = soup.find("p", attrs={"class":"se_textarea"}).get_text()
text = text.replace("\n","") #공백 제거
print("포스트2")
print(text)
elif soup.find("div", attrs={"class":"ArticleContentBox"}):
text = soup.find("div", attrs={"class":"ArticleContentBox"}).get_text()
text = text.replace("\n","") #공백 제거
print("포스트3")
print(text)
elif soup.find("div", attrs={"id":"postViewArea"}):
text = soup.find("div", attrs={"id":"postViewArea"}).get_text()
text = text.replace("\n","") #공백 제거
print("포스트4")
print(text)
elif soup.find("div", attrs={"class":"se_component_wrap"}):
text = soup.find("div", attrs={"class":"se_component_wrap"}).get_text()
text = text.replace("\n","") #공백 제거
print("포스트5")
print(text)
elif soup.find("div", attrs={"id":"cont"}):
text = soup.find("div", attrs={"id":"cont"}).get_text()
text = text.replace("\n","") #공백 제거
print("포스트6")
print(text)
else:
print("포스트 전체 조회")
text = soup
print(text)
f.write("포스트 확인불가\n")
f.write(postSearch.get_attribute("href") + "\n")
f.write(str(text))
f.write('\n')
#url이 cafe일 경우
elif "cafe.naver" in postSearch.get_attribute("href"):
print("카페")
#print(soup)
#탭이동
driver.switch_to.window(driver.window_handles[1])
print("tap1 이동 완료")
#print(driver.page_source)
#f.write("11111111111111111111111111111카페\n")
#f.write(driver.page_source + "\n")
#f.write('\n')
print("cafe_main 로딩시작")
#cafe_main 로딩 완료 대기
#driver.implicitly_wait(10)
time.sleep(10)
print("cafe_main 로딩완료")
driver.switch_to.frame("cafe_main") # cafe_main iframe으로 이동
print("cafe_main frame 이동")
#print(driver.page_source)
#f.write("22222222222222222222222222222카페\n")
#f.write(driver.page_source + "\n")
#f.write('\n')
driver.implicitly_wait(1)
req_tmp = driver.page_source
print("페이지 확인")
#print(driver.page_source)
#f.write("33333333333333333333333333카페\n")
#f.write(driver.page_source + "\n")
#f.write('\n')
soup = BeautifulSoup(req_tmp, "html.parser", from_encoding='ANSI')
#print(soup)
#webpage = requests.get(postSearch.get_attribute("href"))
#print("encoding = " + webpage.encoding)
#soup = BeautifulSoup(webpage.content, "html.parser", from_encoding='ANSI')
if soup.find("div", attrs={"class":"se-main-container"}):
text = soup.find("div", attrs={"class":"se-main-container"}).get_text()
text = text.replace("\n","") #공백 제거
print("카페1")
print(text)
elif soup.find("p", attrs={"class":"se_textarea"}):
text = soup.find("p", attrs={"class":"se_textarea"}).get_text()
text = text.replace("\n","") #공백 제거
print("카페2")
print(text)
elif soup.find("div", attrs={"class":"ArticleContentBox"}):
text = soup.find("div", attrs={"class":"ArticleContentBox"}).get_text()
text = text.replace("\n","") #공백 제거
print("카페3")
print(text)
elif soup.find("div", attrs={"id":"postViewArea"}):
text = soup.find("div", attrs={"id":"postViewArea"}).get_text()
text = text.replace("\n","") #공백 제거
print("카페4")
print(text)
elif soup.find("div", attrs={"class":"se-component-content"}):
text = soup.find("div", attrs={"class":"se-component-content"}).get_text()
text = text.replace("\n","") #공백 제거
print("카페5")
print(text)
else:
print("카페 확인불가")
text = soup
f.write("카페\n")
f.write(postSearch.get_attribute("href") + "\n")
f.write(str(text))
f.write('\n')
if MACHINGWORD in text:
print("Found word " + MACHINGWORD)
#print(postSearch.get_attribute("href"))
driver.implicitly_wait(100) # 로딩될때까지 대기
driver.switch_to.window(driver.window_handles[1])
driver.close()
else:
print("Not Found word " + MACHINGWORD)
#print(postSearch.get_attribute("href"))
driver.implicitly_wait(100) # 로딩될때까지 대기
driver.switch_to.window(driver.window_handles[1])
driver.close()
print("-"*50)
driver.quit()
f.close()
# 리스트의 url n번째 로 이동 하여 "트레비스스캇" 단어를 찾는다.
# 단어가 일치하는 대상이 있다면 변수에 url 을 담는다.
# 단어가 일치하면 count 를 한다.
# 다시 view 탭으로 이동한다.