Selenium 와디즈 크롤링

<프론트>/크롤링|2020. 12. 15. 23:33
반응형

<실행순서>

  1.  와디즈 상품 하나하나 클릭해보는 방식으로 열고닫고 방식으로 제목+내용+카테고리 긁어오기 (상품30개만)
  2. 와디즈가 무한 스크롤 방식이라 총 상품개수를 알수 없음. -> 클릭은 하지 않고 해당 카테고리 상품리스트를 훝는 방식으로 제목+ 상품url 긁어와서 전체 상품 리스트를 만듬(총몇개인가 확인) 
  3. 스크롤을 바닥까지 끌어온다음(30초) 1번 방식으로 하나하나 클릭했다 뒤로갔다 반복하면서 전체 긁어오기 --> (치명적인 문제점 발생 )미친듯이 느리다
  4. 속도개선 -> (((((((((((( IP 차단당함 ))))))))))))))      (ip 우회전에는 120개쯤 긁어오면 귀신같이 연결이 끊어졌는데 ip우회 후에는 300-500개쯤 긁어오면 끊겼다...)
  5. IP우회 + 멀티프로세서 사용 + (2)에서 만든 상품리스트 url을 리스트로 불러와 차례차례 접근 +속도 개선조건들 추가  
  6. time.sleep()을 0.3초로 빨리 하면 빨리 긁어오는데 미처 못긁어온 결측치 데이터가 많이지고(3000개중 1000개 title,body 군데군데 누락) 1분정도로 하면 놓치는 데이터가 현저히 줄어드는대신 속도가 많이 느려진다... 누락된데이터를 다시 모아서 마지막으로 한번더 돌려준다.

 

 

 

 

1. 와디즈 상품 하나하나 열어서 제목+내용+카테고리 긁어오기 (상품30개만)

- 패션/잡화 카테고리 부분 하나하나 클릭해서 열고 제목/본문/카테고리 긁어오기 

!pip install selenium
from selenium import webdriver
driver = webdriver.Chrome(executable_path= r"C:\chromedriver_win32\chromedriver.exe") #다운받은 크롬드라이버.exe위치
driver.get("https://www.wadiz.kr/web/wreward/category/288?keyword=&endYn=ALL&order=recommend") #크롤링할사이트

import time
wadiz_body=[]
wadiz_title=[]
wadiz_category=[]

table = driver.find_element_by_class_name('ProjectCardList_container__3Y14k') #상품들을 포함하는 껍데기 클래스(위사진참조)
rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa") # 열 하나=상품하나 (위사진참조)
#똑같은 클래스네임가진 열들 줄줄이 많이존재(위사진참조)

for i in range(1,31): #30번만 실행
    table = driver.find_element_by_class_name('ProjectCardList_container__3Y14k') #표 전체
    rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa")
    rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa")[i]
    rows.click()
    time.sleep(3) 
    
    # 본문내용 긁어서 list인 wadiz_body에 집어넣기
    #https://stackoverflow.com/questions/49900117/python-selenium-list-object-has-no-attribute-text-error?noredirect=1&lq=1
    body = driver.find_elements_by_xpath(f'//*[@id="introdetails"]/div') #본문내용 xpath, 마우스 우클릭 copy-xpath복사
    for value in body:  #body가 <P></P>형태로 굉장히 줄줄이 있어서 for문으로 해결
        #print(value.text)
        wadiz_body.append(value.text) #리스트에 줄줄이 집어넣기
        
    # 제목내용 긁어서 wadiz_title에 집어넣기
    title = driver.find_element_by_xpath(f'//*[@id="container"]/div[3]/h2/a')  #제목 xpath
    wadiz_title.append(title.text)
    
    #카테고리 긁어서 wadiz_category에 집어넣기
    category = driver.find_element_by_xpath(f'//*[@id="container"]/div[3]/p') #카테고리 Xpath
    wadiz_category.append(category.text)
    
    time.sleep(2) 
        
    button = driver.find_element_by_class_name('back-btn')
    button.click()
    time.sleep(2) 

timesleep(3)으로 했더니 너무 느려서 0.3이나 0.2정도 해주는것이 적당하다.

import pandas as pd
import numpy as np
df1=pd.DataFrame({'title':wadiz_title,'body':wadiz_body,'category':wadiz_category})
# wadiz_title, wadiz_body, wadiz_category이렇게 3개의 열을 가진 표를 dataFrame으로 만든다
df1
len(df1) #총 몇갠지 출력
import csv
df1.to_csv("wadiz.csv", mode='w',encoding='utf-8-sig')
#쥬피터로 실행하면 실행하는 파일안에 csv파일 생성됨/ utf안해주면 한글깨짐

 

기타 연습한것~~!!

import time
title = driver.find_element_by_class_name('ProjectCardList_item__1owJa')
print(title.text)
title.click() #클릭
body = driver.find_element_by_class_name('inner-contents')
print(body.text) #본문내용출력
button = driver.find_element_by_class_name('back-btn')
button.click() #뒤로가기
driver.back() #뒤로가기2
table = driver.find_element_by_class_name('ProjectCardList_list__1YBa2') 
print(table.text)
# 현제 웹페이지 url추출
url = driver.current_url
print(url)

핵심!!

table = driver.find_element_by_class_name('ProjectCardList_container__3Y14k') #표 전체
rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa")[5] 
#똑같은 클래스 이름 가진 열들중 6번째 열, 즉 6번째 상품 클릭
rows.click()

 

2. 무한 스크롤 돌리기 (총상품개수 제목+url만 리스트로 뽑기)

0.3초 간격으로 for문돌리면 1분도 안되서 바닥까지 도달한다.

 

와디즈는 스크롤 방식이지만, 잘 뜯어보면 아래 분명히 더보기 버튼이 숨겨져있다. 

::after로 숨겨져있는 부분이 스크롤을 하면 뒤에 주르륵 새롭게 나타나는 방식이다. 

 

어느순간 클릭이 안된다고 에러가 난다. 바닥에 도착한것이다

(끝나고 스크롤을 맨 밑으로 내려서 더보기버튼을 누르면 눌리지않고 반응도 없다)

 

from selenium import webdriver
driver = webdriver.Chrome(executable_path= r"C:\chromedriver_win32\chromedriver.exe") #다운받은 크롬드라이버.exe위치
driver.get("https://www.wadiz.kr/web/wreward/category/288?keyword=&endYn=ALL&order=recommend") #크롤링할사이트
import time
try:
    for i in range(1000000000000):
        button = driver.find_element_by_xpath(f'//*[@id="main-app"]/div[2]/div/div[5]/div[2]/div[2]/div/button') #더보기버튼 xpath
        time.sleep(0.3)
        driver.execute_script("arguments[0].click();", button) #click()으로 에러가나서 써줌
        
except : 
    button = driver.find_element_by_class_name
    button.click()  
#다된거같은데 끝이안나면 그냥 중지눌러주면 된다
table = driver.find_element_by_class_name('ProjectCardList_container__3Y14k') #표 전체
rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa")

for index, value in enumerate(rows):  #enumerate는 리스트가 있는 경우 순서와 리스트의 값을 전달하는 기능
    title=value.find_element_by_class_name("CommonCard_title__1oKJY")
    wadiz_title.append(title.text) 

    url=value.find_element_by_class_name("CardLink_link__1k83H")
    url1=value.get_attribute('href')
    wadiz_url.append(url1)
    time.sleep(0.3)
import pandas as pd
import numpy as np
df1=pd.DataFrame({'title':wadiz_title})  # 열이름을 title로 해주고 표형식으로 보기좋게 만듬
len(df1) #총상품개수 몇갠지 출력
import csv
df1.to_csv("wadiz.csv", mode='w',encoding='utf-8-sig')  #csv파일로 내보냄 앞에도 설명똑같은거있음

 

3. 무한 스크롤 돌린다음 모든상품 제목+내용+url 긁어오기 (하나하나 클릭해서 열고닫는 방식 ->무지무지 느림)

import time
# 바닥까지 무한 스크롤
try:
    for i in range(1000000000000):
        button = driver.find_element_by_xpath(f'//*[@id="main-app"]/div[2]/div/div[5]/div[2]/div[2]/div/button')
        time.sleep(0.3)
        driver.execute_script("arguments[0].click();", button)
except : 
    button = driver.find_element_by_class_name
    button.click()
   
import time
wadiz_body=[]
wadiz_title=[]
wadiz_url=[]

table = driver.find_element_by_class_name('ProjectCardList_container__3Y14k') #표 전체
rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa") # 열 하나
#똑같은 클래스네임가진 열들 줄줄이 많이존재

for i in range(1,4000): 
    table = driver.find_element_by_class_name('ProjectCardList_container__3Y14k') #표 전체
    rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa")
    rows = table.find_elements_by_class_name("ProjectCardList_item__1owJa")[i]
    rows.click()
    time.sleep(4) 
    
    # 본문내용
    #https://stackoverflow.com/questions/49900117/python-selenium-list-object-has-no-attribute-text-error?noredirect=1&lq=1
    body = driver.find_elements_by_xpath(f'//*[@id="introdetails"]/div')
    for value in body:
        #print(value.text)
        wadiz_body.append(value.text)
        
    # 제목
    title = driver.find_element_by_xpath(f'//*[@id="container"]/div[3]/h2/a')
    wadiz_title.append(title.text)
    
    #카테고리
    #category = driver.find_element_by_xpath(f'//*[@id="container"]/div[3]/p')
    #wadiz_category.append(category.text)
    
    url = driver.current_url
    wadiz_url.append(url)
    
    time.sleep(0.3) 
        
    button = driver.find_element_by_class_name('back-btn')
    button.click()
    time.sleep(5) 

**time.sleep은 알아서 바꿔주기

 

4. 앞서 2번에서 뽑은 전체상품 리스트 url로 접근해서 긁어오기 + 멀티프로세싱 + 속도 최적화 + IP우회

 

속도개선을 위한 조건을 추가해줬다 

from selenium import webdriver
# from selenium.webdriver.common.keys import Keys
# from selenium.webdriver.common.action_chains import ActionChains

options = webdriver.ChromeOptions() # 크롬 옵션 객체 생성
options.add_argument('headless') # headless 모드 설정
options.add_argument("window-size=1920x1080") # 화면크기(전체화면)
options.add_argument("disable-gpu") 
options.add_argument("disable-infobars")
options.add_argument("--disable-extensions")

# 속도 향상을 위한 옵션 해제
prefs = {'profile.default_content_setting_values': {'cookies' : 2, 'images': 2, 'plugins' : 2, 'popups': 2, 'geolocation': 2, 'notifications' : 2, 'auto_select_certificate': 2, 'fullscreen' : 2, 'mouselock' : 2, 'mixed_script': 2, 'media_stream' : 2, 'media_stream_mic' : 2, 'media_stream_camera': 2, 'protocol_handlers' : 2, 'ppapi_broker' : 2, 'automatic_downloads': 2, 'midi_sysex' : 2, 'push_messaging' : 2, 'ssl_cert_decisions': 2, 'metro_switch_to_desktop' : 2, 'protected_media_identifier': 2, 'app_banner': 2, 'site_engagement' : 2, 'durable_storage' : 2}}   
options.add_experimental_option('prefs', prefs)

driver = webdriver.Chrome(executable_path= r"C:\chromedriver_win32\chromedriver.exe", options=options)
driver.get("https://www.wadiz.kr/web/wreward/category/288?keyword=&endYn=ALL&order=recommend")
driver.maximize_window()

 

 

속도는 개선됬는데 와디즈에서 차단당했다...... 

몇시간을 구글링하고 플러그인 결제까지해서 뻘짓을 해본 결과 제일 빠르고 안정적인 우회1방법을 찾았다 ( 윈도우 기준)

blog.naver.com/PostView.nhn?blogId=zzz90zzz&logNo=222026663292참조

 

 

The Tor Project | Privacy & Freedom Online

Defend yourself against tracking and surveillance. Circumvent censorship.

www.torproject.org

여기서 tor다운받고 실행해주고 + 아래코드를 활용할것이다. 

어째 tor을 쓰고나서 네트워크가 더 안정적이어진것같다

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
for i in range(1):
    chrome_options = Options()
    chrome_options.add_argument("--proxy-server=socks5://127.0.0.1:9150")
    driver = webdriver.Chrome(executable_path=' 내 PATH ', options=chrome_options)
    driver.get('웹사이트')

 

 

(2)에서 받아와 저장해둔 url.csv를 다시 불러와서 리스트로 만들어준다.

import pandas as pd
from pandas import Series,DataFrame
import numpy as np
data = pd.read_csv("./wadiz_title_url_f.csv")
data2=data['url']
one = data2.values.tolist() 

# one이라는 이름의 url 리스트 생성완료 / one 치고 실행해보면 리스트안에 url들 잘들어갔나 확인가능하다
len(one)  #3000여개가 나온다
#이부분은 한꺼번에가 아닌 나눠서 크롤링하려고 만들었다. 
#네트워크 상태에 따라서 120개 긁고 멈출때도 있고 500여개 긁고 멈춘일이 매우 다반사라서
#구간을 정해놓고 긁어오기를 시도한다. 중간에 끊기면 Two 리스트 구간만 바꿔서 다시 시도해주면 된다
#중간중간 끊어서 실행해주면 봇으로 의심받아서 차단당할 확률도 줄어든다

two=[]
two=one[464:900]
# 아이피우회 + 최적화...
# headless옵션을 주면 속도는 확실히 빠른데 오류가 잦아져서 뺐다.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

for i in range(1):
    chrome_options = Options()
    chrome_options.add_argument("--proxy-server=socks5://127.0.0.1:9150")   
    prefs = {'profile.default_content_setting_values': { 'images': 2, 'popups': 2, 'geolocation': 2, 'notifications' : 2, 'auto_select_certificate': 2, 'fullscreen' : 2, 'mouselock' : 2, 'mixed_script': 2, 'media_stream' : 2, 'media_stream_mic' : 2, 'media_stream_camera': 2, 'protocol_handlers' : 2, 'ppapi_broker' : 2, 'automatic_downloads': 2, 'midi_sysex' : 2, 'push_messaging' : 2, 'ssl_cert_decisions': 2, 'metro_switch_to_desktop' : 2, 'protected_media_identifier': 2, 'app_banner': 2, 'site_engagement' : 2, 'durable_storage' : 2}}   
    chrome_options.add_experimental_option('prefs', prefs)
    driver = webdriver.Chrome(executable_path=r"C:\chromedriver_win32\chromedriver.exe", chrome_options=chrome_options)
    driver.get("https://www.wadiz.kr/web/wreward/category/288?keyword=&endYn=ALL&order=recommend")
wbody=[]
wtitle=[]
wurl=[]
import requests
import time
from multiprocessing import Pool # Pool import하기


def mul():
    for i in two :
        driver.get(i)
        time.sleep(0.4) 
        # 본문내용
        #https://stackoverflow.com/questions/49900117/python-selenium-list-object-has-no-attribute-text-error?noredirect=1&lq=1
        body = driver.find_elements_by_xpath(f'//*[@id="introdetails"]/div')
        for value in body:
            #print(value.text)
            wbody.append(value.text)
        
        # 제목
        title = driver.find_element_by_xpath(f'//*[@id="container"]/div[3]/h2/a')
        wtitle.append(title.text)
        
        #카테고리
        #category = driver.find_element_by_xpath(f'//*[@id="container"]/div[3]/p')
        #wadiz_category.append(category.text)
    
        url = driver.current_url
        wurl.append(url)
    
    
if __name__=='__main__':
    pool = Pool(processes=32) # 32개의 프로세스를 사용합니다.
    pool.map(mul()) # mul 함수를 넣어줍시다.
len(wurl)
len(wbody)
len(wtitle)
#세명령어로 3개숫자가 같은지 확인 -> 숫자가 같지않으면 표가 만들어지지않음
# csv파일로 저장저장~

import pandas as pd
import numpy as np
import csv
df1=pd.DataFrame({'title':wtitle,'body':wbody,'url':wurl})
df1.to_csv("wadiz_1.csv", mode='w',encoding='utf-8-sig')

5. 결측치데이터 모아서 다시 돌려주기

import pandas as pd
from pandas import Series,DataFrame
import numpy as np

data1 = pd.read_csv("./wadiz_1.csv")
data2 = pd.read_csv("./wadiz_2.csv")
data3 = pd.read_csv("./wadiz_3.csv")
data4 = pd.read_csv("./wadiz_4.csv")

온전한 데이터들 모아서 하나로 합쳐주기

data1.info() #결측치값 확인
data1.dropna(inplace=True) #결측치 포함된 열 지워버리기
f=[data1,data2,data3,data4]
dt = pd.concat(f)
import csv
dt.to_csv("wadiz_11.csv", mode='w',encoding='utf-8-sig') #온전한 데이터들 다시모아서 하나로 합치기

 

결측치값 모아서 url리스트로 바꿔줘서 다시 돌리기

data1=data1.fillna("miss") #결측치 miss 스트링열로 바꿔치기
d1=data1[data1['body'] == 'miss'] ## df[조건식] 
d1=data1[data1['title'] == 'miss'] ## df[조건식]  # 내용, 제목 결측치 합친건데 교집합 안뺀 합집합

d1 = d1.drop_duplicates('url', keep='first')   #교집합 뺴주기
d2 = d2.drop_duplicates('url', keep='first')

d1=d1['url']
one = d1.values.tolist() #url만 뽑아서 리스트로 만들어주기

miss_list = one + two + thr + fou #리스트 하나로 합치기

그리고 나서 3번이랑 똑같이 셀레니움 새창 띄우고 리스트를 돌려서 다시긁어주고 반복!

반응형

댓글()