[Python + Flask + Crawling] 스파르타 코딩 4주 차 7-1번째 수업

안영우·2020년 10월 23일
0
post-thumbnail

✏️ 서론

지난 시간에는 [ 모두의 책리뷰 ] 예제를 실습하며 API에 대해 공부 해 볼 수 있었다.

이번 시간에는 비슷하게 API기능을 사용하되, PythonCrawling기능을 더하는 [나 홀로 메모장] 예제를 실습해보자.

전체적인 구조는 다음과 같다.

1. 저장하고 싶은 `URL`을 가져온다.
2. 코멘트를 작성한다.

➡️ 결과 
해당 `URL`의 `title`, `image`, `description`내용과 
내가 작성한 `Comment`을 불러오고 나의`DB`에 저장 된 내용을 불러온다.

💡 잠깐, Crawling을 어떻게 할까?

우리가 흔히 SNS를 통해 URL을 공유하면 다음과 같은 화면을 볼 수 있다.

이는 해당 URLmeta_tag를 가져온 것인데, 이를 사용하여 crawling 코드를 작성하면 내용을 쉽게 가져 올 수 있다.

다음과 같은 코드를 작성해보자.

지금 사용할 기능은 pythonrequests, BeautifulSoup4 패키지이다.

import requests
from bs4 import BeautifulSoup

# 가져오고 싶은 `URL`
url = ''
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, headers=headers)

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

meta_title = soup.select_one('meta[property="og:title"]')
meta_image = soup.select_one('meta[property="og:image"]')
meta_description = soup.select_one('meta[property="og:description"]')

print(meta_title['content'])
print(meta_image['content'])
print(meta_description['content])

실행결과는 다음과 같다.

URL을 공유했을 때 나오는 화면과 동일하다.
성공적으로 예제를 마쳤다.


✏️ 본론

Flask Server 코드

import flask import Flask, render_template, jsonify, request
from bs4 import BeautionfulSoup
from pymongo import MongoClient

app = Flask(__name__)

clinet = MongoClient('localhost', 27017)
db = client.dbsparta

@app.route('/')
def home():
return render_template('index.html')
    
@app.route('/memo', method=['POST'])
def post_article():

# 클라이언트부터 데이터 받기
    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'}
    url = request.form.get('url')
    comment = request.form.get('comment')
    
    data = requests.get(url, headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')
    
# meta_tag 스크래핑
    title = soup.select_one('meta[property="og:title"]')
    image = soup.select_one('meta[property="og:image"]')
    desc = soup.select_one('meta[property="og:description"]')

    meta_title = title['content']
    meta_image = image['content']
    meta_desc = desc['content']
    
    print('client에서 온 title: ', meta_title)
    print('client에서 온 image_url: ', meta_image)
    print('client에서 온 desc: ', meta_desc)
    
 # mongoDB에 data 입력   
     web_list = {
        'url': url,
        'title': meta_title,
        'image': meta_image,
        'desc': meta_desc,
        'comment': comment
    }

    db.self_memo.insert_one(web_list)
    return jsonify({'result': 'success', 'msg': '성공적으로 작성되었습니다.'})

@app.route('/memo', methods=['GET'])
def read_articles():
    # mongoDB에서 모든 데이터 조회
    web_lists = list(db.self_memo.find({}, {'_id': False}))
    return jsonify({'result': success, 'msg': '성공적으로 리뷰를 가져왔습니다.', 'web_lists: web_lists})
    
    if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True) 

Server단에서 동작시킨 후 Client에서 내용을 넘기면 다음과 같이 뜬다.

urlcommentnone값으로 출력되는데,
그 이유는 Client단에서 작성한 POST API에서 urlcomment 값을 입력하지 않았기 때문이다.

[line:78]data:{} 값을 다음과 같이 추가하면 드디어 Server로 데이타가 넘어간다.

📍주의 할 점은 urlcomment 변수는 Server에서 정한다는 것이다.

data: {'url': url, 'commnet': comment}

HTML Client Function 코드

<script>
    $(document).ready(function () {
        $("#cards-box").html("");
        showArticles();
    });
    
// `Server` `POST` 함수이다.
function postArticle() {
        let url = $(`#post-url`).val()
        let comment = $(`#post-comment`).val()

        $.ajax({
            type: "POST",
            url: "/memo",
            data: {'url': url, 'comment': comment},
            success: function (response) {
                if (response["result"] == "success") {
                    console.log("정상적으로 요청되었습니다.", response, response[url, comment])
                    alert(response["msg"]);
//.reload코드로 강제로 새로고침을 해줘야 
// 따로 `F5` 버튼을 누르지 않고도 `card` 값이 입력된다.
                    window.location.reload();
                }
            }
        })
    }

    function showArticles() {
        $.ajax({
            type: "GET",
            url: "/memo",
            data: {},
            success: function (response) {
                if (response["result"] == "success") {
                    let web_lists = response['web_lists']
                    for (let i = 0; i < web_lists.length; i++) {
                        let web_list = web_lists[i]
                        let {title, image, desc, url, comment} = web_list
                        
// `tempHtml` .append 함수로 새로운 데이터를 추가해준다.
                        let tempHtml = `
                                            <div class="card">
                                            <img class="card-img-top"
                                                 src="${image}"
                                                 alt="Card image cap">
                                            <div class="card-body">
                                            <a href="${url}" class="card-title">${title}</a>
                                            <p class="card-text">${desc}</p>
                                            <p class="card-text comment">${comment}</p>
                                            </div>
                                            </div>`
                        $(`#cards-box`).append(tempHtml)
                    }
                } else {
                    alert('DB를 정상적으로 가져오지 못했습니다.')
                }
            }
        })
    }

    function makeCard(url, title, desc, comment, image) {
    }
</script>

실험결과는 다음과 같다.
아티클 URL간단 코멘트를 입력하고 기사 저장을 누르면

이런식으로 따로 F5버튼을 누르지 않고도 자동으로 새로고침이 된다.

Client에서 입력한 값: URL, Comment
Crawling코드로 수집한 값: image, title, description

이렇게 분석 가능하다.


✏️ 결론

오늘은 저번시간에 배웠던 내용에 Crawling 기술을 더한 나만의 메모장 기능을 만들어보았다. 처음 수강할때는 어떤 원리로 진행되는지 이해가 잘 안됐지만 따로 1~2시간정도 복습하다보니 자연스럽게 과정을 이해 할 수 있었다.

나중에는 내가 원하는 단어가 들어가있는 뉴스 기사를 Crawling하여 나만의 뉴스스탠드 를 만들 수 있을 것 같다.


🗣 끝으로

개발자는 삽질의 직업

이라는 문장을 지나가다 들은적이 있다.
처음들었을때는 삽질만해서 어떻게 구덩이를 파 라는 생각을 했으나
삽질을 하면서 점차 나중에는 산도 옮길 수 있을 것 같다는 생각이 들었다.

내가 하고 있는 과정이 올바른 길인지 궁금할땐 끝까지 파보고나서 후회하자.

profile
YW_Tech

0개의 댓글