programming/Python

파이썬으로 맛집 웹크롤링 하기 (망고플레이트) - 2탄

Jofresh 2023. 6. 19. 19:01
728x90
반응형

 

안녕하세요. 조신선입니다.

 

오늘은 파이썬을 활용해서 웹크롤링 하는 방법 2탄에 대해서 포스팅하겠습니다.

 

 

 

2번째 코드입니다. 1번의 경우 맛집들의 주소를 크롤링 했다면,

2번째 코드는 1탄에서 크롤링한 주소에 접속해서 원하는 정보를 추출해서 csv 파일로 저장하는 코드라고 생각하시면 됩니다.

 

 

import requests
import scrapy
from scrapy.http import TextResponse
from selenium import webdriver
import pandas as pd
import json
import time
import datetime
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from bs4 import BeautifulSoup
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import WebDriverException
from selenium.common.exceptions import NoSuchElementException

now = datetime.datetime.now()


df_list = pd.DataFrame()
count = 0

df = pd.read_csv('1탄에서 저장한 파일명.csv')

links = df['링크'].dropna().tolist() #n/a값들을 날려줍니다. 

for link in links:
    # 페이지 접속
    options = webdriver.ChromeOptions()  # 백그라운드에서 크롬 실행
    #options.add_argument("headless")
    driver = webdriver.Chrome(options=options)
    driver.get(link)
    WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > header > div.restaurant_title_wrap > span > h1')))
    # 이름 가져오기
    name = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > header > div.restaurant_title_wrap > span > h1').text

    # 주소 가져오기
    try:
        address = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(1) > td').text.strip()
    except:
        address = " "
    # 전화번호 가져오기
    try:
        tel = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(2) > td').text.strip()
    except:
        tel = " "

    # 평점 가져오기
    try:
        price = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(4) > td').text.strip()
    except:
        price = " "
    # 대표메뉴 가져오기
    try:
        menu = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(3) > td > span').text.strip()
    except:
        menu = " "
    id_code = link[:]
    try:
        score = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.RestaurantReviewList > header > h2 > span.RestaurantReviewList__AllCount').text.strip()
    except:
        score = " "
    try:
        times = driver.find_element(By.CSS_SELECTOR, '#lbl_review_point').text.strip()
    except:
        times = "0"
    time.sleep(1)
    df_list = df_list.append({
        'id': id_code,
        '가게명': name,
        '주소': address,
        "전화번호": tel,
        "리뷰": score,
        "운영시간": times,
        "메뉴": menu
    }, ignore_index=True)
    count += 1



df_list.to_csv("{}_망고플레이트_정보.csv".format(now.strftime('%Y-%m-%d_%H-%M')), encoding='utf-8-sig')

 

필요한 모듈 및 라이브러리 임포트에 대한 설명

 


requests: HTTP 요청을 보내기 위한 모듈
scrapy: 웹 스크래핑 프레임워크
TextResponse from scrapy.http: 스크래핑한 웹 페이지의 응답을 다루기 위한 클래스
webdriver from selenium: 웹 브라우저 자동화 도구
pandas: 데이터 조작 및 분석을 위한 라이브러리
json: JSON 데이터 처리를 위한 모듈
time: 시간 관련 기능을 제공하는 모듈
datetime: 날짜와 시간 관련 기능을 제공하는 모듈
By from selenium.webdriver.common.by: 웹 요소를 찾기 위한 다양한 방법을 제공하는 클래스
Keys from selenium.webdriver.common.keys: 키보드 키를 제어하기 위한 클래스
WebDriverWait from selenium.webdriver.support.ui: 웹 페이지에서 특정 요소가 나타날 때까지 대기하는 기능을 제공하는 클래스
BeautifulSoup from bs4: HTML 및 XML 문서 파싱을 위한 라이브러리
EC from selenium.webdriver.support.expected_conditions: 웹 요소의 상태를 확인하는 조건 클래스
Options from selenium.webdriver.chrome.options: Chrome 웹 드라이버의 옵션을 설정하기 위한 클래스
WebDriverException from selenium.common.exceptions: Selenium의 예외 클래스 중 하나
NoSuchElementException from selenium.common.exceptions: 웹 요소를 찾지 못했을 때 발생하는 예외 클래스

 

코드에 관련된 설명

 

현재 날짜와 시간 정보 가져오기:
now = datetime.datetime.now(): 현재 날짜와 시간을 가져와 변수 now에 저장합니다.

 

데이터프레임 및 변수 초기화:
df_list = pd.DataFrame(): 빈 데이터프레임을 생성하여 음식점 정보를 저장할 준비를 합니다.
count = 0: 반복문을 실행한 횟수를 저장하는 변수를 초기화합니다.

 

 

CSV 파일에서 링크 데이터 읽기:
df = pd.read_csv('1탄에서 저장한 파일명.csv'): CSV 파일에서 '링크' 열의 데이터를 읽어와 데이터프레임 df에 저장합니다.

 

음식점 정보 수집:
'for link in links:': 링크 데이터를 하나씩 반복하여 처리합니다.

 

웹 브라우저 설정 및 접속:
options = webdriver.ChromeOptions(): Chrome 웹 드라이버의 옵션을 설정합니다.
driver = webdriver.Chrome(options=options): Chrome 웹 드라이버를 생성합니다.
driver.get(link): 지정된 링크로 웹 페이지에 접속합니다.
WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > header > div.restaurant_title_wrap > span > h1'))): 페이지에서 특정 요소가 나타날 때까지 최대 30초간 대기합니다.

 

웹 브라우저 설정 및 접속을 하려면 아래 포스팅을 확인 후 구글드라이버 설치를 해주셔야 합니다.

 

[파이썬/크롤링] 구글드라이버 &selenium 라이브러리 설치_ 웹 크롤링 하기 전 필수 작업

안녕하세요. 조신선입니다. 셀레니엄 라이브러리를 사용하기 위해서는 크롬드라이버를 필수적으로 설치를 해야 하는데요. 제가 웹크롤링 하는 방법에 대한 포스팅은 몇 번 했으나, 크롬드라이

jofresh.tistory.com

음식점 정보 추출:
name = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > header > div.restaurant_title_wrap > span > h1').text: 웹 페이지에서 음식점 이름을 추출합니다.
address = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(1) > td').text.strip(): 웹 페이지에서 음식점 주소를 추출합니다.
tel = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(2) > td').text.strip(): 웹 페이지에서 음식점 전화번호를 추출합니다.
price = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(4) > td').text.strip(): 웹 페이지에서 음식점 가격 정보를 추출합니다.
menu = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.restaurant-detail > table > tbody > tr:nth-child(3) > td > span').text.strip(): 웹 페이지에서 음식점 대표 메뉴를 추출합니다.
id_code = link[:]: 링크 값을 변수에 저장합니다.
score = driver.find_element(By.CSS_SELECTOR, 'body > main > article > div.column-wrapper > div.column-contents > div > section.RestaurantReviewList > header > h2 > span.RestaurantReviewList__AllCount').text.strip(): 웹 페이지에서 음식점 리뷰 개수를 추출합니다.
times = driver.find_element(By.CSS_SELECTOR, '#lbl_review_point').text.strip(): 웹 페이지에서 운영 시간을 추출합니다.

 

 

정보 추출시 주의사항! 

 

웹페이지 접속 후  위 이미지와 같이 전화번호/ 음식종류 / 가격대 등의 정보를 크롤링하는 코드입니다.

 

하지만, 아래 이미지와 같이 정보가 제한적인 경우는 크롤링하는 정보의 순서가 꼬일 수 있습니다.

 

전화번호 / 음식종류/ 가격대 / 주차 / 영업시간 / 마지막주문 / 휴일 / 메뉴 

와 같은 정보들은 각각의 번호 인덱스를 가지는데요.

 

예를 들어,

1번 전화번호 / 2번 음식종류/ 3번 가격대 / 4번 주차 / 5번 영업시간 / 6번 마지막주문 / 7번 휴일 / 8번 메뉴 

위와 같이 모든 정보가 표기된 가게의 경우 1번부터 8번까지 css_select 번호가 생성됩니다.

 

하지만 아래 이미지와 같은 가게는 3개의 css_select 번호가 생기겠죠?

 

1번 전화번호/ 2번 음식종류

 

이렇게 되는건 문제가 없습니다만, 

 

 

 

음식 종류는 없고 바로 가격대 정보를 노출시키는 가게가 있다면,

 

음식종류라는 컬럼에 가격대의 정보가 들어갈 수 있습니다. 

아래 이미지처럼 전화번호에 음식종류가 들어가게 되는거죠. 

 

저는 이렇게 되는 경우 따로 엑셀로 작업을 해주었습니다. 

 

혹시나, 더 좋은 방법 알고 계신 분 계시다면 알려주시면 정말 감사하겠습니다!

 

 

 

데이터프레임에 음식점 정보 추가:
df_list = df_list.append({...}, ignore_index=True): 추출한 음식점 정보를 데이터프레임 df_list에 추가합니다.

 

마지막으로:

df_list.to_csv("{}_망고플레이트_정보.csv".format(now.strftime('%Y-%m-%d_%H-%M')), encoding='utf-8-sig'): 추출한 정보를 csv 파일로 저장합니다.

 

필요한 정보가 다르다면 원하는 css_selector값으로 변경해서 원하는 대로 추가/삭제 후 정보를 얻어가시면 될 것 같습니다.

 

css_selector값을 보는 방법은 아래 이전 포스팅 글을 참조해주세요!

 

*** 아참! 그리고 웹페이지에서는 크롤링을 막기 위해 css_selector를 종종 변경하곤 합니다.

코드 실행 전 내가 크롤링할 웹페이지에 접속 후 css_seletor가 변경되었는지 확인 후 코드를 실행하세요!

 

 

 

 

 

[selenium] 구글 이미지 검색 후 이미지 파일 저장하기!

안녕하세요! 조신선입니다. 오늘은 구글 이미지 검색을 하고, 검색한 결과값을 jpg파일로 저장하는 코드를 만들어 보겠습니다. 이 코드는 구글 이미지 검색을 통해 검색어에 해당하는 이미지를

jofresh.tistory.com

 

 

 

 

 

 

 

728x90
반응형