ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [셀레니움 크롤링 예제] 다나와 리뷰 크롤링을 위한 지속가능한 코드 만들기 (1)
    직접 해보기/Python 2024. 6. 7. 03:10
    728x90
    반응형

     

    다나와 크롤링 예제 — 공기청정기 인기3사 제품정보 수집하기


    ✅  셀레니움, 크롬드라이버 설치 전이거나 기본 사용법을 익히기 전이라면,

    설치 완료하기! 기본 사용법 익혀보기!

     

    0️⃣  다나와에서 [공기청정기] 카테고리만 선택해서 크롤링해볼게요.

    • 다나와는 친절하게도 카테고리별 URL을 따로 챙겨주시네요.
    • 이걸 복사해와서 driver.get(url) 안에 넣겠습니다. 아래 코드를 실행하면 다나와 공기청정기 카테고리로 이동합니다.

    # 필요한 패키지 가져오기
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    from bs4 import BeautifulSoup
    import time
    import math
    import pandas as pd
    import pickle
    
    
    # 다나와 공기청정기 카테고리로 이동
    url = "https://prod.danawa.com/list/?cate=10352481&searchOption=/innerSearchKeyword="
    driver.get(url)

     


    1️⃣  공기청정기 인기3사인 LG전자, 삼성전자, 위닉스만 선택해서 제품을 필터링하겠습니다.

    • 경쟁사를 정해놓고 제품정보를 크롤링하는 상황으로 가정하겠습니다.
    • 현재 분석타겟 제조사는 LG전자, 삼성전자, 위닉스 3사입니다. 제조사 필터에서 이 3가지만 선택해야합니다.
    • 어느정도 "지속가능한 코드 만들기"가 목표니까요, 나중에 타겟 제조사를 바꿔서 다시 분석할 경우를 대비해서,
      제조사 이름을 입력하면 → 체크박스를 클릭해주는 흐름으로 코드를 구성하고 싶어요.

     

     

    • HTML을 살펴보고 [제조사별] 부분의 XPath를 카피해서 find_elements 메소드로 내용을 가져와봤습니다. 
    • 아래와 같이 내용을 가져올 수는 있지만 리스트 길이가 1입니다.
      이 경로로 가져오면 리스트로 가져온게 소용이 없고.. 다 합쳐져서 가져와지네요.

     

    • HTML을 다시 살펴볼게요. 하위에 li class="sub item" 이 5개 존재하고, 이게 각각 제조사별 체크박스에 해당하네요!
    • 이 부분의 XPATH를 카피하면 끝에 li[숫자]가 있습니다. //*[@id="dlMaker_simple"]/dd/ul[1]/li[1]
      [숫자] 부분을 지우면 리스트를 제대로 가져올 수 있을 것 같아요.

     

     

    • 제조사 리스트 가져오기 성공! 리스트 길이가 5니까 제조사별로 각각 떼어서 가져오는걸 성공했어요~
    • 이 리스트 요소 중에서 'LG전자', '삼성전자', '위닉스'에 해당하는 경로를 각각 찾아서, 체크박스를 클릭할 수 있어요.

     

    • 이제 이 리스트 요소 중에서 'LG전자', '삼성전자', '위닉스'에 해당하는 각 경로를 가져와서, 체크박스를 클릭할 수 있습니다.
    • 에어컨, 세탁기 등 다른 카테고리 페이지에서도 이부분은 HTML구성이 동일합니다! 같은 코드로 체크박스 클릭이 가능하네요.
      나중에 다른 제품 크롤링할때도 같은 코드로 써먹을 수 있을 것 같아요!

     

     

    • 위에서 밝혔듯이 제조사 이름을 넣으면 → 체크박스를 클릭하는 함수를 만들어서 크롤링 코드 맨 앞에 넣어줄게요.
    • 이러면 나중에 분석타겟 제조사를 바꿔도, 제조사 이름만 바꿔넣으면 문제없이 크롤링할 수 있겠죠. 또 코딩할 필요 없이요.
      혹은 코드가 초면인 사람에게, 코드를 주면서 다나와 링크랑 경쟁사 이름 넣어서 실행하면 돼요~ 라고 전달할 수 있을거에요.
      모든건 나중의 나자신을 위한 노가다와 준비입니다..
    def manufacturer_checkbox(target_list): # 함수 입력값: 타겟 제조사 리스트
        
        # 제조사별 부분 XPath 리스트로 가져오기
        manufacturer_list = driver.find_elements(By.XPATH, '//*[@id="dlMaker_simple"]/dd/ul[1]/li')
        
        # 타겟 제조사 체크박스 하나씩 클릭하기
        for target in target_list:
            for m in manufacturer_list:
                if target in m.text:
                    m.click()
                    break
                    
        print(str(target_list), '선택 완료')

     

     

     

     

     


    2️⃣  이제 제품정보를 크롤링해오려면, 페이지를 하나씩 넘겨야합니다.

    • 총 몇 페이지인지 알아야겠죠. 아래 캡처에서 빨간네모친 총 제품 개수를 가져와서, 총 페이지 수 num_pages 변수를 만들게요.
    # 모델 개수
    num_models = driver.find_element(By.CLASS_NAME, 'list_num').text.strip().replace('(', '').replace(')', '')
    
    # 페이지 개수 (페이지당 보이는 제품은 30개)
    num_pages = math.ceil(int(num_models) / 30))

     

    • 반복문 돌리면서 지금 페이지 내용 긁어온 다음, 다음 페이지 번호를 눌러주는 흐름으로 가야겠습니다.
    • 지금 몇번째 페이지로 넘겨야하는지 나타내는 page 변수를 두고, num_page 와 같아질때까지 while문을 돌릴게요.
    • 주의할 점! 11, 21, 31..번째 페이지로 넘길 때는 그냥 다음 페이지가 아니라, 다음 "화살표 버튼"을 눌러줘야 합니다.
      이 부분이 아래코드에서 if문에 해당합니다. (참고-이상하게 css selector로 가져오지 않으면 에러가 나더라구요..)
    • 하나더 주의! 한 페이지 끝날때마다 time.sleep으로 잠시 "대기"가 필요합니다.
      잠깐 로딩을 기다려주지 않으면 요소를 찾을 수 없다는 에러가 계속나왔어요. (참고-driver.implicitly_wait도 안통했음.)
    # 페이지 변수 생성, 시작은 1페이지부터
    page = 1
    
    # page에 1씩 더하면서, 전체 페이지 수와 같아지기 전까지 반복
    while page < num_pages:
    
        page += 1
        
        ### 페이지 크롤링 코드는 여기에 추가될 예정 ###
        
        # 11,21,31..번째 페이지인 경우 [다음 페이지] 버튼 클릭
        if page%10 == 1:
            driver.find_element(By.CSS_SELECTOR, '#productListArea > div.prod_num_nav > div > a').click()
    
        # 나머지 경우는 page에 해당하는 페이지 클릭
        else:
            # 페이지 넘기는 부분 경로 통째로 가져와놓고
            page_nums = driver.find_element(By.XPATH, '//*[@id="productListArea"]/div[4]/div')
            # 다음 페이지 링크를 클릭
            page_nums.find_element(By.LINK_TEXT, str(page)).click()
    
        # 에러나지 않도록 한페이지마다 잠시 대기
        time.sleep(2)

     

     

     

     

     


    3️⃣  이제 페이지마다 제품정보를 크롤링해와서, DataFrame에 저장해주겠습니다.

    • 한 페이지마다 데이터는 BeautifulSoup으로 전부 긁어오겠습니다.
      체크박스랑 페이지 넘길때는 Selenium이 일하고, 한 페이지 안에서는 BeautifulSoup이 일하는 구성이에요.

     

    3️⃣-(1). 가격정보 크롤링은 준비가 필요합니다!

    • 그 전에 문제가 하나 있어요! 아래 캡처를 보시면.. 가격(최저가) 정보가 문제입니다. 
      가격 정보가 1개인 제품이 있고, 2개 3개 여러개인 제품이 있습니다. 가격 정보만 먼저 따로 살펴봐야 겠어요.
    • 제품마다 가격정보가 몇개인지 가져와보고, 가장 많은 것 제품을 기준으로 크롤링해오려고 합니다.
      예를들어 가장 많은 가격정보를 가진 제품이 가격 3개였다면.. 엑셀에서 가격 칼럼을 3개 만들고 싶다는 거죠.
      가격이 1개거나 2개인 제품들은 그냥 셀을 비워두면 되잖아요.

     

     

    • HTML을 살펴보면서.. 가격정보를 어떻게 가져와야 하는지 알아봐야 합니다. 아래처럼 시험삼아 가격정보 1개를 가져와봤어요.
    • 이제 모든 페이지의 모든 제품을 돌려보면서 "가격정보가 가장 많은 제품은 가격정보가 몇개" 인지 알아봐야 합니다.
      아래와 같이.. 위에서 작성했던 페이지 넘기는 반복문 중간에, 가격 리스트 가져오는 부분을 추가하고, 최댓값을 돌려받을게요.
    • 그리고 한페이지 마다 페이지에 있는 모든 제품 데이터들products 변수에 넣고 이걸 딕셔너리에 저장해줄게요.
      사실상 크롤링은 여기서 끝입니다! 이제 딕셔너리에서 데이터를 가져다가 필요한 정보만 뽑아쓰면 됩니다.

    # 가격정보 저장할 빈 리스트 생성
    numofprices_list = []
    
    # 페이지별 소스 저장할 빈 딕셔너리 생성
    soup_dict = {}
    
    page = 1
    
    # page에 1씩 더하면서, 전체 페이지 수와 같아지기 전까지 반복
    while page < num_pages:
    
        # 제품 정보들 전부 가져오기
        soup = BeautifulSoup(driver.page_source)
        products = soup.select('div.prod_main_info')
        time.sleep(1)
        
        # 페이지별 소스 딕셔너리에 저장해두기
        soup_dict[page] = products
    
        # 제품하나씩 돌리면서
        for i in range(len(products)):
            try: # 가격정보 개수 가져오기
                numofprices_list.append(len(products[i].select('div.prod_pricelist li')))
            except:
                numofprices_list.append('')
                
        time.sleep(1)
        print(page, "페이지 완료!")
    
        page += 1
        
        # 11,21,31..번째 페이지로 넘기는 경우 [화살표] 버튼 클릭
        if page%10 == 1:
            driver.find_element(By.CSS_SELECTOR, '#productListArea > div.prod_num_nav > div > a').click()
    
        # 나머지 경우는 page에 해당하는 페이지 클릭
        else:
            # 페이지 넘기는 부분 경로 통째로 가져와놓고
            page_nums = driver.find_element(By.XPATH, '//*[@id="productListArea"]/div[4]/div')
            # 다음 페이지 링크를 클릭
            page_nums.find_element(By.LINK_TEXT, str(page)).click()
            
        # 에러나지 않도록 한페이지마다 잠시 대기
        time.sleep(2)
    
    
    # 마지막 페이지 소스 가져오고 마무리
    soup = BeautifulSoup(driver.page_source)
    products = soup.select('div.prod_main_info')
    soup_dict[page] = products
    print(page, "페이지 완료!")
    
    print("<<< 크롤링 완료입니다! >>>")
    print("가격정보가 가장 많은 경우는", max(numofprices_list), "개 입니다!")

     

     

    3️⃣-(2). 저장해둔 페이지 소스에서 쓸모있는 제품정보만 가져와서, DataFrame으로 합칠게요.

    • 위 코드로 저장해둔 딕셔너리에서, 제품정보를 하나씩 뽑아오면서.. 이제 드디어 쓸모있는 결과물을 만들어줄 차례입니다!
    • 이 부분에선 HTML을 하나씩 살펴보면서.. 어디에 어떤정보가 있는지 직접 가져와야합니다.
    • 본격적으로 BeatifulSoup을 사용하게 되는데, select는 여러개를, select_one은 딱 한개만 찾아오는 메소드입니다.
      각자 Selenium에서 find_elements, find_element와 비슷하죠?
    • select_one으로 가져온 결과물은 날것 그자체이니, 마지막에 .text.strip()을 붙여서 텍스트만 남기는것 잊지마세요!

     

     

    • 위와 같이, 제품1개마다 모델이름, 출시시기, 헤드메시지, 스펙, 리뷰평점, 리뷰개수, 페이지링크, 가격정보를 가져오겠습니다.
    • 이제 for문을 돌리면서, 위 정보들을 리스트에 하나씩 append하고, 마지막에 DataFrame으로 합쳐줄거에요.
    • 아까 뽑아둔 가격정보 최댓값X2 개의 리스트를 만들어서 가격정보도 같이 붙여줄거에요.
      이건 코드랑 결과물 참고해주세요. priceinfo_list_set, price_list_set에 해당합니다.
    • 참고로, 제품에 따라 정보가 없을수도 있으니 try-except를 달아줬습니다. 
      예를들어 n번째 제품에 헤드메시지가 있으면 리스트에 추가하고, 없으면 공백을 추가할 것입니다.
    def crawling_danawa(soup_dict, max_numofprices_list):
        
        # 모델이름, 출시시기, 헤드메시지, 스펙, 리뷰평점, 리뷰개수, 페이지링크 가져올 빈 리스트 생성
        name_list, hm_list, spec_list, release_list, star_list, review_list, link_list = [], [], [], [], [], [], []
        # 가격정보 리스트셋 (ex. 1위 일반구매, 2위 추가필터 포함..)
        priceinfo_list_set = []
        # 최저가 리스트셋 (ex. 100,000원, 120,000원..)
        price_list_set = []
    
        # 최댓값만큼 빈 리스트 생성 (이중리스트)
        for i in range(max_numofprices_list):
            priceinfo_list_set.append([])
            price_list_set.append([])
    
        # 딕셔너리에 저장해둔 페이지 하나씩 돌리기
        for key in range(len(soup_dict)):
            products = soup_dict[key+1]
            
            # 제품마다 하나씩 돌리기
            for i in range(len(products)):
                
                # 모델 이름
                try:
                    name_list.append(products[i].select_one('p.prod_name a').text.strip())
                except:
                    name_list.append('')
                    
                # 모델 출시시기
                try:
                    release_list.append(products[i].select_one('div.prod_sub_info dd').text.strip())
                except:
                    release_list.append('')
                    
                # 헤드 메시지
                try:
                    hm_list.append(products[i].select_one('div.prod_intro').text.strip())
                except:
                    hm_list.append('')
                    
                # 모델 스펙
                try:
                    spec_list.append(products[i].select_one('div.spec_list').text.strip())
                except:
                    spec_list.append('')
                    
                # 리뷰 평점 & 개수
                try:
                    star_list.append(products[i].select_one('div.cnt_star').text.strip().replace('점', ''))
                    review_list.append(products[i].select_one('div.prod_sub_info a').text.strip())
                except:
                    star_list.append('')
                    review_list.append('')
                    
                # 제품페이지 링크
                try:
                    thumbnail = products[i].select_one('div.thumb_image a')
                    link_list.append(thumbnail['href'])
                except:
                    link_list.append('')
                    
                # 가격정보
                pricelist_raw = products[i].select('div.prod_pricelist li')
                
                for p in range(max_numofprices_list):
                    try:
                        priceinfo_list_set[p].append(
                        	pricelist_raw[p].select_one('div.over_preview').text.strip())
                    except:
                        priceinfo_list_set[p].append('')
    
                for p in range(max_numofprices_list):
                    try:
                        price_list_set[p].append(pricelist_raw[p].select_one('p.price_sect a').text.strip())
                    except:
                        price_list_set[p].append('')
    
        # DafaFrame 저장
        df_result = pd.DataFrame({
            '제품모델명' : name_list, '출시시기' : release_list, 
            '리뷰평점' : star_list, '리뷰개수' : review_list,
            '헤드메시지' : hm_list, '스펙' : spec_list, '링크URL' : link_list
        })
    
        for p in range(max_numofprices_list):
            df_result['가격정보_{}'.format(str(p+1))] = priceinfo_list_set[p]
            df_result['최저가_{}'.format(str(p+1))] = price_list_set[p]
    
        return df_result

    크롤링 결과물 데이터프레임

     

     

     

     

     

     


    4️⃣  문제없이 크롤링 완료됐는지 확인한 다음, 크롤링 함수를 최종 정리해보겠습니다.

    • 다나와에 보이는 제품은 총 375개 였는데, 이상하게도 결과 데이터프레임은 388행이라고 나오네요.
      중복 수집된 모델이 있는지 확인해봐도.. 중복은 없습니다. 아무래도 더미데이터가 들어온 것 같으니 엑셀로 내보내서 볼게요.

     

     

    • 이상하게 예전부터 다나와 크롤링하면 이런 더미데이터가 딸려들어오더라구요.
      중간중간 광고때문인걸까요? 그런것 치곤 가격데이터가 있는 것이 좀 이상합니다. 아무튼 이걸 빼니 375개 딱 맞네요!
    • 살펴보니 출시시기가 비어있으면 더미에 해당합니다. 이걸 기준으로 걸러주는게 좋겠네요.

     

     

    4️⃣-(1) [함수1] 크롬드라이버 실행부터 페이지 넘기면서 크롤링까지

    • 이제 위에서 작성했던 코드들을 함수 2개로 묶겠습니다.
    • crawling_danawa_get_source: 페이지 넘기면서 제품정보 데이터들을 긁어오는 함수입니다.
      - 입력값은 다나와 링크, 타겟 제조사 리스트입니다.
      - 출력값은 크롤링 페이지 정보 저장된 딕셔너리, 가격정보 최댓값입니다.
    # 필요한 패키지 가져오기
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    from bs4 import BeautifulSoup
    import time
    import math
    import pandas as pd
    import pickle
    def crawling_danawa_get_sources(url, target_list): 
    	# 함수 입력값: 다나와 링크, 타겟 제조사 리스트
    
        ##### 드라이버 실행 ~ 타겟 제조사 선택까지 #####
        # webdirver 설정 및 실행
        my_options = webdriver.ChromeOptions()
        my_options.add_argument('--window-size=1920,1080')
        my_options.add_argument("disable-gpu")
        driver = webdriver.Chrome(options=my_options)
        driver.implicitly_wait(1)
        
        # 다나와 제품카테고리 페이지 접속
        driver.get(url)
        driver.implicitly_wait(3)
        
        # 제조사별 부분 XPath 리스트로 가져오기
        manufacturer_list = driver.find_elements(By.XPATH, '//*[@id="dlMaker_simple"]/dd/ul[1]/li')
        
        # 타겟 제조사 체크박스 하나씩 클릭하기
        for target in target_list:
            for m in manufacturer_list:
                if target in m.text:
                    m.click()
                    break
    
        driver.implicitly_wait(3)
        print('타겟 제조사: ', str(target_list), '선택 완료 했습니다!\n')
        
        # 전체 모델 개수
        num_models = driver.find_element(
            By.CLASS_NAME, 'list_num').text.strip().replace('(', '').replace(')', '')
        # 페이지 개수
        num_pages = math.ceil(int(num_models) / 30))
        print('현재 검색된 모델은 총', str(num_models), '개 입니다.')
        print('크롤링할 페이지는 총', str(num_pages), '페이지 입니다.\n')
        
        
        ##### 페이지 넘기면서 제품정보 가져와서 저장하기 ####
        # 가격정보 저장할 빈 리스트 생성
        numofprices_list = []
        # 페이지별 소스 저장할 빈 딕셔너리 생성
        soup_dict = {}
        
        page = 1
        
        # page에 1씩 더하면서, 전체 페이지 수와 같아지기 전까지 반복
        while page < num_pages:
        
            # 제품 정보들 전부 가져오기
            soup = BeautifulSoup(driver.page_source)
            products = soup.select('div.prod_main_info')
            time.sleep(1)
            
            # 페이지별 소스 딕셔너리에 저장해두기
            soup_dict[page] = products
        
            # 제품하나씩 돌리면서
            for i in range(len(products)):
                try: # 가격정보 개수 가져오기
                    numofprices_list.append(len(products[i].select('div.prod_pricelist li')))
                except:
                    numofprices_list.append('')
                    
            time.sleep(1)
            print(page, "페이지 완료!")
        
            page += 1
            
            # 11,21,31..번째 페이지로 넘기는 경우 [화살표] 버튼 클릭
            if page%10 == 1:
                driver.find_element(
                    By.CSS_SELECTOR, '#productListArea > div.prod_num_nav > div > a').click()
        
            # 나머지 경우는 page에 해당하는 페이지 클릭
            else:
                # 페이지 넘기는 부분 경로 통째로 가져와놓고
                page_nums = driver.find_element(By.XPATH, '//*[@id="productListArea"]/div[4]/div')
                # 다음 페이지 링크를 클릭
                page_nums.find_element(By.LINK_TEXT, str(page)).click()
                
            # 에러나지 않도록 한페이지마다 잠시 대기
            time.sleep(2)
        
        
        # 마지막 페이지 소스 가져오고 마무리
        soup = BeautifulSoup(driver.page_source)
        products = soup.select('div.prod_main_info')
        soup_dict[page] = products
        print(page, "페이지 완료!\n")
        
        print("<<< 크롤링 완료입니다! >>>\n")
        print("가격정보가 가장 많은 경우는", max(numofprices_list), "개 입니다!")
        
        # 함수 출력값: 크롤링된 페이지 정보 저장된 딕셔너리, 가격정보 최댓값
        return soup_dict, max(numofprices_list)

     

    4️⃣-(2) [함수2] 수집된 정보를 거르고 필터링해서 분석 가능한 데이터프레임으로!

    • 위에서 더미데이터 거르는 부분 수정도 포함해서 수정한 최종함수입니다.
    • crawling_danawa_result: 긁어온 데이터를 돌리면서 데이터프레임으로 정리하는 함수입니다. 
      - 입력값은 함수1에서 크롤링 페이지 정보 저장했던 딕셔너리, 가격정보 최댓값, 그리고 저장할 엑셀파일의 이름입니다.
      - 출력값은 크롤링 결과가 정리된 데이터프레임, 그리고 저장된 엑셀파일입니다.
    def crawling_danawa_result(soup_dict, max_numofprices_list, excel_title): 
        # 함수 입력값: 제품정보 저장된 딕셔너리, 가격정보 최댓값, 결과 저장할 엑셀파일명
    
        ### 데이터 저장할 빈 리스트 생성 ###
        # 모델이름, 출시시기, 헤드메시지, 스펙, 리뷰평점, 리뷰개수, 페이지링크
        name_list, hm_list, spec_list, release_list, star_list, review_list, link_list = [], [], [], [], [], [], []
        # 가격정보 리스트셋 (ex. 1위 일반구매, 2위 추가필터 포함..)
        priceinfo_list_set = []
        # 최저가 리스트셋 (ex. 100,000원, 120,000원..)
        price_list_set = []
    
        # 최댓값만큼 빈 리스트 생성 (이중리스트)
        for i in range(max_numofprices_list):
            priceinfo_list_set.append([])
            price_list_set.append([])
    
        ### 딕셔너리에 저장해둔 페이지 하나씩 돌리기 ###
        for key in range(len(soup_dict)):
            products = soup_dict[key+1]
            
            # 제품마다 하나씩 돌리기
            for i in range(len(products)):
                
                # 모델 출시시기 (마지막 온점떼고 string으로 저장)
                try:
                    release = str(products[i].select_one('div.prod_sub_info dd').text.strip())
                    release_list.append(release[:-1])
                except:
                    continue
                
                # 모델 이름 (string으로 저장)
                try:
                    name_list.append(str(products[i].select_one('p.prod_name a').text.strip()))
                except:
                    name_list.append('')
                    
                    
                # 헤드 메시지 (string으로 저장)
                try:
                    hm_list.append(str(products[i].select_one('div.prod_intro').text.strip()))
                except:
                    hm_list.append('')
                    
                # 모델 스펙 (string으로 저장)
                try:
                    spec_list.append(str(products[i].select_one('div.spec_list').text.strip()))
                except:
                    spec_list.append('')
    
                # 리뷰 개수 (int로 저장, 리뷰없으면 0)
                try:
                    review_list.append(int(
                        products[i].select_one('div.prod_sub_info a').text.strip().replace(',', '')))
                except:
                    review_list.append(0)
                    
                # 리뷰 평점 (float으로 저장, 리뷰없으면 0)
                try:
                    star_list.append(float(
                        products[i].select_one('div.cnt_star').text.strip().replace('점', '')))
                except:
                    star_list.append(0)
                    
                # 제품페이지 링크
                try:
                    thumbnail = products[i].select_one('div.thumb_image a')
                    link_list.append(thumbnail['href'])
                except:
                    link_list.append('')
    
                
                # 가격정보 전부 가져와서 하나씩 더하기
                pricelist_raw = products[i].select('div.prod_pricelist li')
                
                # 가격정보 (string으로 저장)
                for p in range(max_numofprices_list):
                    try:
                        priceinfo_list_set[p].append(str(
                            pricelist_raw[p].select_one('div.over_preview').text.strip()))
                    except:
                        priceinfo_list_set[p].append('')
    
                # 가격 최저가 (int로 저장)
                for p in range(max_numofprices_list):
                    try:
                        price_list_set[p].append(int(
                            pricelist_raw[p].select_one('p.price_sect a').text.strip().replace('원', '').replace(',', '')))
                    except:
                        price_list_set[p].append('')
    
        ### 크롤링 결과 저장 ###
        # 데이터프레임 생성
        df_result = pd.DataFrame({
            '제품모델명' : name_list, '출시시기' : release_list, '리뷰평점' : star_list, '리뷰개수' : review_list,
            '헤드메시지' : hm_list, '스펙' : spec_list, '링크URL' : link_list
        })
    
        for p in range(max_numofprices_list):
            df_result['가격정보_{}'.format(str(p+1))] = priceinfo_list_set[p]
            df_result['최저가_{}'.format(str(p+1))] = price_list_set[p]
    
        # 데이터프레임을 엑셀파일로 저장
        with pd.ExcelWriter(excel_title) as writer:
            df_result.to_excel(writer)
    
        # 함수 출력값: 크롤링 결과 데이터프레임과 엑셀파일 저장
        return df_result


     

    • 수고하셨습니다! 이제 이 함수 2개로 다나와에서 공기청정기 뿐만 아니라 다른 제품정보들도 크롤링 할 수 있습니다! 
      다른 제품, 다른 제조사를 선택해도 문제없도록 작성되었으니, 가끔 문제시 유지보수만 해주면 되겠어요.
    • 분석 대상이 될 제품의 기본정보를 전부 수집 완료했습니다!
      다음엔 제품마다 리뷰데이터를 수집해볼게요. 다나와는 말그대로 판매중인 사이트의 리뷰들이 다나와있어서 아주 유용합니다.
    (다음포스팅) 다나와에서 제품별로 리뷰 크롤링하기!

     

     

     

    728x90
    반응형