티스토리 뷰

반응형

네이버 뉴스에서 신문사, 헤드라인, 요약 크롤링해오기.

 

1) 사이트에서 검사 > Copy > Copy Selector로 2개 가져오기.

2) 두개 중에 공통되는 부분이 어디인지 찾아보기.

3) 공통이 될 수 있는 부분을 select('')로 묶어서 변수 하나 설정해주기.

4) for문을 돌려서 반복을 할 수 있게 하고, 제목, 가수, 순위 별로 변수 설정하기.

5) 변수에는 Copy Selector에서 반복되지 않는 각각의 요소를 넣기

6) .text 함수를 이용해서 그 안에 있는 내부 데이터만 읽어오기.

 

 

 

크롤링 진행

  1. parsing 방안 및 위치 확인
  2. request 방법 확인
  3. data 저장 형태 설계

최종 데이터 생성

  1. 데이터 저장 형태
  2. 데이터 저장
패키지 명 용도
requests 웹페이지 소스 추출(HTML)
bs4 HTML 파싱, 필요 태그 및 소스 추출
re 조건부 문자열(정규 표현식), 태그 탐색 시 일반화 조건을 사용하기 위함
pandas 데이터 프레임, 엑셀 변환

 

 

<서버쪽 코드>

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


from pymongo import MongoClient
client = MongoClient('mongodb+srv://test:sparta@cluster0.klhr9in.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta


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('https://news.daum.net/',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')


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

@app.route("/news", methods=["GET"])
def news_get():
    db.news.delete_many({})
    news = soup.select(
        'body > div.container-doc > main > section > div > div.content-article > div.box_g.box_news_issue > ul > li')

    for new in news:
        article4 = new.select_one('div > div > strong > a').text.strip()
        print(article4)

        doc = {
            'title': article4
        }
        db.news.insert_one(doc)

    news_list = list(db.news.find({}, {'_id': False}))
    return jsonify({'news':news_list})

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

다음 뉴스에서 실시간 뉴스를 가져와서 한줄한줄 DB에 집어 넣는 코드

 

핵심코드

news = soup.select('body > div.container-doc > main > section > div > div.content-article > div.box_g.box_news_issue > ul > li')

 

    #뉴스 DB에서 Text만 추출하여 article4에 입력해라. 
    for new in news:
        article4 = new.select_one('div > div > strong > a').text.strip()
        #print(article4)

 

        #doc라는 리스트타입 정보중 title이라는 칸에 article4(기사)를 입력해라)
        doc = {
            'title': article4
        }

 

        #DB에 1줄 입력해라.
        db.news.insert_one(doc)

 

    #뉴스 리스트를 DB에서 다 찾아서 리스트업을 하고, return해라.
    news_list = list(db.news.find({}, {'_id': False}))
    return jsonify({'news':news_list})

 

 

 

 

<클라이언트 코드>

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
            crossorigin="anonymous"></script>

    <title>오늘의 뉴스</title>

    <link href="https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap" rel="stylesheet">

    <style>
        * {
            font-family: 'Gowun Dodum', sans-serif;
        }

        .mytitle {
            width: 100%;
            height: 250px;

            background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://www.collinsdictionary.com/images/full/newspaper_127408157_1000.jpg');
            background-position: 86% 14%;
            background-size: cover;

            color: white;

            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .mytitle > button {
            width: 200px;
            height: 50px;

            background-color: transparent;
            color: white;

            border-radius: 50px;
            border: 1px solid white;

            margin-top: 10px;
        }

        .mytitle > button:hover {
            border: 2px solid white;
        }

        .mycomment {
            color: gray;
        }

        .mycards {
            margin: 20px auto 0px auto;
            width: 95%;
            max-width: 1200px;
        }

        .mypost {
            width: 95%;
            max-width: 500px;
            margin: 20px auto 0px auto;
            padding: 20px;
            box-shadow: 0px 0px 3px 0px gray;

            display: none;
        }

        .mybtns {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: center;

            margin-top: 20px;
        }

        .mybtns > button {
            margin-right: 10px;
        }
    </style>
</head>
<script>
    $(document).ready(function () {
        listing();
    });

    function listing() {
        $.ajax({
            type: 'GET',
            url: '/news',
            data: {},
            success: function (response) {
                let rows = response['news']
                console.log(rows)
                for (let i = 0; i < rows.length; i++ ){
                    let article = rows[i]['title']
                    let temp_html = `<div class="card-body">
                                       <h5 class="card-title">${article}</h5>
                                     </div>`
                    $('#cards-box').append(temp_html)
                }
            }
        })

    }

    function posting() {
        let url = $('#url').val()
        let star = $('#star').val()
        let comment = $('#comment').val()

        $.ajax({
            type: 'POST',
            url: '/news',
            data: {},
            success: function (response) {
                alert(response['msg'])
                window.location.reload()
            }
        });
    }

    function open_box() {
        
        $('#listing').show()
    }

    function close_box() {
        $('#post-box').hide()
    }
</script>

<body>
<div class="mytitle">
    <h1>오늘의 뉴스</h1>
    <button onclick="open_box()">뉴스 보기</button>
</div>
<div class="mycards">
    <div class="row row-cols-1 row-cols-md-4 g-4" id="cards-box">

    </div>
</div>
</body>

</html>

 

 

문제점.

 

1. 화면이 깨끗하게 출력되도록 바꿔야 한다. 

    해결 : POST로 데이터를 입력해서 받는 것이 아닌 GET타입에서 바로 데이터를 받아서 출력하게 만듬.

 


2. 서버에 올려야 하는데 안올라간다.

    해결 : git Bash에서 ssh -i를 통해서 내 프로젝트까지 가기. python app.py 실행. 에러 발생.

              bs4 패키지가 미설치 되어있었음 pip install bs4를 실행하니 정상으로 동작을 함.

 

 

3. 중복된 기사가 계속해서 출력이 됨.

 

반응형
댓글