클리앙 모두의공원 게시글 분석기(세번째)
Updated:
이글은 클리앙 모두의공원 게시글 분석기에 이은 세번째 분석기이다. 이번 글에서는 클리앙 모두의공원 게시글의 일 별 조회수/댓글수/공감수 통계를 구해보고자 한다. 조회수/댓글수/공감수를 기반으로 하루동안 이슈를 끌었던 게시물 TOP100 리스트를 만들어 볼 것이다.
1. 도입 - 다시 데이터를 수집하자
첫번째 분석기에서 파이썬 웹 크롤러를 통해서 데이터를 수집했었다. 이 때는 새 글을 등록되면, 랜덤으로 글을 선택해서 1시간 마다 해당 웹페이지를 다시 읽어서 24시간 동안 조회수/댓글수/공감수를 저장하였다. 즉, 모두의 공원 게시물의 등록 후 24시간 동안의 조회수/댓글수/공감수의 추세를 분석하였다.
첫번째 분석기에서 수집한 파이썬 웹 크롤러의 데이터를 토대로 2가지 방향으로 분석을 진행하였고 추가 분석할 내용은 없어 보였다. 그래서 이번에는 데이터 수집부터 다시 시작하였다. 이번 아이디어는 모두의 공원 게시물의 일별 통계를 분석해보고 싶었다. 날짜가 변경되면 전날(어제)의 게시물 통계를 모두 모아서 어디 게시물이 모두의 공원 커뮤니티에서 가장 큰 이슈가 되었는지를 TOP100 리스트를 생성해보고자 한다.
이전에 일별 추천 게시물이나 베스트 게시물 등의 형태로 커뮤니티 글 중에 추천 게시물만 보여주는 웹사이트를 방문해본 적이 있다. 이런 종류의 분석을 목표로 하였다.
이전에 만들었던 파이썬 웹 크롤러를 다시 꺼내왔다. 한번 코드를 작성해두었더니 여러모로 요긴하게 사용하고 있다. 웹 크롤러 동작은 변경할 것이 없으니 데이터 수집 시점과 결과 취합 부분만 변경하면 된다.
GitHub repo에 11_top100_project 폴더를 추가하여 세번째 분석에 사용한 스크립트와 결과를 업로드 하였다. 관심이 있다면 코드를 같이 확인해보자.
데이터 수집은 01_happen_yesterday.py 스크립트 파일에서 수행하였다. 이번 데이터 수집의 핵심 사항은 모공에 등록되는 모든 게시글 정보를 수집해야 하는데 언제 정보를 수집할 것인지가 되겠다. 게시물이 등록되고 어느 정도 시간이 지나야만 조회수/댓글수/공감수를 저장할 수 있는데 이 시간을 얼마로 정하는지에 따라서 취합 데이터가 달라질 수 도 있기 때문이다. 일단 지난 분석기에서 취합했던 데이터를 토대로 너무 짧지도 않고 너무 길지도 않은 6시간으로 선택했다. 게시물 등록 후 6시간이 지나면 유저들의 판단을 받았다고 생각한 것이다.
while keepGoing:
# Step 1. 게시물 ID 확인
# a. 날짜로csv 파일명을 확인해서 파일명 존재시 마지막 row의ID 확인
# b. 파일명이 없을 경우, 현재 게시물의 첫글로 초기화(이제부터 시작)
thisId = lastId + 1
print("\nThis id : %d - [%s]" % (thisId, getNowTime()))
scraper.boardId = thisId
# Step 2. 확인한 게시물 ID의 +1 게시글을 읽어서 확인
# a. 정해진 시간(ex. 6hour) 보다 오래되었으면 정보를 csv에 저장
# b. 정해진 시간을 안넘겼으면 그대로 out 종료
scraper.scraping()
ret = scraper.checkLongerThan()
if ret is None:
print("Id : %d is HTTPError 404 or was deleted by the web manager.." % thisId)
httpError = httpError + 1
if httpError > 30:
print("httpError count is %d. We're going out." % httpError)
keepGoing = False
elif ret:
print("Id : %d is longer than buzzCheckDuration." % thisId)
scraper.concatPd()
httpError = 0
else:
print("Id : %d is short than buzzCheckDuration." % thisId)
keepGoing = False
lastId = thisId
스크립트의 메인 로직 부분이다. 모공의 게시물 id가 신규 등록글에는 +1이 되어서 할당됨을 이용했다. 게시물 id를 기반으로 웹 크롤링을 수행하고 해당 페이지가 존재하지 않으면 스킵, 기준 시간인 6시간이 넘었으면 데이터 저장 후 다음 게시물을 웹 크롤링 수행, 기준 시간인 6시간이 안되었으면 스크립트 종료를 수행한다.
이 스크립트를 1분 단위로 계속 실행해주면 게시물 등록 시간을 기준으로 6시간이 넘으면 바로바로 정보 수집을 해서 default.csv 파일에 계속 저장하게 된다.
2. 수집 데이터 가공 & 수치화
데이터 수집은 default.csv 파일에 계속 추가된다. 날짜가 변경되고 6시간이 지나면(매일 6AM) 전날의 데이터 수집이 완료되므로 데이터 가공 및 수치화를 할 수 있다.
데이터 가공은 02_build_data.py 스크립트에서 수행한다.
날짜가 변경되고 위와같이 csv 파일을 인자로 넣어서 실행하면 csv 파일 데이터 중에 전날 날짜에 해당하는 데이터만 추출하여 results 폴더로 이동시킨다.
이제 가공을 해야하는 데이터가 모두 확정된 상태가 된 것이다. 이제 데이터 별로 순위를 매겨서 TOP100 리스트만 추출하면 된다. 처음에는 조회수/댓글수/공감수 별로 TOP100 리스트를 생성하려고 했다. 하지만 이 방법에는 보여줘야할 리스트가 3가지 종류로 너무 많아지고 각 항목별 TOP100 리스트에는 서로 중복되는 게시물이 너무 많았다. 그래서 조회수/댓글수/공감수를 합쳐서 수치화하고 이를 Buzz라고 이름을 붙였다. 아래는 스크립트에서 Buzz를 계산하는 부분이다.
sum_view = (int)(sum[ ['view'] ].iloc[0].values)
pd_sum_pct= pd.DataFrame(ystDf['view'].apply(lambda x: x/sum_view))
pd_sum_pct.columns = ['view_pct']
sum_reply = (int)(sum[ ['reply'] ].iloc[0].values)
pd_sum_reply = pd.DataFrame(ystDf['reply'].apply(lambda x: x/sum_reply))
pd_sum_reply.columns = ['reply_pct']
pd_sum_pct = pd.concat([pd_sum_pct, pd_sum_reply], axis=1)
sum_symph = (int)(sum[ ['symph'] ].iloc[0].values)
pd_sum_symph = pd.DataFrame(ystDf['symph'].apply(lambda x: x/sum_symph))
pd_sum_symph.columns = ['symph_pct']
pd_sum_pct = pd.concat([pd_sum_pct, pd_sum_symph], axis=1)
pd_sum_pct = (pd.DataFrame(pd_sum_pct.sum(axis=1)))
pd_sum_pct = pd_sum_pct.apply(lambda x: (x/3*100))
pd_sum_pct.columns = ['buzz_pct']
ystDf = pd.concat([ystDf, pd_sum_pct], axis=1)
largest = ystDf.nlargest(100, 'buzz_pct')[ printLists ]
Buzz는 게시물의 조회수/댓글수/공감수를 각 항목의 총합으로 나눠서 각 게시물의 항목이 가진 수가 그 항목의 총합에서 차지하는 비율을 계산했다. 그리고 3개 항목으로 이뤄졌기 때문에 각 비율을 3으로 나눠서 그 총합이 100%가 되도록 하였다.
ID | 조회수 | 댓글수 | 공감수 | Buzz |
---|---|---|---|---|
1 | 100 | 0 | 10 | 40.00% |
2 | 100 | 50 | 0 | 23.33% |
3 | 100 | 50 | 0 | 23.33% |
4 | 100 | 0 | 0 | 6.67% |
5 | 100 | 0 | 0 | 6.67% |
TOTAL | 500 | 100 | 10 | 100.00% |
위는 설명을 위한 간단한 예시이다. ID 5를 보면 조회수가 100으로 조회후 총합인 500으로 나누면 20%가 된다. 댓글수와 공감수는 0이기 때문에 0%가 된다. 이 결과의 총합인 20%를 3으로 나누면 6.67%가 된다.
이 Buzz가 의미하는 바는 조회수/댓글수/공감수를 기반으로 전날에 등록된 모든 게시물 중에 이 게시물이 얼마나 화제가 되었는지(=이목을 끌었는지)를 보여주는 것이다. 계산된 Buzz 수치를 가지고 상위 100개를 데이터를 뽑으면 완료가 된다.
3. 결과 - 2019월 05월 01일 TOP100
TOP100 리스트가 완성되었다. 데이터를 수집하고 Buzz 수치를 기반으로 TOP100을 추출하면서 다른 사이트에서 보여주는 추천글 내지는 베스트글들이 어떻게 만들어질지 대략 상상할 수 있는 경험이었다.
여기서는 게시물의 조회수/댓글수/공감수를 각 1/3의 동일 비중으로 취급하였지만 어떤 항목값을 얼만큼의 비중을 부여할지는 전적으로 운영자(=코드 작성자) 마음이다. 운영자가 정의한 기준이 제 각기이므로 선정된 베스트글 목록이나 순위가 사이트 별로 다를 것이다.
마지막으로 모두의 공원 게시글의 2019월 05월 01일 TOP100 리스트를 아래에 추가하였다. TOP100 리스트에는 어떤 글들이 있는지 구경해보자.
Leave a comment