본문으로 바로가기
import matplotlib.pyplot as plt
import pandas as pd
from selenium import webdriver
import urllib.request
from PIL import Image
import sqlite3 
import time
import glob
import os
import math
%matplotlib inline

 

여행 정보를 담을 DB Table 만들기

def tour_crawl(place='보라카이'):

    dbpath = "tour_info.db" 
    conn = sqlite3.connect(dbpath)
    cur = conn.cursor() 
    
    script = """
    DROP TABLE IF EXISTS tour_crawl;

    CREATE TABLE tour_crawl(
      id INTEGER PRIMARY KEY AUTOINCREMENT,  -- 여행 상품의 ID 값
      title TEXT,                            -- 여행 상품의 제목
      price INTEGER,                         -- 여행 상품의 가격
      image TEXT                             -- 여행 상품의 썸네일 이미지 링크
    );
    """ 
    cur.executescript(script)

 

Selenium으로 스크래핑

def tour_crawl(place='보라카이'):

    # 코드 이어서    

    service = Service(executable_path=ChromeDriverManager().install()) 
    driver = webdriver.Chrome(service=service)
    
    driver.get('http://tour.interpark.com')
    print('\nCurrent URL :', driver.current_url)
    time.sleep(5)

    driver.find_element_by_id('SearchGNBText').send_keys(place)
    driver.find_element_by_class_name('search-btn').click()
    print('\n(2 of 3) {} 여행 상품에 대한 크롤링을 곧 시작합니다.'.format(place))
    time.sleep(3)

    driver.find_element_by_class_name('moreBtn').click()
    print('\n여행 상품 리스트에 도착했습니다.')
    time.sleep(3)

    
    maxpage = math.ceil(int(driver.find_element_by_class_name('mainTxt').find_element_by_tag_name('span').text)/10)
    # maxpage = 3 # 여행 상품의 페이지 수가 3 미만일 경우 에러가 발생합니다.
    
    for page in range(1, maxpage + 1):

        driver.find_element_by_xpath('/html/body/div[3]/div/div[1]/div[2]/div[4]/div[3]/ul/li[{}]'.format(page)).click()
        time.sleep(3) 
        print("\n{}번째 페이지의 크롤링을 시작합니다.\n".format(page))

        box_list = driver.find_element_by_id('boxList')
        box_items = box_list.find_elements_by_class_name('boxItem')

        for li in box_items:
            title = li.find_element_by_class_name('infoTitle').text 
            price = li.find_element_by_class_name('infoPrice').find_element_by_tag_name('strong').text.replace(',','')
            image = li.find_element_by_tag_name('img').get_attribute('src')
            
            # DB에 한 행씩 추가
            base_sql = "INSERT INTO tour_crawl(title, price, image) values('{}',{},'{}')" # TEXT인 제목은 ''로 감싸주는 것에 유의
            sql_query = base_sql.format(title, price, image) 
            print('SQL Query :', sql_query[:90], "...")

            cur.execute(sql_query)
            conn.commit()

    driver.close()
    driver.quit()

    print('\n총 {}페이지의 크롤링이 정상적으로 종료되었습니다.'.format(maxpage))
    
    # DB를 확인하기 위해 추가해준 line
    df = pd.read_sql_query("SELECT image FROM tour_crawl;", conn)
    conn.close()

 

URL을 통한 이미지 일괄 다운로드

def tour_crawl(place):
	
    # 코드 이어서
    
    # 패턴을 따르는 파일들의 (경로를 포함한) 파일명을 리스트로 리턴
    previous_images = glob.glob('images/*.jpg')
    # 이전 크롤링의 결과 images 폴더 안에 남아있는 이미지 파일들이 있다면 모두 삭제
    for image in previous_images:
        os.remove(image)


    img_urls = list(df['image'])
    print('\n(3 of 3) 총 {}장의 여행지 이미지에 대한 다운로드를 시작합니다.\n'.format(len(img_urls)))

    for index, url in enumerate(img_urls): 
        urllib.request.urlretrieve(url, "images/{}.jpg".format(index)) # 실제 이미지를 다운로드하는 코드 
        time.sleep(0.3)
        if index % 10 == 0:
            print('총 {}장까지 이미지 다운로드가 성공했습니다.'.format(index))

    print('\n모든 이미지의 다운로드가 종료되었습니다! (총 이미지 수 : {})'.format(len(img_urls)))


    fig = plt.figure(figsize=(15, 30)) 
    rows = len(df['image']) // 5 + 1 # 전체 이미지를 5개씩 하나의 행에 보여줄 때 필요한 행의 수
    cols = 5
    i = 1

    for filename in glob.glob("images/*.jpg"):

        ax = fig.add_subplot(rows, cols, i)
        ax.axis('off')
        ax.imshow(Image.open(filename))
        i += 1

    plt.tight_layout(pad=0)
    plt.show()