프로그래밍/이것저것_개발일지
성대 학생회 공약 모아보기 사이트 - 멋쟁이사자처럼 프로젝트 (1)
inspirit941
2018. 1. 20. 16:28
171122
(1) Python 웹 크롤링으로 정보 수집하기
성균관대학교 멋쟁이사자처럼 5기 - 2학기 프로젝트
학교를 몇 년 다니고 있지만,
딱히 관심을 갖고 보지 않으면
대학교 학생회가 어떤 공약을 제시했고, 얼마나 이행했는지 알기가 쉽지 않다.
프로젝트 주제 선정 과정에서 이 문제를 해결해보면 좋겠다는 이야기가 나왔고,
2014년부터 2017년까지, 4년간 총학생회와 단과대 학생회의 공약 정보를 조사하기로 했다.
이 문제를 해결하려면 어떤 과정이 필요할지 대강 그려봤다.
1. 매년 총학생회와 단과대 공약 데이터를 저장해 두는 무언가를 찾는다.
2. 조사한 데이터를 웹페이지에 활용할 수 있는 데이터베이스 형태로 만든다.
3. 데이터베이스를 활용한 웹페이지를 만든다.
이 웹페이지가 만들어지기 위해 가장 중요한 것이 바로 공약 데이터다. 그렇다면 성균관대학교에서 매년 총학생회와 단과대 학생회의 공약을 저장하는 곳을 찾아봐야 했다.
성균관대 선거관리위원회나 학교 내 학생지원팀에게 연락해보려 했으나, 이 프로젝트를 시작한 시기인 11월은 총학생회 선거가 있는 달이었다. 게다가 한창 일을 시작해야 할 프로젝트 초기가 11월 하순으로, 정말 선거가 며칠 앞으로 다가온 시기였다. 선거관리위원회는 이미 일하느라 정신없을 것 같고, 학생지원팀 입장에서도 선거가 코앞이다 보니 도움을 기대하기 어려울 것 같았다.
지인들에게 수소문한 결과 성대신문에서 매년 총학생회의 공약 이행여부를 평가하고 있다는 사실을 알게 됐다. 그렇다면 성대신문 웹페이지 크롤링 후 스크래핑하면 정보를 얻을 수 있을 것이다.
성대신문 웹페이지를 들어가서 확인해봤다.
http://www.skkuw.com/news/articleList.html
기사 중에서도 보통 ‘기획보도’에 학생회 관련 기사가 많으니, 기획보도를 중점적으로 확인해보기로 했다.
크롬 개발자도구로 확인해본 결과, 다행스럽게도 성대신문 웹페이지는 자바스크립트 기반 동작이 아니라 html과 css로 이루어져 있었다. 이 정도면 크롤링에 큰 어려움은 없다.
먼저, 필요한 라이브러리를 가져온다.
jupyter notebook을 활용했다.
import requests
from bs4 import BeautifulSoup4
import chardet
import datetime
import pandas as pd
import numpy as np
#그리고 DataFrame으로 만들기 위한 array를 몇 개 정의한다.
datearray=[]
title=[]
author=[] href=[]
url = "http://www.skkuw.com/news/articleList.html"
for i in range(1,55):
querystring = {"page":i,
#url 뒤에 있는 parameter에서 변형하면 되는 건 page 변수 하나뿐이다.
"total":"1093",
"sc_section_code":"S1N2",
"sc_sub_section_code":"",
"sc_serial_code":"",
"sc_area":"",
"sc_level":"",
"sc_article_type":"",
"sc_view_level":"",
"sc_sdate":"",
"sc_edate":"",
"sc_serial_number":"",
"sc_word":"",
"sc_word2":"",
"sc_andor":"",
"sc_order_by":"I",
"view_type":""
}
headers = {
'accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
'accept-encoding': "gzip, deflate",
'accept-language': "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
'cache-control': "no-cache",
'connection': "keep-alive",
'cookie': "PHPSESSID=881f1642a92a997af2c6a5bf978e976d",
'host': "www.skkuw.com",
'referer': "http://www.skkuw.com/news/articleList.html?page=2&total=1093&sc_section_code=S1N2&sc_sub_section_code=&sc_serial_code=&sc_area=&sc_level=&sc_article_type=&sc_view_level=&sc_sdate=&sc_edate=&sc_serial_number=&sc_word=&sc_word2=&sc_andor=&sc_order_by=I&view_type=",
'upgrade-insecure-requests': "1",
'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
'page': "1",
'total': "1093",
'sc_section_code': "S1N2",
'sc_order_by': "I",
'postman-token': "04862f8b-61e1-e890-785d-cd4d8d74b1c7"
}
response = requests.request("GET", url, headers=headers, params=querystring)
response.raise_for_status()
response.encoding='euc-kr'
html=response.text
#request 라이브러리로 성대신문 페이지를 1 ~ 55페이지까지 각각 가져온다.
#17년 11월 22일은 55페이지가 마지막이었지만, 포스팅하는 지금은 아마 더 많을 것이다.
for word in bs.select ('td.View_SmFont.FontEng'):
array=word.string
date=datetime.datetime.strptime(array,"%Y-%m-%d").date()
datearray.append(date)
#게시글의 시간을 스크래핑해서 datetime으로 정의한 다음, date array에 넣음
for text in bs.select('td.ArtList_Title > a'):
titleword=text.string
title.append(titleword)
#html a tag의 string을 추출해 title이라는 array에 append했다.
link='http://www.skkuw.com/news/'+text['href']
href.append(link)
#게시글 상세 url 주소 a tag에서 수집해, href array에 append했다.
raw_data={'title':title,
'date':datearray,
'link':href
}
#title, date, link 세 개의 array를 하나의 dictionary로 만들고,
data=pd.DataFrame(raw_data)
#해당 dictionary를 DataFrame으로 변환하면 Table 형태 데이터가 완성된다. data
위 코드를 실행하면 11월 22일 기준, 다음과 같은 결과를 얻을 수 있다.
이 중에서는 총학생회 공약과 관계없는 신문기사도 많다. 총학과 관련 있을 법한 기사들만 따로 추려냈다.
공약=data.loc[data.title.str.contains('공약|총학생회|총학|평가|학생자치')==True,:].reset_index(drop=True)
#데이터 중 'title'안에 공약, 총학생회, 총학, 평가, 학생자치라는 단어가 하나라도 들어가 있는 데이터만 빼내서 정렬했다.
공약.to_excel('공약데이터.xlsx') #엑셀 파일로 저장
위 코드를 통해 엑셀 파일로 데이터를 추출할 수 있다.
데이터 양이 많은 편이 아니어서, 굳이 2014년부터 2017년까지의 데이터만 코드로 따로 빼내는 작업은 하지 않았다.
이제, 이 url 중에서 총학생회와 학생자치기구의 공약을 평가한 게시글을 찾아서 정리하면
기본 데이터는 완성된다. 그 다음, c9 프로젝트에 데이터베이스로 옮기는 작업을 해야 한다.