티스토리 뷰
네이버 뉴스에서 신문사, 헤드라인, 요약 크롤링해오기.
1) 사이트에서 검사 > Copy > Copy Selector로 2개 가져오기.
2) 두개 중에 공통되는 부분이 어디인지 찾아보기.
3) 공통이 될 수 있는 부분을 select('')로 묶어서 변수 하나 설정해주기.
4) for문을 돌려서 반복을 할 수 있게 하고, 제목, 가수, 순위 별로 변수 설정하기.
5) 변수에는 Copy Selector에서 반복되지 않는 각각의 요소를 넣기
6) .text 함수를 이용해서 그 안에 있는 내부 데이터만 읽어오기.
크롤링 진행
- parsing 방안 및 위치 확인
- request 방법 확인
- data 저장 형태 설계
최종 데이터 생성
- 데이터 저장 형태
- 데이터 저장
패키지 명 | 용도 |
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. 중복된 기사가 계속해서 출력이 됨.