쿠버네티스,쿠버플로우
던전앤파이터 시세 예측[장고]
세용용용용
2023. 9. 1. 20:16
이제 장고를 사용해 던파 사이트를 만들어 보자
먼저 로컬에서 테스트 해보자
로컬 마리아db에 테이블을 만들고 데이터를 넣어보자


장고로 테이블 불러와서 웹에 띄우자!!
# asgi.py
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_asgi_application()
----------------------------------------------------------------------------------------
# settings.py
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-u$l2=t)pk-4wsqmn6lu&=7u*jyjjqa%971&k-+(p8zfw(&j6)9'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pybo',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
#DATABASES = {
#'default': {
#'ENGINE': 'django.db.backends.sqlite3',
#'NAME': BASE_DIR / 'db.sqlite3',
#}
#}
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME' : 'donpa_item',
'USER' : 'root',
'PASSWORD' : '1234', #MariaDB 로그인 시 비밀번호
'HOST' : 'localhost', #디폴트는 로컬호스트
'PORT' : '3306', #기본은 3306인데 저는 다른 DBMS가 3306을 쓰고 있어서 3307로 했습니다.
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'ko-kr'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
----------------------------------------------------------------------------------------
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
# 기존의 pybo 앱 URL 매핑
path('pybo/', include('pybo.urls')),
# 추가적으로 루트 URL('/')로 접속시 pybo 앱의 URL 매핑을 처리하도록 설정
path('', include('pybo.urls')),
path('admin/', admin.site.urls),
]
----------------------------------------------------------------------------------------
# wsgi.py
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_wsgi_application()
python manage.py inspectdb donpa_item1 >>> 테이블 스키마 확인하는 코드!!
apps.py
from django.apps import AppConfig
class PyboConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'pybo'
models.py
from django.db import models
class DonpaItem1(models.Model):
item_img = models.TextField(blank=True, null=True)
item_name = models.TextField(blank=True, null=True)
price = models.FloatField(blank=True, null=True)
before_now = models.FloatField(blank=True, null=True)
before_one = models.FloatField(blank=True, null=True)
before_two = models.FloatField(blank=True, null=True)
before_three = models.FloatField(blank=True, null=True)
before_four = models.FloatField(blank=True, null=True)
before_five = models.FloatField(blank=True, null=True)
before_six = models.FloatField(blank=True, null=True)
before_seven = models.FloatField(blank=True, null=True)
before_eight = models.FloatField(blank=True, null=True)
before_nine = models.FloatField(blank=True, null=True)
before_ten = models.FloatField(blank=True, null=True)
class Meta:
managed = False
db_table = 'donpa_item1'
urls.py
urlpatterns = [
path('', views.item_list),
path('aabata/', views.aabata_view, name='aabata'),
path('event/', views.events_view, name='event'),
path('news/', views.news_view, name='news'), # /news/ 경로에 news_view를 연결
# 다른 URL 패턴들...
]
views.py
from django.shortcuts import render
from .models import DonpaItem1
def item_list(request):
items = DonpaItem1.objects.all()
return render(request, 'index.html', {'items': items})
index.html
<!DOCTYPE html>
<html>
<head>
<title>Item List</title>
<style>
/* 표 스타일링 */
table {
width: 80%; /* 표의 너비를 조절하세요 */
border-collapse: collapse;
margin: 20px auto; /* 가운데 정렬 */
}
th, td {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
/* 이미지 크기 조정 */
img {
width: 100px; /* 이미지의 너비를 조절하세요 */
height: auto; /* 이미지 높이 자동 조절 */
}
/* 제목 */
h1 {
font-size: 46px; /* 큰 제목 크기로 변경 */
color: #f7e706; /* 게임 색상으로 변경 */
text-align: center;/* 제목 가운데 정렬*/
}
/* 메뉴 스타일링 */
ul.menu {
list-style-type: none;
margin: 0;
padding: 0;
text-align: center;
padding: 10px 0; /* 메뉴 항목 위아래로 간격 추가 */
}
ul.menu li {
display: inline;
margin-right: 20px;
font-size: 40px;
}
ul.menu li a {
color: rgb(255, 255, 255);
text-decoration: none;
padding: 10px 20px; /* 각 메뉴 항목의 내부 여백 추가 */
border-radius: 5px; /* 각 메뉴 항목을 둥글게 꾸미기 */
/* background-color: #534747; /* 배경색 추가 */
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); /* 그림자 효과 추가 */
transition: background-color 0.3s, transform 0.2s; /* 호버 효과를 위한 트랜지션 설정 */
}
ul.menu li a:hover {
background-color: #4e2626; /* 호버 시 배경색 변경 */
transform: translateY(-2px); /* 호버 시 약간 위로 이동 효과 */
}
/* 차트 컨테이너 스타일링 */
.chart-container {
width: 90%; /* 차트 컨테이너의 너비를 조절하세요 */
margin: 20px /* 가운데 정렬 */
}
/* item-name 스타일 */
.item-name {
font-weight: bold; /* 굵은 글씨체 */
color: #007BFF; /* 텍스트 색상 변경 */
font-size: 18px; /* 글씨 크기 변경 */
}
/* item-price 스타일 */
.item-price {
font-weight: bold; /* 굵은 글씨체 */
color: #28A745; /* 텍스트 색상 변경 */
font-size: 18px; /* 글씨 크기 변경 */
}
/* 배경 이미지 추가 */
body {
background-image: url('https://mblogthumb-phinf.pstatic.net/20160909_66/neoplog_1473407324296hgvz4_JPEG/1_%B9%F6%BC%B8%C1%A4%BF%F8.jpg?type=w800');
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
position: relative;
z-index: 0;
}
/* 표 스타일링 */
table {
width: 80%; /* 표의 너비를 조절하세요 */
border-collapse: collapse;
margin: 20px auto; /* 가운데 정렬 */
position: relative; /* z-index를 사용하기 위해 설정 */
z-index: 1; /* 표의 z-index를 배경 이미지 위로 설정 */
}
th, td {
border: 4px solid #000000;
background-color: #dddddd;
text-align: left;
padding: 18px;
}
th {
background-color: #ff0000;
}
</style>
<!-- Chart.js 추가 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
</head>
<body>
<ul class="menu">
<li><a href="/">아이템 시세</a></li>
<li><a href="/aabata/">아바타 시세</a></li>
<li><a href="/event/">진행 중 이벤트</a></li>
<li><a href="/news/">던파 소식</a></li>
</ul>
<h1>던전앤파이터 아이템</h1>
<table>
<thead>
<tr>
<th>아이템 이미지</th>
<th>아이템 명</th>
<th>1시간뒤 예상 가격</th>
<th>아이템 가격 변동</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td><img src="{{ item.item_img }}" alt="Item Image"></td>
<td><span class="item-name">{{ item.item_name }}</span></td>
<td><span class="item-price">{{ item.price }}</span></td>
<td>
<div class="chart-container">
<canvas class="line-chart" data-values="{{ item.before_ten }}, {{ item.before_nine }}, {{ item.before_eight }}, {{ item.before_seven }}, {{ item.before_six }}, {{ item.before_five }}, {{ item.before_four }}, {{ item.before_three }}, {{ item.before_two }}, {{ item.before_one }}, {{ item.before_now }}"></canvas>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- JavaScript로 그래프 그리기 -->
<script>
// 모든 차트를 가져와서 데이터를 설정하고 그립니다.
const charts = document.querySelectorAll('.line-chart');
charts.forEach(chart => {
const values = chart.dataset.values.split(', ').map(value => parseFloat(value));
new Chart(chart, {
type: 'line',
data: {
labels: ['10시간 전', '9시간 전', '8시간 전', '7시간 전', '6시간 전', '5시간 전', '4시간 전', '3시간 전', '2시간 전', '1시간 전', '0시간 전'],
datasets: [{
data: values,
borderColor: '#ff6600', /* 게임 스타일 색상으로 변경 */
backgroundColor: 'rgba(255, 102, 0, 0.2)', /* 배경색 추가 */
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: false
}
}
}
});
});
</script>
</body>
</html>
이제 던파 뉴스와 이벤트목록을 크롤링해와서 장고에 띄워보자
1. 크롤링해와서 마리아db테이블에 저장하고
던파 뉴스 부터 만들어보자
먼저 던파 뉴스 테이블을 생성해주자
테이블 생성 코드 : create table donpa_news ( photo TEXT, title TEXT, link TEXT );
크롤링해서 테이블에 데이터는 넣는 코드
import requests
from bs4 import BeautifulSoup
import pymysql
# MySQL 연결 설정
conn = pymysql.connect(
host='localhost', # 호스트명
user='root', # 데이터베이스 사용자명
password='1234', # 데이터베이스 암호
db='donpa_item', # 데이터베이스 이름
port = 3306
)
# 커서 생성
cursor = conn.cursor()
# 크롤링 코드 작성
photo_list = []
title_list = []
link_list = []
# 검색 결과 페이지 URL
url = "https://search.naver.com/search.naver?where=news&query=%EB%8D%98%ED%8C%8C&sm=tab_opt&sort=1&photo=1&field=0&pd=0&ds=&de=&docid=&related=0&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so%3Add%2Cp%3Aall&is_sug_officeid=0&office_category=0&service_area=0"
# HTTP GET 요청
response = requests.get(url)
# 응답 데이터 파싱
soup = BeautifulSoup(response.text, "html.parser")
select_num = 1
while select_num<=10:
# 이미지 선택자
selector = f"#sp_nws{select_num} > div > a > img"
# 선택자에 해당하는 이미지 요소를 찾음
image = soup.select_one(selector)
# 각 링크의 href 속성값을 출력
photo = image.get("data-lazysrc")
photo_list.append(photo)
select_num+=1
# 뉴스 타이틀, 링크 선택자
selector = "#main_pack > section.sc_new.sp_nnews._prs_nws > div > div.group_news > ul > li> div > div > a"
# 선택자에 해당하는 요소들을 모두 찾음
title_link = soup.select(selector)
# 각 타이틀,링크 속성값을 출력
for link in links:
title = link.get("title")
href = link.get("href")
title_list.append(title)
link_list.append(href)
# 테이블 초기화 (기존 데이터 삭제)
truncate_sql = "TRUNCATE TABLE donpa_news"
cursor.execute(truncate_sql)
# 데이터베이스에 데이터 삽입
for i in range(len(photo_list)):
photo = photo_list[i]
title = title_list[i]
link = link_list[i]
sql = "INSERT INTO donpa_news (photo, title, link) VALUES (%s, %s, %s)"
cursor.execute(sql, (photo, title, link))
# 변경사항 커밋
conn.commit()
# 연결 종료
conn.close()
models.py수정
from django.db import models
class DonpaItem1(models.Model):
item_img = models.TextField(blank=True, null=True)
item_name = models.TextField(blank=True, null=False, primary_key=True) # null=False로 수정
price = models.FloatField(blank=True, null=True)
before_now = models.FloatField(blank=True, null=True)
before_one = models.FloatField(blank=True, null=True)
before_two = models.FloatField(blank=True, null=True)
before_three = models.FloatField(blank=True, null=True)
before_four = models.FloatField(blank=True, null=True)
before_five = models.FloatField(blank=True, null=True)
before_six = models.FloatField(blank=True, null=True)
before_seven = models.FloatField(blank=True, null=True)
before_eight = models.FloatField(blank=True, null=True)
before_nine = models.FloatField(blank=True, null=True)
before_ten = models.FloatField(blank=True, null=True)
class Meta:
managed = False
db_table = 'donpa_item1'
class DonpaNews(models.Model):
photo = models.TextField(blank=True, null=True)
title = models.TextField(blank=True, null=True)
link = models.TextField(blank=True, null=False, primary_key=True)
class Meta:
managed = False
db_table = 'donpa_news'
python manage.py makemigrations
python manage.py migrate
모델이 변경되었을떄 적용시켜주는 명령어
view.py
from django.shortcuts import render
from .models import DonpaItem1
from .models import DonpaNews
def item_list(request):
items = DonpaItem1.objects.all()
return render(request, 'index.html', {'items': items})
def aabata_view(request):
# news.html 템플릿 렌더링
return render(request, 'aabata.html')
def events_view(request):
# news.html 템플릿 렌더링
return render(request, 'event.html')
def news_view(request):
# news.html 템플릿 렌더링
items = DonpaNews.objects.all()
return render(request, 'news.html', {'items':items})
news.html
<!DOCTYPE html>
<html>
<head>
<title>Item List</title>
<style>
/* 제목 */
h1 {
font-size: 46px; /* 큰 제목 크기로 변경 */
color: #f7e706; /* 게임 색상으로 변경 */
text-align: center;/* 제목 가운데 정렬*/
}
/* 메뉴 스타일링 */
ul.menu {
list-style-type: none;
margin: 0;
padding: 0;
text-align: center;
padding: 10px 0; /* 메뉴 항목 위아래로 간격 추가 */
}
ul.menu li {
display: inline;
margin-right: 20px;
font-size: 40px;
}
ul.menu li a {
color: rgb(255, 255, 255);
text-decoration: none;
padding: 10px 20px; /* 각 메뉴 항목의 내부 여백 추가 */
border-radius: 5px; /* 각 메뉴 항목을 둥글게 꾸미기 */
/* background-color: #534747; /* 배경색 추가 */
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); /* 그림자 효과 추가 */
transition: background-color 0.3s, transform 0.2s; /* 호버 효과를 위한 트랜지션 설정 */
}
ul.menu li a:hover {
background-color: #4e2626; /* 호버 시 배경색 변경 */
transform: translateY(-2px); /* 호버 시 약간 위로 이동 효과 */
}
/* 배경 이미지 추가 */
body {
background-image: url('https://bbscdn.df.nexon.com/data7/commu/201712/205032_5a44da887e6a8.jpg');
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
position: relative;
z-index: 0;
}
/* 테이블 스타일링 */
table {
margin: 0 auto; /* 가운데 정렬 */
border-collapse: collapse; /* 테이블 셀 경계 표시 제거 */
width: 70%; /* 테이블의 너비를 조절하세요 */
height: 0%;
}
/* 테이블 셀 스타일링 */
table, th, td {
border: 5px solid #ddd; /* 테이블 셀 테두리 스타일 */
}
th, td {
padding: 0px; /* 셀 내부 여백 추가 */
text-align: center; /* 가운데 정렬 */
vertical-align: middle; /* 셀 내용 세로 중앙 정렬 */
}
/* 뉴스 타이틀 스타일링 */
.item-title {
font-size: 280%; /* 글꼴 크기 설정 */
color: #bee60d; /* 글꼴 색상 설정 */
text-decoration: none; /* 밑줄 제거 */
font-weight: bold; /* 글꼴 굵게 설정 */
}
/* 이미지 스타일링 */
img {
width: 100%;
height: auto; /* 높이 자동 조정 */
}
</style>
</head>
<body>
<ul class="menu">
<li><a href="/">아이템 시세</a></li>
<li><a href="/aabata/">아바타 시세</a></li>
<li><a href="/event/">진행 중 이벤트</a></li>
<li><a href="/news/">던파 소식</a></li>
</ul>
<h1>던전앤파이터 뉴스</h1>
<table>
<thead>
<tr>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td><img src="{{ item.photo }}" alt="Item Image"></td>
<td><a href="{{ item.link }}" class="item-title">{{ item.title }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
이제 던파 이벤트를 띄워보자
테이블 생성 코드
MariaDB [donpa_item]> create table donpa_event(
-> img TEXT,
-> text TEXT,
-> date TEXT,
-> herf TEXT
-> );
크롤링해서 테이블에 데이터 넣는 코드
import requests
from bs4 import BeautifulSoup
import re
import pymysql
# MySQL 연결 설정
conn = pymysql.connect(
host='localhost', # 호스트명
user='root', # 데이터베이스 사용자명
password='1234', # 데이터베이스 암호
db='donpa_item', # 데이터베이스 이름
port = 3306
)
# 커서 생성
cursor = conn.cursor()
eve_img = []
eve_text = []
eve_date = []
eve_herf = []
# 검색 결과 페이지 URL
url = "https://df.nexon.com/community/news/event/list"
# HTTP GET 요청
response = requests.get(url)
# 응답 데이터 파싱
soup = BeautifulSoup(response.text, "html.parser")
# 이벤트 img 셀렉터
selector_img = "#wrap > section.content.news > article.board_eventlist > ul > li > img"
# 이벤트 b 셀렉터
selector_text = "#wrap > section.content.news > article.board_eventlist > ul > li > b"
# 이벤트 날짜 span 셀렉터
selector_date = "#wrap > section.content.news > article.board_eventlist > ul > li > span"
# 이벤트 링크가 포함된 li 태그들 선택
selector_href = "#wrap > section.content.news > article.board_eventlist > ul > li"
# 선택자에 해당하는 요소들을 모두 찾음
event_img = soup.select(selector_img)
# URL에 프로토콜을 추가하여 출력
for img in event_img:
src = img.get('src')
if src.startswith('//'):
src = 'https:' + src
eve_img.append(src)
# 선택자에 해당하는 요소들을 모두 찾음
event_text = soup.select(selector_text)
# 각 링크의 텍스트만 추출하여 리스트에 저장
event_text = [link.get_text(strip=True) for link in event_text]
# 결과 출력
for text in event_text:
eve_text.append(text)
# 선택자에 해당하는 요소들을 모두 찾음
event_dates = soup.select(selector_date)
# 결과 출력
for span in event_dates:
date_text = span.text.strip().replace('\n', '').strip().replace(' ','') # span 태그 안의 텍스트에서 공백 및 줄바꿈 제거
eve_date.append(date_text)
event_href = soup.select(selector_href)
# 결과 출력
for li in event_href:
if li.get("data-no"):
event_url = f"http://df.nexon.com/community/news/event/{li.get('data-no')}?categoryType=0"
eve_herf.append(event_url)
else:
li = li.get("onclick")
if 'window.location.href' in li:
# 정규 표현식을 사용하여 값을 추출합니다.
li = re.findall(r"'(.*?)';", li)
eve_herf.append("https://df.nexon.com"+''.join(li))
elif 'neople.openCouponPop()' in li:
li = "https://df.nexon.com/community/news/event/list"
eve_herf.append(li)
elif 'window.open' in li:
# 정규 표현식을 사용하여 URL 추출
li = re.search(r"https://[a-zA-Z0-9./-]+", li).group()
eve_herf.append(li)
# 테이블 초기화 (기존 데이터 삭제)
truncate_sql = "TRUNCATE TABLE donpa_event"
cursor.execute(truncate_sql)
# 데이터베이스에 데이터 삽입
for i in range(len(eve_img)):
img = eve_img[i]
text = eve_text[i]
date = eve_date[i]
herf = eve_herf[i]
sql = "INSERT INTO donpa_event (img, text, date, herf) VALUES (%s, %s, %s, %s)"
cursor.execute(sql, (img, text, date, herf))
# 변경사항 커밋
conn.commit()
# 연결 종료
conn.close()
이제 장고에서 데이터를 띄워보자!!!
event.html
<!DOCTYPE html>
<html>
<head>
<title>던전앤파이터 이벤트</title>
<style>
/* 제목 */
h1 {
font-size: 46px; /* 큰 제목 크기로 변경 */
color: #f7e706; /* 게임 색상으로 변경 */
text-align: center;/* 제목 가운데 정렬*/
}
/* 메뉴 스타일링 */
ul.menu {
list-style-type: none;
margin: 0;
padding: 0;
text-align: center;
padding: 10px 0; /* 메뉴 항목 위아래로 간격 추가 */
}
ul.menu li {
display: inline;
margin-right: 20px;
font-size: 40px;
}
ul.menu li a {
color: rgb(255, 255, 255);
text-decoration: none;
padding: 10px 20px; /* 각 메뉴 항목의 내부 여백 추가 */
border-radius: 5px; /* 각 메뉴 항목을 둥글게 꾸미기 */
/* background-color: #534747; /* 배경색 추가 */
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); /* 그림자 효과 추가 */
transition: background-color 0.3s, transform 0.2s; /* 호버 효과를 위한 트랜지션 설정 */
}
ul.menu li a:hover {
background-color: #4e2626; /* 호버 시 배경색 변경 */
transform: translateY(-2px); /* 호버 시 약간 위로 이동 효과 */
}
/* 배경 이미지 추가 */
body {
background-image: url('https://bbscdn.df.nexon.com/data7/commu/201712/205032_5a44da887e6a8.jpg');
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
position: relative;
z-index: 0;
}
/* 아이템 스타일링 */
.item {
background-color: #fff;
padding: 20px;
margin: 10px;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
width: calc(50% - 20px); /* 컨테이너의 절반 너비로 설정하고 간격을 추가합니다 */
display: inline-block;
vertical-align: top;
box-sizing: border-box;
float: left;
}
/* 컨테이너 스타일링 */
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
text-align: center; /* 가운데 정렬 */
overflow: hidden; /* float 된 아이템을 감싸기 위해 추가 */
}
.item img {
max-width: 100%;
height: auto;
margin-bottom: 10px;
transition: transform 0.2s; /* 호버 효과를 위한 트랜지션 설정 */
}
.item:hover img {
transform: scale(1.1); /* 호버 시 이미지 확대 효과 */
}
.item-title {
font-weight: bold;
font-size: 20px;
text-decoration: none;
color: #333;
transition: color 0.3s; /* 호버 효과를 위한 트랜지션 설정 */
}
.item-title:hover {
color: #f7e706; /* 호버 시 제목 색상 변경 */
}
.date {
color: #777;
}
</style>
</head>
<body>
<ul class="menu">
<li><a href="/">아이템 시세</a></li>
<li><a href="/aabata/">아바타 시세</a></li>
<li><a href="/event/">진행 중 이벤트</a></li>
<li><a href="/news/">던파 소식</a></li>
</ul>
<h1>던전앤파이터 이벤트</h1>
<div class="container">
{% for item in items %}
<div class="item">
<a href="{{ item.herf }}" target="_blank">
<img src="{{ item.img }}" alt="Item Image">
<a href="{{ item.herf }}" target="_blank" class="item-title">{{ item.text }}</a>
<p class="date">{{ item.date }}</p>
</a>
</div>
{% endfor %}
</div>
</body>
</html>
던파 이벤트와, 던파 뉴스 데이터를 수집해 테이블에 저장하는 코드를 도커 이미지로 만들어 놓자
1. 던파 뉴스 도커 파일
dockerfile
# 베이스 이미지 설정
FROM python:latest
# 작업 디렉토리 설정
WORKDIR /app
# main, requirements 두 파일 작업디렉토리로 복사
COPY main.py /app/main.py
COPY requirements.txt /app
# 필요한 종속성 설치
RUN pip install --no-cache-dir -r requirements.txt
CMD [ "python" , "main.py" ]
main.py
import requests
from bs4 import BeautifulSoup
import pymysql
# MySQL 연결 설정
conn = pymysql.connect(
host='10.109.90.46', # 호스트명
user='root', # 데이터베이스 사용자명
password='1234', # 데이터베이스 암호
db='donpa_item', # 데이터베이스 이름
port = 3306
)
# 커서 생성
cursor = conn.cursor()
# 크롤링 코드 작성
photo_list = []
title_list = []
link_list = []
# 검색 결과 페이지 URL
url = "https://search.naver.com/search.naver?where=news&query=%EB%8D%98%ED%8C%8C&sm=tab_opt&sort=1&photo=1&field=0&pd=0&ds=&de=&docid=&related=0&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so%3Add%2Cp%3Aall&is_sug_officeid=0&office_category=0&service_area=0"
# HTTP GET 요청
response = requests.get(url)
# 응답 데이터 파싱
soup = BeautifulSoup(response.text, "html.parser")
select_num = 1
while select_num<=10:
# 이미지 선택자
selector = f"#sp_nws{select_num} > div > a > img"
# 선택자에 해당하는 이미지 요소를 찾음
image = soup.select_one(selector)
# 각 링크의 href 속성값을 출력
photo = image.get("data-lazysrc")
photo_list.append(photo)
select_num+=1
# 뉴스 타이틀, 링크 선택자
selector = "#main_pack > section.sc_new.sp_nnews._prs_nws > div > div.group_news > ul > li> div > div > a"
# 선택자에 해당하는 요소들을 모두 찾음
title_link = soup.select(selector)
# 각 타이틀,링크 속성값을 출력
for link in title_link:
title = link.get("title")
href = link.get("href")
title_list.append(title)
link_list.append(href)
# 테이블 초기화 (기존 데이터 삭제)
truncate_sql = "TRUNCATE TABLE donpa_news"
cursor.execute(truncate_sql)
# 데이터베이스에 데이터 삽입
for i in range(len(photo_list)):
photo = photo_list[i]
title = title_list[i]
link = link_list[i]
sql = "INSERT INTO donpa_news (photo, title, link) VALUES (%s, %s, %s)"
cursor.execute(sql, (photo, title, link))
# 변경사항 커밋
conn.commit()
# 연결 종료
conn.close()
requirements.txt
requests
beautifulsoup4
pymysql
이미지 저장하는 명령어
docker build -t sy02229/donpa_news:latest .
이미지 푸쉬하는 명령어
docker push sy02229/donpa_news
2. 던파 이벤트 도커파일
dockerfile
FROM python:latest
# 작업 디렉토리 설정
WORKDIR /app
# main, requirements 두 파일 작업디렉토리로 복사
COPY main.py /app/main.py
COPY requirements.txt /app
# 필요한 종속성 설치
RUN pip install --no-cache-dir -r requirements.txt
CMD [ "python" , "main.py" ]
main.py
import requests
from bs4 import BeautifulSoup
import re
import pymysql
# MySQL 연결 설정
conn = pymysql.connect(
host='10.109.90.46', # 호스트명
user='root', # 데이터베이스 사용자명
password='1234', # 데이터베이스 암호
db='donpa_item', # 데이터베이스 이름
port = 3306
)
# 커서 생성
cursor = conn.cursor()
eve_img = []
eve_text = []
eve_date = []
eve_herf = []
# 검색 결과 페이지 URL
url = "https://df.nexon.com/community/news/event/list"
# HTTP GET 요청
response = requests.get(url)
# 응답 데이터 파싱
soup = BeautifulSoup(response.text, "html.parser")
# 이벤트 img 셀렉터
selector_img = "#wrap > section.content.news > article.board_eventlist > ul > li > img"
# 이벤트 b 셀렉터
selector_text = "#wrap > section.content.news > article.board_eventlist > ul > li > b"
# 이벤트 날짜 span 셀렉터
selector_date = "#wrap > section.content.news > article.board_eventlist > ul > li > span"
# 이벤트 링크가 포함된 li 태그들 선택
selector_href = "#wrap > section.content.news > article.board_eventlist > ul > li"
# 선택자에 해당하는 요소들을 모두 찾음
event_img = soup.select(selector_img)
# URL에 프로토콜을 추가하여 출력
for img in event_img:
src = img.get('src')
if src.startswith('//'):
src = 'https:' + src
eve_img.append(src)
# 선택자에 해당하는 요소들을 모두 찾음
event_text = soup.select(selector_text)
# 각 링크의 텍스트만 추출하여 리스트에 저장
event_text = [link.get_text(strip=True) for link in event_text]
# 결과 출력
for text in event_text:
eve_text.append(text)
# 선택자에 해당하는 요소들을 모두 찾음
event_dates = soup.select(selector_date)
# 결과 출력
for span in event_dates:
date_text = span.text.strip().replace('\n', '').strip().replace(' ','') # span 태그 안의 텍스트>에서 공백 및 줄바꿈 제거
eve_date.append(date_text)
event_href = soup.select(selector_href)
# 결과 출력
for li in event_href:
if li.get("data-no"):
event_url = f"http://df.nexon.com/community/news/event/{li.get('data-no')}?categoryType=0"
eve_herf.append(event_url)
else:
li = li.get("onclick")
if 'window.location.href' in li:
# 정규 표현식을 사용하여 값을 추출합니다.
li = re.findall(r"'(.*?)';", li)
eve_herf.append("https://df.nexon.com"+''.join(li))
elif 'neople.openCouponPop()' in li:
li = "https://df.nexon.com/community/news/event/list"
eve_herf.append(li)
elif 'window.open' in li:
# 정규 표현식을 사용하여 URL 추출
li = re.search(r"https://[a-zA-Z0-9./-]+", li).group()
eve_herf.append(li)
# 테이블 초기화 (기존 데이터 삭제)
truncate_sql = "TRUNCATE TABLE donpa_event"
cursor.execute(truncate_sql)
# 데이터베이스에 데이터 삽입
for i in range(len(eve_img)):
img = eve_img[i]
text = eve_text[i]
date = eve_date[i]
herf = eve_herf[i]
sql = "INSERT INTO donpa_event (img, text, date, herf) VALUES (%s, %s, %s, %s)"
cursor.execute(sql, (img, text, date, herf))
# 변경사항 커밋
conn.commit()
# 연결 종료
conn.close()
req.txt
requests
beautifulsoup4
pymysql
이미지 저장하는 명령어
docker build -t sy02229/donpa_event:latest .
이미지 푸쉬하는 명령어
docker push sy02229/donpa_event