본문 바로가기
TIL/내배캠 사전캠프

23.05.09

by J1-H00N 2023. 5. 9.

select_one을 통해 크롤링한 정보가 제대로 가져와지지 않는 오류 발생

오류 발생 코드

@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give']
    # 입력한 url 저장
    comment_receive = request.form['comment_give']
    # 입력한 comment 저장
    star_receive = request.form['star_give']
    # 입력한 별점 저장

    headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogimage = soup.select_one('meta[property="og:image"]')['content']
    ogdesc = soup.select_one('meta[property="og:description"]')['content']
    # meta tag에서 제목, 이미지, 간단 설명 스크랩하는 코드

    #mainContent > div > div.box_detailinfo > div.contents > div:nth-child(3) > ul > li:nth-child(2) > div > div > strong > a

    derector = soup.select_one('#mainContent > section > div.slide_ranking > div > ol > li.swiper-slide.swiper-slide-active > div > div.thumb_item > div.poster_info > a > dl:nth-child(4) > dd')
    # 감독 정보 selector 복사
    character = soup.select_one('#mainContent > div > div.box_detailinfo > div.contents > div:nth-child(3) > ul > li:nth-child(1) > div > div > strong > a')
    # 출연진 정보 selector 복사


    doc = {
        'title' : ogtitle,
        'desc' : ogdesc,
        'image' : ogimage,
        'comment' : comment_receive,
        'star' : star_receive,
        'derector' : derector,
        'characters' : character
    }
    db.main.insert_one(doc)
    # main이라는 콜렉션 생성, 데이터들 가져와서 저장하기

    return jsonify({'msg':'등록 완료!'}) # 위 코드가 정상 작동 시 등록 완료라는 메시지 반환

위 코드에서 meta tag를 사용한 제목, 설명, 이미지, 별점, 코멘트는 정상적으로 저장되나 select_one을 통해 가져온 감독, 출연진 정보는 null로 가져와지는 상황이다.

 

등록 완료라는 메시지가 정상적으로 작동하는 것을 보면 코드 자체에 오류가 있는 것은 아닌듯 한데, 팀원분의 의견으로는 페이지 내 기본 정보가 아닌 다른 추가 작동을 해야만이 읽을 수 있는 정보?라 오류가 발생하는 것이 아닌가 한다.

 

원인은 파악되었다. 메가박스는 영화의 상세설명이나 출연진 정보와 같은 정보들은 동적 처리되어 selenium이라는 패키지를 따로 사용해야 한다고 한다. 지금은 새롭게 배우는게 아닌 아는 것들을 복습하는 시간이기에 cgv사이트에서 다시 시도해보려 한다.

 

cgv에 맞춰 수정한 코드

@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give']
    # 입력한 url 저장
    comment_receive = request.form['comment_give']
    # 입력한 comment 저장
    star_receive = request.form['star_give']
    # 입력한 별점 저장

    headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogimage = soup.select_one('meta[property="og:image"]')['content']
    # ogdesc = soup.select_one('meta[property="og:description"]')['content'] # cgv에는 og:description 태그 부분이 없기에 주석처리
    # meta tag에서 제목, 이미지, 간단 설명 스크랩하는 코드

    #mainContent > div > div.box_detailinfo > div.contents > div:nth-child(3) > ul > li:nth-child(2) > div > div > strong > a

    derector = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(2) > a').text
    # 감독 정보 selector 복사
    character = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(1)').text
    # 출연진 정보 selector 복사
    desc = soup.select_one('#menu > div.col-detail > div.sect-story-movie').text.strip()
    # meta tag에 없던 세부 설명을 가져오기 위해 selector 따로 복사


    doc = {
        'title' : ogtitle.replace(' | 영화 그 이상의 감동. CGV',''),
        # 'desc' : ogdesc,
        'desc' : desc,
        'image' : ogimage,
        'comment' : comment_receive,
        'star' : star_receive,
        'derector' : derector,
        'characters' : character
    }
    db.main.insert_one(doc)
    # main이라는 콜렉션 생성, 데이터들 가져와서 저장하기

    return jsonify({'msg':'등록 완료!'}) # 위 코드가 정상 작동 시 등록 완료라는 메시지 반환

등장인물을 세명까지 늘림

@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give']
    # 입력한 url 저장
    comment_receive = request.form['comment_give']
    # 입력한 comment 저장
    star_receive = request.form['star_give']
    # 입력한 별점 저장

    headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogimage = soup.select_one('meta[property="og:image"]')['content']
    # ogdesc = soup.select_one('meta[property="og:description"]')['content'] # cgv에는 og:description 태그 부분이 없기에 주석처리
    # meta tag에서 제목, 이미지, 간단 설명 스크랩하는 코드

    #mainContent > div > div.box_detailinfo > div.contents > div:nth-child(3) > ul > li:nth-child(2) > div > div > strong > a

    derector = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(2) > a').text
    # 감독 정보 selector 복사
    character = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(1)').text
    # 출연진 정보 selector 복사
    character_2 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(2)').text
    # 출연진이 따로 따로 저장되어 있어 두번째 등장인물 저장
    character_3 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(3)').text
    # 세 명까지 저장
    desc = soup.select_one('#menu > div.col-detail > div.sect-story-movie').text.strip()
    # meta tag에 없던 세부 설명을 가져오기 위해 selector 따로 복사


    doc = {
        'title' : ogtitle.replace(' | 영화 그 이상의 감동. CGV',''),
        # 'desc' : ogdesc,
        'desc' : desc,
        'image' : ogimage,
        'comment' : comment_receive,
        'star' : star_receive,
        'derector' : derector,
        'character1' : character,
        'character2' : character_2,
        'character3' : character_3
    }
    db.main.insert_one(doc)
    # main이라는 콜렉션 생성, 데이터들 가져와서 저장하기

    return jsonify({'msg':'등록 완료!'}) # 위 코드가 정상 작동 시 등록 완료라는 메시지 반환

중간 점검 완성 코드

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.oid4wb8.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta
# mongodb연결 및 dbspata라는 데이터베이스 지정

import requests
from bs4 import BeautifulSoup

@app.route('/')
def home():
    return render_template('index.html')

@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give']
    # 입력한 url 저장
    comment_receive = request.form['comment_give']
    # 입력한 comment 저장
    star_receive = request.form['star_give']
    # 입력한 별점 저장

    headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogimage = soup.select_one('meta[property="og:image"]')['content']
    # ogdesc = soup.select_one('meta[property="og:description"]')['content'] # cgv에는 og:description 태그 부분이 없기에 주석처리
    # meta tag에서 제목, 이미지, 간단 설명 스크랩하는 코드

    derector = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(2) > a').text
    # 감독 정보 selector 복사
    character = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(1)').text
    # 출연진 정보 selector 복사
    character_2 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(2)').text
    # 출연진이 따로 따로 저장되어 있어 두번째 등장인물 저장
    character_3 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(3)').text
    # 세 명까지 저장
    desc = soup.select_one('#menu > div.col-detail > div.sect-story-movie').text.strip()
    # meta tag에 없던 세부 설명을 가져오기 위해 selector 따로 복사


    doc = {
        'title' : ogtitle.replace(' | 영화 그 이상의 감동. CGV',''),
        # 'desc' : ogdesc,
        'desc' : desc,
        'image' : ogimage,
        'comment' : comment_receive,
        'star' : star_receive,
        'derector' : derector,
        'character1' : character,
        'character2' : character_2,
        'character3' : character_3
    }
    db.main.insert_one(doc)
    # main이라는 콜렉션 생성, 데이터들 가져와서 저장하기

    return jsonify({'msg':'등록 완료!'}) # 위 코드가 정상 작동 시 등록 완료라는 메시지 반환

@app.route("/movie", methods=["GET"])
def movie_get():
    all_movies = list(db.main.find({},{'_id':False})) 
    # db에서 main 콜렉션에 있는 데이터들을 리스트화 해서 저장
    return jsonify({'result': all_movies}) # 저장한 값 반환

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

 

중간 과정 총 정리

 

app.py 생성

templates 폴더 생성 -> index.html 생성 (백엔드를 담당하지만 정상 작동 시험용)

app.py에서 python -m venv venv 로 가상환경 설정

$ pip install flask pymongo dnspython requests bs4 - 필요한 패키지 설치

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

@app.route('/')
def home():
    return render_template('index.html')

@app.route("/movie", methods=["POST"])
def movie_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg':'POST 연결 완료!'})

@app.route("/movie", methods=["GET"])
def movie_get():
    return jsonify({'msg':'GET 연결 완료!'})

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

전에 공부할 때 만든 기본 틀 사용

 

	url_receive = request.form['url_give']
    # 입력한 url 저장
    comment_receive = request.form['comment_give']
    # 입력한 comment 저장
    star_receive = request.form['star_give']
    # 입력한 별점 저장

등록 페이지에서 입력하는 내용을 저장하기 위한 코드

 

    headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogimage = soup.select_one('meta[property="og:image"]')['content']
    ogdesc = soup.select_one('meta[property="og:description"]')['content']

메타 태그를 사용하기 위한 기본 코드 

 

    derector = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(2) > a').text
    # 감독 정보 selector 복사
    character = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(1)').text
    # 출연진 정보 selector 복사
    character_2 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(2)').text
    # 출연진이 따로 따로 저장되어 있어 두번째 등장인물 저장
    character_3 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(3)').text
    # 세 명까지 저장
    desc = soup.select_one('#menu > div.col-detail > div.sect-story-movie').text.strip()
    # meta tag에 없던 세부 설명을 가져오기 위해 selector 따로 복사

메타 태그에는 없지만 프로젝트에서 목표로 한 정보를 담기 위해 url에서 가져올 정보들을 bs4를 이용해 저장

 

    doc = {
        'title' : ogtitle.replace(' | 영화 그 이상의 감동. CGV',''),
        # 'desc' : ogdesc,
        'desc' : desc,
        'image' : ogimage,
        'comment' : comment_receive,
        'star' : star_receive,
        'derector' : derector,
        'character1' : character,
        'character2' : character_2,
        'character3' : character_3
    }
    db.main.insert_one(doc)

필요한 데이터들 main컬렉션에 저장

 

@app.route("/movie", methods=["GET"])
def movie_get():
    all_movies = list(db.main.find({},{'_id':False})) 
    # db에서 main 콜렉션에 있는 데이터들을 리스트화 해서 저장
    return jsonify({'result': all_movies}) # 저장한 값 반환

저장한 데이터들을 get으로 읽기

 

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

실험하기 위해 local호스트연결 (localhost:5000)

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

 

이상으로 메인 화면 영화 등록 기능 구현을 완료했고, 상세 페이지를 구현할 차례다.

@app.route("/movie_list", methods=["GET"]) # 메인화면에서 목록을 불러오기 위한 get
def movie_list():
    all_movies = list(db.main.find({},{'_id':False},{'derector':False},{'character1':False},{'character2':False},{'character3':False},{'comment':False})) # 코멘트, 감독, 등장인물은 메인화면에서 표시하지 않을 것이기 때문에 제외
    # db에서 main 콜렉션에 있는 데이터들을 리스트화 해서 저장
    return jsonify({'result': all_movies}) # 저장한 값 반환

@app.route("/movie_desc", methods=["GET"]) # 상세 페이지에서 정보를 불러오기 위한 get
def movie_desc():
    specific_movie = list(db.main.find({},{'_id':False})) # 데이터 베이스의 모든 정보를 가져올 것
    return jsonify({'result':specific_movie})

메인페이지에서 불러올 정보와 상세 페이지에서 불러올 정보를 구분하기 위해 post를 하나 더 만들고, 이름을 직관적으로 수정했다.

 

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.oid4wb8.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta
# mongodb연결 및 dbspata라는 데이터베이스 지정

import requests
from bs4 import BeautifulSoup

@app.route('/')
def home():
    return render_template('index.html')

@app.route("/movie", methods=["POST"]) # 등록 페이지에서 url, comment, 별점 입력시 상세페이지 및 메인 페이지에서 출력할 정보들 저장하는 post
def movie_post():
    url_receive = request.form['url_give']
    # 입력한 url 저장
    comment_receive = request.form['comment_give']
    # 입력한 comment 저장
    star_receive = request.form['star_give']
    # 입력한 별점 저장

    headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogimage = soup.select_one('meta[property="og:image"]')['content']
    # ogdesc = soup.select_one('meta[property="og:description"]')['content'] # cgv에는 og:description 태그 부분이 없기에 주석처리
    # meta tag에서 제목, 이미지, 간단 설명 스크랩하는 코드

    derector = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(2) > a').text
    # 감독 정보 selector 복사
    character = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(1)').text
    # 출연진 정보 selector 복사
    character_2 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(2)').text
    # 출연진이 따로 따로 저장되어 있어 두번째 등장인물 저장
    character_3 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(3)').text
    # 세 명까지 저장
    desc = soup.select_one('#menu > div.col-detail > div.sect-story-movie').text.strip()
    # meta tag에 없던 세부 설명을 가져오기 위해 selector 따로 복사


    doc = {
        'title' : ogtitle.replace(' | 영화 그 이상의 감동. CGV',''),
        'desc' : desc,
        'image' : ogimage,
        'comment' : comment_receive,
        'star' : star_receive,
        'derector' : derector,
        'character1' : character,
        'character2' : character_2,
        'character3' : character_3
    }
    db.main.insert_one(doc)
    # main이라는 콜렉션 생성, 데이터들 가져와서 저장하기

    return jsonify({'msg':'등록 완료!'}) # 위 코드가 정상 작동 시 등록 완료라는 메시지 반환

@app.route("/movie_list", methods=["GET"]) # 메인화면에서 목록을 불러오기 위한 get
def movie_list():
    all_movies = list(db.main.find({},{'_id':False},{'character1':False},{'character2':False},{'character3':False},{'comment':False})) # 코멘트, 등장인물은 메인화면에서 표시하지 않을 것이기 때문에 제외
    # db에서 main 콜렉션에 있는 데이터들을 리스트화 해서 저장
    return jsonify({'result': all_movies}) # 저장한 값 반환

@app.route("/movie_desc", methods=["GET"]) # 상세 페이지에서 정보를 불러오기 위한 get
def movie_desc():
    specific_movie = list(db.main.find({},{'_id':False})) # 데이터 베이스의 모든 정보를 가져올 것
    return jsonify({'result':specific_movie})

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

 

위 코드로 진행시 알 수 없는 오류가 발생해 중간 완성코드로 되돌렸다.

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.oid4wb8.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta
# mongodb연결 및 dbspata라는 데이터베이스 지정

import requests
from bs4 import BeautifulSoup

@app.route('/')
def home():
    return render_template('index.html')

@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give']
    # 입력한 url 저장
    comment_receive = request.form['comment_give']
    # 입력한 comment 저장
    star_receive = request.form['star_give']
    # 입력한 별점 저장

    headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogimage = soup.select_one('meta[property="og:image"]')['content']
    # ogdesc = soup.select_one('meta[property="og:description"]')['content'] # cgv에는 og:description 태그 부분이 없기에 주석처리
    # meta tag에서 제목, 이미지, 간단 설명 스크랩하는 코드

    derector = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(2) > a').text
    # 감독 정보 selector 복사
    character = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(1)').text
    # 출연진 정보 selector 복사
    character_2 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(2)').text
    # 출연진이 따로 따로 저장되어 있어 두번째 등장인물 저장
    character_3 = soup.select_one('#select_main > div.sect-base-movie > div.box-contents > div.spec > dl > dd:nth-child(5) > a:nth-child(3)').text
    # 세 명까지 저장
    desc = soup.select_one('#menu > div.col-detail > div.sect-story-movie').text.strip()
    # meta tag에 없던 세부 설명을 가져오기 위해 selector 따로 복사


    doc = {
        'title' : ogtitle.replace(' | 영화 그 이상의 감동. CGV',''),
        # 'desc' : ogdesc,
        'desc' : desc,
        'image' : ogimage,
        'comment' : comment_receive,
        'star' : star_receive,
        'derector' : derector,
        'character1' : character,
        'character2' : character_2,
        'character3' : character_3
    }
    db.main.insert_one(doc)
    # main이라는 콜렉션 생성, 데이터들 가져와서 저장하기

    return jsonify({'msg':'등록 완료!'}) # 위 코드가 정상 작동 시 등록 완료라는 메시지 반환

@app.route("/movie", methods=["GET"])
def movie_get():
    all_movies = list(db.main.find({},{'_id':False})) 
    # db에서 main 콜렉션에 있는 데이터들을 리스트화 해서 저장
    return jsonify({'result': all_movies}) # 저장한 값 반환

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

'TIL > 내배캠 사전캠프' 카테고리의 다른 글

23.05.11  (0) 2023.05.11
23.05.11  (0) 2023.05.11
23.05.10  (0) 2023.05.10
23.05.08  (0) 2023.05.08