TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 데이터 분석>

[파이썬] 웹 스크래핑: 한남동, 이태원 맛집 분석(실패)

by 기록자_Recordian 2024. 6. 24.
728x90
반응형

해당 프로젝트는 실패하여 중간에 중단하였으므로, 어떻게 실패했는지 궁금하고,

만약에 이렇게 했으면 성공했을텐데 라는 조언을 주실 분이 읽어주셨으면 합니다.

 

참고로, 아래는 성공한 글입니다.

 

[파이썬] 웹 스크래핑: 한남동, 이태원 맛집 분석 - 1

프로젝트 수행 내용 및 목표 웹스크래핑으로 이태원과 한남동에 위치한 맛집 리스트를 받아와 DataFrame 으로 만들고,지도 정보를 받아 folium을 통해 시각화 하는 것을 목표로 한다. 맛집 리스트

puppy-foot-it.tistory.com


프로젝트 수행 내용 및 목표

 
웹스크래핑으로 이태원과 한남동에 위치한 맛집 리스트를 받아와 DataFrame 으로 만들고,
지도 정보를 받아 folium을 통해 시각화 하는 것을 목표로 한다.
 
맛집 리스트는 '디너의 여왕' 사이트에서 가져오도록 한다.


'디너의 여왕' 사이트에서 맛집 리스트 얻기

 
https://dinnerqueen.net/restaurant/area/4.

 

디너의여왕 - 이태원&한남동 맛집랭킹

오늘 뭐 먹을지 고민된다면, 디너의여왕만의 빅데이터 맛집 랭킹을 찾아주세요.

dinnerqueen.net

 
해당 사이트에 접속하여 가게 리스트 정보를 얻기 위해 먼저 웹스크래핑을 할 수 있는 세팅을 한다.

# 이태원, 한남동 맛집 리스트
from bs4 import BeautifulSoup
from urllib.request import urlopen
import requests

url_base= "https://dinnerqueen.net"

url_sub = '/restaurant/area/4'
url = url_base + url_sub

# 크롤링 방지
url = requests.get(url_base + url_sub, headers={'User-Agent': "Mozailla/5.0"})
html = urlopen(url.url)

soup = BeautifulSoup(html, 'html.parser')
soup


find_all 명령을 이용해서 div 태그의 dq-area-card__text 클래스 찾기

 
개발자 도구를 이용하여 '3. 더플라잉팬블루'에 마우스를 올려보면
div 태그에 dq-area-card__text 클래스 임을 알 수 있다.

 

# find_all 이용하여 태그 찾기
print(soup.find_all('div', 'dq-area-card__text'))

 
찾는 태그가 맞는지 확인하기 위해 len 명령으로 글자수를 조회해보면

len(soup.find_all('div', 'dq-area-card__text'))

전체 리스트 개수는 2,452개인데, 15개만 조회된다. 왜냐하면 해당 링크에 들어가면 리스트가 15개만 뜨고 스크롤을 내리면 자동으로 나머지 리스트가 생성되는 구조이기 때문이다.
이러한 경우, 스크롤을 자동으로 움직이게 하는 기능을 추가해줘야 할 거 같은데, 그러려면 selenium 모듈을 사용해야 할 거 같다. selenium을 사용하기 위한 준비를 한다. (하단 링크 참고)

 

[파이썬] Selenium 라이브러리 사용하기

시작에 앞서해당 내용은 -민형기 저, BJPUBLIC 출판사 의 내용을 토대로 작성되었습니다.보다 자세한 내용은 해당 교재를 확인하여 주시기 바랍니다.  Selenium 라이브러리 사용하기 파이썬의 Sele

puppy-foot-it.tistory.com

 
주요 내용은
- selenium 모듈 설치
- 크롬 드라이버 설치는 하지 않아도 된다.
(셀레니움이 업데이트 되어 크롬 드라이버 다운로드 없이 webdriver.Chrome() 입력 - 괄호 안에 아무 내용 없이)


자동으로 스크롤을 내리는 코드 작성 (+새로운 방식으로 접근)

 
앞서 설명했듯, 해당 사이트에서 전체 맛집 리스트를 다 받으려면 스크롤을 아래로 내려야 하는데,
해당 기능을 수행할 수 있는 코드를 만들어서 테스트 해 본다.

# 셀레니움 임포트
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time

url_base= "https://dinnerqueen.net"

url_sub = '/restaurant/area/4'
url = url_base + url_sub


driver = webdriver.Chrome()
driver.get(url)


# 페이지 하단까지 스크롤 내리기
def scroll_to_bottom():
    last_height = driver.execute_script("return document.body.scrollHeight")
    
    while True:
        # Scroll down to the bottom
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        
        # Wait for new content to load
        time.sleep(2)
        
        # Calculate new scroll height and compare with last scroll height
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:
            break
        last_height = new_height

# 스크롤 내리기 함수 호출
scroll_to_bottom()

 
▶ 테스트 해 보니, 크롬 웹드라이버로 크롬 창이 자동으로 켜지고,
해당 url로 자동으로 접속되며 스크롤이 자동으로 잘 내려간다.
 
그러나 목적은 '스크롤을 자동으로 내리면서 html 정보를 읽어 필요한 데이터를 저장하는 것'이니,
위의 코드에 데이터를 저장하는 기능까지 추가를 시키는 것으로 코드를 보완한다.

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()

try:
    # 웹사이트 열기
    driver.get('https://dinnerqueen.net/restaurant/area/4')

    # 페이지 하단까지 스크롤 내리기
    def scroll_to_bottom():
        last_height = driver.execute_script("return document.body.scrollHeight")

        while True:
            # 스크롤 아래로 내리기
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

            # 새로운 콘텐츠 로딩 대기
            time.sleep(1)

            # 새로운 스크롤 길이 계산하고 앞의 스크롤 길이와 비교하기
            new_height = driver.execute_script("return document.body.scrollHeight")
            if new_height == last_height:
                break
            last_height = new_height

    # 스크롤 내리기 함수 호출
    scroll_to_bottom()

    # 필요한 작업 수행
    # 돌면서 식당 리스트 가져오기
    # dq-area-card__text 클래스의 값을 저장하기
    text_elements = driver.find_elements(By.CSS_SELECTOR, 'div.dq-area-card__text')
    texts = [element.text for element in text_elements]

finally:
    # 브라우저 닫기
    driver.quit()

▶ 기존 코드는 time.sleep(2)로 설정되어 있어 스크롤이 늦어 속도를 높였고, 
해당 사이트 스크롤을 내리면서 div 태그의 dq-area-card__text 클래스의 데이터를 텍스트 형태로 저장할 수 있게 하였다.
 
식당 정보가 담긴 데이터인 변수 'texts'를 출력해보면

print(texts)

식당 이름, 주소, 리뷰 등이 잘 저장된 것을 확인할 수 있다. (하지만 2천여 개 중 105개 식당의 리스트만 저장되었다.)


리스트로 저장된 맛집 리스트 문자열로 바꾸기

 
위의 과정을 거쳐 texts라는 변수에 식당 이름, 주소, 리뷰 등의 정보가 잘 저장되었으나,
문제는 해당 값이 리스트 형으로 저장되어 있어 분할을 해줘야 한다는 문제가 있다.
따라서, 해당 코드 실행 후 데이터를 저장할 때 리스트가 아닌 문자열로 저장할 수 있게 코드를 수정 및 보완해야 할 거 같다.
 

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()

try:
    # 웹사이트 열기
    driver.get('https://dinnerqueen.net/restaurant/area/4')

    # 페이지 하단까지 스크롤 내리기
    def scroll_to_bottom():
        last_height = driver.execute_script("return document.body.scrollHeight")

        while True:
            # 스크롤 아래로 내리기
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

            # 새로운 콘텐츠 로딩 대기
            time.sleep(1)

            # 새로운 스크롤 길이 계산하고 앞의 스크롤 길이와 비교하기
            new_height = driver.execute_script("return document.body.scrollHeight")
            if new_height == last_height:
                break
            last_height = new_height

    # 스크롤 내리기 함수 호출
    scroll_to_bottom()

    # 필요한 작업 수행
    # 돌면서 식당 리스트 가져오기
    # dq-area-card__text 클래스의 값을 저장하기
    text_elements = driver.find_elements(By.CSS_SELECTOR, 'div.dq-area-card__text')
    #texts = [element.text for element in text_elements]
    # 리스트로 저장된 texts를 문자열로 변환
    text_string = ''.join(element.text for element in text_elements)

finally:
    # 브라우저 닫기
    driver.quit()

▶ 기존 코드에서 식당 정보(div 태그의 dq-area-card__text 클래스)를 리스트가 아닌 문자열로 text_string 이라는 변수에 저장하는 것으로 수정되었다.
 
그리고 해당 변수를 출력해보면

print(text_string)

2,452 가게 리스트가 이전 값보다 훨씬 더 깔끔하게 저장되었다.


 text_string 변수 txt 파일로 저장하기

 

2,452 가게 리스트를 우선 txt 파일로 저장해서 오류나 예기치 못한 상황에 대비하도록 한다.

파일로 저장하는 것은 이전에 진행했던 파일 입출력 관련 내용을 참고하면 된다.

 

[파이썬] 파이썬기초: 입력과 출력, 파일 읽고 쓰기

시작에 앞서해당 내용은 ' 박응용 지음. 이지스 퍼블리싱' 을 토대로 작성되었습니다. 보다 자세한 내용은 해당 서적에 상세히 나와있으니 서적을 참고해 주시기 바랍니다.사용자 입력 사용자

puppy-foot-it.tistory.com

# 해당 변수의 데이터 txt 파일로 저장하기

# 변수에 저장할 데이터
data = text_string

# 파일 열기 (쓰기 모드, UTF-8 인코딩)
with open("Yongsan_list.txt", 'w', encoding='utf-8') as f:
    f.write(data)

# 파일 닫기
f.close()

print("데이터가 성공적으로 저장되었습니다.")

식당 리스트가 텍스트 파일로 잘 저장 되었다. 이제 작업을 새로 시작해야 하는 상황이 생기면 텍스트 파일을 불러 진행하면 된다.

Yongsan_list.txt
0.28MB

 

혹시 접속이 끊기거나 해서 크롤링을 다시 해야 하는 상황을 대비하여 텍스트 파일을 불러 작업을 진행하도록 한다.

# 텍스트 파일 불러오기
f = open("C:/Users/niceq/Documents/DataScience/Practice/Source_code/Yongsan_list.txt", 'r', encoding='utf-8')
data = f.read()
print(data)
f.close()

 

※ 줄바꿈의 문제, 해시태그와 순위가 붙어있어 분할을 해야 하는 문제(예. #음식점 #멕시코 #남미음식 2. 올 댓 재즈) 등을 해결하려 했지만, 실패하여 다른 방식으로 새롭게 접근해 보고자 한다.

 

 

 

 

728x90
반응형