이전에 메인 페이지 html/css 작업까지 완료하였다. 이번에는 스크래핑한 데이터를 csv로 저장하는 작업과 임시로 표시해 뒀던 부분에 실제 공모전의 제목과 날짜가 표시되도록 할 것이다.
스크래핑 데이터를 csv로 저장
이전에 작성했던 스크래핑 저장 코드는 직접적으로 데이터베이스에 저장하는 방식으로 작성되었다. 그런데 외부 데이터베이스가 아닌 내부 데이터베이스를 쓰기 때문에 만약 다른 사용자가 사용할 때, 무조건 스크래핑 작업을 거쳐야 한다는 단점이 있다. 이러한 시간을 줄이기 위해 미리 csv로 저장해 두고, 해당 csv 파일을 바로 데이터베이스에 적용할 수 있도록 할 것이다. (나중에 시간이 된다면 스크래핑을 다시 했을 때, csv에 존재하지 않는 것만 가져올 수 있도록 코드를 수정할 것이다.)
스크래핑 중 에러
스크래핑 데이터를 수집하고 저장하는 과정을 save.py에서 수행하려고 하니 에러가 발생하였다. 이유는 순환 import를 사용해서 그렇다고 한다. 이전에 스크래핑 코드에서 __main__을 활용하여 데이터 수집 및 데이터베이스에 저장하는 과정을 수행했기 때문이다. 그래서 스크래핑 코드들에서 save 파일을 import 하지 않고, save에서 세 개의 스크래핑 코드를 import 하여 저장 과정은 save에서 수행하도록 수정하였다.
링커리어
- '24.04.25 ~ 채용 시 마감'과 같이 시작 날짜는 있지만 마감 날짜가 존재하지 않는 경우 => 날짜 형식 에러
- 스크래핑 코드는 그대로 두되, save.py에서 올바른 날짜 형식이 아니면 '-'로 저장되도록 수정
- 해당 페이지의 공모전 url만 탐색해야 하지만, 다시 처음부터 반복문을 수행 => 데이터 길이 불일치
- scraping_linkcarrer.py에 매 반복마다 초기화되는 tmp_urls로 날짜를 추출
씽굿
- 제목이 맨 처음 페이지에 존재하는 5개만 추출됨 => 랜더링 에러
- 페이지를 넘기고 공모전 내용이 뜨기 전에 스크래핑을 진행해서 생긴 오류
- time.sleep을 통해 페이지를 넘긴 후 기다리는 작업 수행
위비티
- 해당 페이지의 공모전 url만 탐색해야 하지만, 다시 처음부터 반복문을 수행 => 데이터 길이 불일치
- scraping_wevity.py에 매 반복마다 초기화되는 tmp_urls로 날짜를 추출
csv로 저장 - save.py
데이터베이스에 저장할 수 있는 함수를 만들었던 save 파일에 csv 파일로 저장하는 함수를 추가하였다.
import pandas as pd
import csv
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'moremore.settings')
django.setup()
from datetime import datetime
from mainpage.models import Competition
from scraping_linkcarrer import scraping_linkcarrer
from scraping_thinkgood import scraping_thinkgood
from scraping_wevity import scraping_wevity
def save_data_to_database(platform, title, url, application_start, application_end):
if platform == 'linkcarrer':
for t, u, start, end in zip(title, url, application_start, application_end):
Competition.objects.create(
platform=platform,
title=t,
url=u,
application_start=datetime.strptime(start, "%y.%m.%d").strftime("%Y-%m-%d") if start.replace('.', '').isdigit() else '-',
application_end=datetime.strptime(end,"%y.%m.%d").strftime("%Y-%m-%d") if end.replace('.', '').isdigit() else '-'
)
elif platform in ['wevity', 'thinkgood']:
for t, u, start, end in zip(title, url, application_start, application_end):
Competition.objects.create(
platform=platform,
title=t,
url=u,
application_start=datetime.strptime(start,'%Y-%m-%d').strftime("%Y-%m-%d") if start.replace('.', '').isdigit() else '-',
application_end=datetime.strptime(end,'%Y-%m-%d').strftime("%Y-%m-%d") if end.replace('.', '').isdigit() else '-'
)
def save_data_to_dataframe(platform, title, url, application_start, application_end):
if platform == 'linkcarrer':
data = {
'platform': platform,
'title': title,
'url': url,
'application_start': [datetime.strptime(start, "%y.%m.%d").strftime("%Y-%m-%d") if start.replace('.', '').isdigit() else '-' for start in application_start],
'application_end': [datetime.strptime(end, "%y.%m.%d").strftime("%Y-%m-%d") if end.replace('.', '').isdigit() else '-' for end in application_end]
}
elif platform in ['wevity', 'thinkgood']:
data = {
'platform': platform,
'title': title,
'url': url,
'application_start': [datetime.strptime(start, "%Y-%m-%d") if start.replace('-', '').isdigit() else '-' for start in application_start],
'application_end': [datetime.strptime(end, "%Y-%m-%d") if end.replace('-', '').isdigit() else '-' for end in application_end]
}
df = pd.DataFrame(data)
df.to_csv(f"{platform}.csv", index=False)
def save_csv_to_database(csv_file):
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader) # 첫 번째 행은 헤더이므로 건너뜁니다.
for row in reader:
platform = row[0]
title = row[1]
url = row[2]
application_start = datetime.strptime(row[3], "%Y-%m-%d")
application_end = datetime.strptime(row[4], "%Y-%m-%d")
Competition.objects.create(platform=platform, title=title, url=url, application_start=application_start, application_end=application_end)
if __name__ == "__main__":
title, url, application_start, application_end = scraping_linkcarrer()
save_data_to_dataframe('linkcarrer', title, url, application_start, application_end)
save_csv_to_database("linkcarrer.csv")
title, url, application_start, application_end = scraping_wevity()
save_data_to_dataframe('wevity', title, url, application_start, application_end)
save_csv_to_database("wevity.csv")
title, url, application_start, application_end = scraping_thinkgood()
save_data_to_dataframe('thinkgood', title, url, application_start, application_end)
save_csv_to_database("thinkgood.csv")
메인 페이지에 공모전 표시
예시로 'competition title'과 '0000-00-00'을 표시해뒀던 공모전 정보 목록을 실제 데이터를 적용하여 볼 수 있도록 할 것이다. 그러기 위해 scraping 파일을 일부 페이지만 추출할 수 있도록 break 구문을 작성하고, save.py를 실행하여 상위 일부 데이터만 추출하였다.
views.py
저장한 데이터 중 플랫폼 별로 상위 10개의 데이터를 필터링하여 context로 담아 랜더링 한다.
from django.shortcuts import render
from .models import Competition
# Create your views here.
def index(request):
competition_linkcarrer = Competition.objects.filter(platform='linkcarrer').order_by('-id')[:10]
competition_wevity = Competition.objects.filter(platform='wevity').order_by('-id')[:10]
competition_thinkgood = Competition.objects.filter(platform='thinkgood').order_by('-id')[:10]
context = {
'competition_linkcarrer': competition_linkcarrer,
'competition_wevity': competition_wevity,
'competition_thinkgood': competition_thinkgood
}
return render(request, 'mainpage/index.html', context)
index.html
예시로 작성했던 부분(li - /li)을 제거하고, for문과 views를 통해 전달받은 context를 사용하여 데이터를 제공하도록 한다. 또한 <a> 태그의 href도 수정하여 클릭하면 해당 페이지로 이동할 수 있도록 하였다.
{% for competition in competition_thinkgood %}
<li>
<a href="{{ competition.url }}">
<h5 class='title'>{{ competition.title }}</h5>
<span class='application-start'>{{ competition.application_start|date:"Y-m-d" }}</span>
<span> ~ </span>
<span class='application-end'>{{ competition.application_end|date:"Y-m-d" }}</span>
</a>
</li>
{% endfor %}
style.css
title에 css를 적용하여 만약 width가 280px보다 길다면 '...'으로 생략되어 보여주도록 설정하였다.
.title {
display: block;
width: 280px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
결과
공모전의 링크만 수정하였고, 더보기나 플랫폼 제목의 링크는 아직 '/main'으로 수정하지 않았다. 이후 세부 페이지를 구성하면서 링크를 수정할 예정이다.
git push
테스트용으로 생성한 csv파일이 같이 push 되지 않도록 .gitignore에 '*.csv'를 추가해 주었다.
git add .
git commit -m "feat, fix: add data to dataframe and dataframe to database function, scraping data on web, and fix scraping error"
git push origin main
다음에는 세부 페이지 html 파일을 작성하고, 메인 페이지에서 검색하면 해당 데이터를 받을 수 있도록 할 것이다.
'프로젝트 단위 공부 > [개인 프로젝트] 공모전 크롤링' 카테고리의 다른 글
[개인 프로젝트] 공모전 크롤링 - 중간점검 (0) | 2024.05.08 |
---|---|
[개인 프로젝트] 공모전 크롤링 (9) - 세부 페이지(검색, 더보기) (0) | 2024.05.06 |
[개인 프로젝트] 공모전 크롤링 (7) - 메인 페이지 (프론트) (2) | 2024.05.02 |
[개인 프로젝트] 공모전 크롤링 (6) - 데이터 수집 (스크래핑) - 씽굿 (2) | 2024.05.01 |
[개인 프로젝트] 공모전 크롤링 (5) - 데이터 수집 (스크래핑) - 위비티 (2) | 2024.05.01 |