작년에 게임과 관련된 한국어 감성분석 사전을 만들어볼까 하는 생각에 Steam에 등록된 한국어 게임평들을 모두 긁어온 적이 있었는데요, 결론부터 밝히자면 그 수가 적어서 유의미한 분석을 할 수는 없었습니다.
그래서 당분간 묵혀두었는데, 기껏 짜놓은 코드 하드 속에서 용량만 차지하게 냅두느니, 먼지 털고 올려두면 누군가에게 도움이 될 수 있지 않을까 하는 생각에 공유하기로 마음 먹었습니다.
Python3 기반의 코드이고, 간단하므로 크게 설명할 건덕지는 없을듯합니다. BeautifulSoup 라이브러리가 필요합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import urllib import urllib.request import urllib.parse import bs4 import re import os from concurrent.futures import ThreadPoolExecutor def deleteTag(x): return re.sub( "<[^>]*>" , "", x) def getComments(appid, lang = 'all' ): def makeArgs(appid, lang, page): params = { 'userreviewsoffset' : 10 * (page - 1 ), 'p' : page, 'workshopitemspage' : page, 'readytouseitemspage' : page, 'mtxitemspage' : page, 'itemspage' : page, 'screenshotspage' : page, 'videospage' : page, 'artpage' : page, 'allguidepage' : page, 'webguidepage' : page, 'integratedguidepage' : page, 'discussionspage' : page, 'numperpage' : 10 , 'browsefilter' : 'toprated' , 'appid' : appid, 'appHubSubSection' : 10 , 'l' : 'english' , 'filterLanguage' : lang, 'searchText' : '', 'forceanon' : 1 } return urllib.parse.urlencode(params) def innerHTML(s, sl = 0 ): ret = '' for i in s.contents[sl:]: if i is str : ret + = i.strip() else : ret + = str (i) return ret def fText(s): if len (s): return innerHTML(s[ 0 ]).strip() return '' retList = [] colSet = set () print ( "Processing: %d" % appid) page = 1 while 1 : try : f = urllib.request.urlopen( data = f.read().decode( 'utf-8' ) except : break soup = bs4.BeautifulSoup(data, "html.parser" ) cs = soup.select( ".apphub_Card" ) if not len (cs): break for link in cs: url = link.get( 'data-modal-content-url' ) url = url[ 29 :].replace( 'recommended/' , '') if url in colSet: return retList colSet.add(url) helpful = fText(link.select( '.found_helpful' )) cat = fText(link.select( '.title' )) cont = innerHTML(link.select( '.apphub_CardTextContent' )[ 0 ], 2 ) cont = deleteTag(re.sub( "([\t\r\n ]|<br>|</br>)+" , ' ' , cont)).strip() ng = 0 nb = 0 nf = 0 nh = re.search( "^([0-9]+) of ([0-9]+)" , helpful) if nh: ng = int (nh.group( 1 )) nb = int (nh.group( 2 )) - ng nh = re.search( "([0-9]+) people found this review funny" , helpful) if nh: nf = int (nh.group( 1 )) retList.append((url, cat, cont, ng, nb, nf)) page + = 1 return retList def fetch(i): outname = 'comments/%d.txt' % (i * 10 ) try : if os.stat(outname).st_size > 0 : return except : None # english 대신에 korean을 넣으면 한국어를 긁어옵니다. rs = getComments(i * 10 , 'english' ) if not len (rs): return f = open (outname, 'w' , encoding = 'utf-8' ) for r in rs: f.write( '%d\t%s\t%s\t%s\t%d\t%d\t%d\n' % (i * 10 , r[ 0 ], r[ 1 ], r[ 2 ], r[ 3 ], r[ 4 ], r[ 5 ])) f.close() with ThreadPoolExecutor(max_workers = 5 ) as executor: #일단 게임ID가 어디서부터 어디까지인지 몰라 다음과 같이 지정했습니다. for i in range ( 1 , 100000 ): executor.submit(fetch, i) |
사실 크롤링이라는게 어려운 기법이 필요한것은 아니고 은근과 끈기를 얼마나 가지고 (서버의 감시를 피해서) 잘 긁어오느냐가 관건인건데, 스팀에서 전체 게임 목록을 따로 제공해주지 않길래 게임의 고유 ID를 1부터 십만까지 뒤지며 차례로 다 검사해봤습니다. 나중에 게임이 더 늘어나면 해당 조사 범위를 조절할 필요가 있겠죠?
[Python] TextRank 구현 코드 (55) | 2017.04.20 |
---|---|
[Python] 특정 분포가 멱법칙(Power-law Distribution)을 따르는지 확인하기 (0) | 2017.04.11 |
[Python] 네이버 영화 한줄평 크롤링 코드 (14) | 2017.03.17 |
[Python] 단어 간 상호정보량 계산 코드 (0) | 2017.02.14 |
CppCon 자료 링크 (0) | 2017.02.05 |
[C++] 한글 두벌식 자판에서의 편집거리 (2) | 2016.12.26 |
댓글 영역