나의 공부 일기

프로젝트) 크롤링/스크랩핑 프로젝트 2일차 본문

프로젝트

프로젝트) 크롤링/스크랩핑 프로젝트 2일차

곽병권 2023. 12. 5. 13:19
728x90

같이 프로젝트를 진행한 팀원: https://jihoon44-it.tistory.com/

 

 

 

 

1일차에서
https://k-python-note-taking.tistory.com/59

 

프로젝트) 크롤링/스크랩핑 프로젝트 1일차

저는 지금 파이썬 개발자와 데이터분석에 관한 국비지원을 받고 있습니다. 2주간 글을 작성하지 안했던것은 이 국비지원을 하며 진행하는 프로젝트에 더 집중하기 위해서였습니다. 먼저 크롤링

k-python-note-taking.tistory.com

 

여기까지 진행했었고, 추가적으로 진행한 코드들입니다.

ls = ['강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구',' 금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구',
     '서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구']

cafe_name_list = {} # 메인 딕셔너리

for i in range(len(ls)):  # 모든 자치구에 있는 카페를 알아보기 위해 반복
    # 브라우저 열기
    keyword = quote(f'{ls[i]} 카페')
    url = 'https://map.naver.com/p/search/' + keyword  
   
    browser = webdriver.Chrome()
    browser.get(url)
    browser.implicitly_wait(10)

   # 스위치 변경
    switch_frame("searchIframe")
    time.sleep(1)
   
    print(f'------------------------------------{i}/{len(ls)}------------------------------------')

    # 버튼 변수들
    next_btn = browser.find_elements(By.CSS_SELECTOR, '.zRM9F> a')
 
   
    # 버튼길이만큼 반복 첫번재는 이전버튼 이므로 제외
    for btn in range(len(next_btn))[1:]:    
        #body부분을 잡기 위해 쓸데없는 버튼을 클릭해줌
        browser.find_element(By.XPATH, '//*[@id="_pcmap_list_scroll_container"]/ul/li[1]/div[1]/div[1]/div').click()
       
        #검색결과가 모두 보이지 않기 때문에 page down을 눌러 끝까지 펼쳐준다.
        for scroll_1 in range(35):
            browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.PAGE_DOWN)

        resp = browser.page_source     # 처음 브라우저 소스와, 버튼을 누를때마다 그것에 관한 페이지 소스 가져옴
        soup = BeautifulSoup(resp, 'html.parser') # 브라우저소스를 html로 변환하여 가져옴
        length = len(soup.select('#_pcmap_list_scroll_container > ul > li'))+1  # 한페이지에 보이는 카페들의 개수 반환

        # 카페들의 개수만큼 반복
        for j in range(1, length+1):
            # 스위치 변경
            switch_frame("searchIframe")
           
            #해당하는 카페에 정보를 알기위해 그 카페를 클릭해줌
            try:
                browser.find_element(By.XPATH, f'//*[@id="_pcmap_list_scroll_container"]/ul/li[{j}]/div[1]/a/div/div').click()
                time.sleep(1)
            except:
                continue
               
            # 스위치 변경
            switch_frame("entryIframe")
            time.sleep(1)
 
            # 카페의 주소를 저장하기 위해 주소 더보기 클릭
            browser.find_element(By.CLASS_NAME,'PkgBl').click()
               
            print(f'-------------------------------{j}번째-------------------------------')
           
            # 카페 주소 저장
            cafe_address = browser.find_element(By.XPATH,'/html/body/div[3]/div/div/div/div[5]/div/div[2]/div[1]/div/div[1]/div/div[1]/div[1]').text[3:-2]
            time.sleep(1)
           
            # 이미지 가져오기
            background_image_style = browser.find_element(By.XPATH,'/html/body/div[3]/div/div/div/div[1]/div/div[1]/div/a/div').get_attribute('style')
            background_image_url = re.search(r'url\("([^"]+)"\)', background_image_style).group(1)
            time.sleep(1)
           
            for scroll in range(0,10):
                browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.PAGE_DOWN)
           
            resp = browser.page_source
            soup = BeautifulSoup(resp, 'html.parser')
            time.sleep(1)
           
            # 리뷰 높은순 3개 가져오기.
            cafe_review_list = []
            try:
                for k in range(1,4):
                    cafe_review_list.append(soup.select(f'div.place_section_content > div.iqjjt > a > ul > li:nth-child({k}) > div.CsBE9 > span.nWiXa')[0].text[1:-1])
            except:
                cafe_review_list.append('리뷰 참여자가 10명이 되지 않습니다.')
           
            # 스위치 변경
            switch_frame("searchIframe")
            time.sleep(1)
           
            resp = browser.page_source
            time.sleep(1)
            soup = BeautifulSoup(resp, 'html.parser')
           
           
# --------------------------------------------------------평점이 없는 매장이 훨신 많아 평점 제거--------------------------------------------------
            # 딕셔너리에 담을 변수들 생성
            cafe_name = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > a.tzwk0 > div > div > span.TYaxT')[0].text
            cafe_classification = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > a.tzwk0 > div > div > span.KCMnt')[0].text
            cafe_review_count = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > div > div > span:nth-child(3)')[0].text

            # 메인 딕셔너리 안에 리스트에 넣을 딕셔너리 템프 작성
            dict_temp = {'page_count':str(btn)+'페이지',
                         'cafe_name':cafe_name,                       # 카페 이름
                         'cafe_classification':cafe_classification,   # 카페 종류
                         'cafe_review_count':cafe_review_count,       # 카페 리뷰 개수
                         'cafe_address':cafe_address,                 # 카페 주소
                         'cafe_review_list':cafe_review_list,         # 카페 리뷰 Top3
                         'background_image_url':background_image_url} # 카페 이미지
           
            # 메인 딕셔너리에 값 추가
            cafe_name_list[f'{ls[i]}_카페_정보_{j}'] =  [dict_temp]

            print(cafe_name_list)
            time.sleep(1)
       
        next_btn[-1].click() # 다음 버튼 클릭
       
        # 버튼이 눌리지 않으면 종료
        if not next_btn[-1].is_enabled():
            break
    browser.implicitly_wait(10)
    browser.close()

 

서울시에 있는 모든 자치구를 돌면서 순회해야되므로 25개의 구를 리스트에 넣어 for문을 사용하여 순회하게 만들었습니다

 

browser.implicitly_wait() 은 브라우저에 제가 크롬을 이용하여 ()안의 url에 해당하는 경로를 넣어놨었는데,

그 브라우저가 열릴때까지() 안의 수만큼 대기하다가 브라우저가 열리면 ()안의 수만큼 지나지 않았어도,

다음 코드가 실행됩니다.

 

time.sleep()도 이와 비슷하지만 이것은 ()안의 수만큼 무조건 대기하다가 넘어가는속성을 가지고 있습니다.

위에있는 implicitly_wait()과는 다르게 페이지가 열려있어도 ()안의 시간은 무조건 대기하다가 넘어갑니다.

 

네이버플레이스를 보시면 1페이지에 54개 1페이지 이후부터는 50개씩 있는 형식으로

54개 또는 50개가 넘어간다면 다음버튼을 누르거나 내가 원하는 페이지 버튼을 눌러야 넘어갑니다. 

 

그래서

next_btn = browser.find_elements(By.CSS_SELECTOR, '.zRM9F> a')

우선 밑에 버튼들이 어디까지 있는지 하나의 값을 가저오는 find_element가 아닌

find_elements를 사용해서 모든 요소들을 가져왔습니다.

 

이때 가져온 값은 리스트형식으로 저장이 됩니다.

 

그 값들의 맨 마지막 요소는 항상 다음 버튼이므로 마지막 코드에서 한페이지에 있는 모든 값들을 가져오면 다음페이지로 넘어가도록 하였습니다.

 

is_enabled()를 활용하여 버튼이 눌리지 않을경우 다음 구로 넘어가도록 구현하였습니다.

 

BeautifulSoup는 url 링크 안에 있는 요소를 html로 바꿔서 보여줍니다.

 

그리고 사이트를 보며 코드를 작성하다보니 iframe이 또 하나 있어서 스위치를 필요할때 바꿔주며 코드를 작성하였습니다.

 

코드를 작성하면서 다음에 이 코드를 보더라도 이 코드가 무엇인지 알아보기 쉽게 주석에서 설명들을 넣었습니다.

 

여기까지 프로젝트를하면서 문제점으로는 같은 IP내에 있는 사용자중 컴퓨터를 사용하는 사용자가 많을경우

인터넷이 느려져 오류가 나오는 경우가 있었습니다.

 

페이지의 요소를 찾지 못하던가, 요소를 가져올때 갖고오지 않는다거나,,, 

 

그리고 이렇게 컴퓨터가 자동으로 사이트에 들어갈때 time.sleep()을 해주지 않는다면

그 사이트에서 ddos공격인줄알고 해당 ip를 몇일간 혹은 몇시간 차단할 수도 있으니,

코드 중간중간에 어디 사이트를 들어가거나 클릭을 하게된다면 time.sleep()을 넣어줘야 합니다.

 

처음에는 이 오류가 도대체 무엇인지 알아보느라 시간을 너무 허비했습니다..

이제라도 이유를 알았으니 다음에 이 부분을 수정하여 오류가 최대한 나오지 않도록 코드를 작성해보도록 하겠습니다.

 


다음에 추가적으로 오류를 수정하고 업데이트를 해보도록 하겠습니다.

728x90