Python/2.7 for fun.
pyqt를 이용한 나만의 웹툰 뷰어 만들기3 (개선,기능추가)
이전글 : http://qkqhxla1.tistory.com/347
개선점.
1. 웹툰이 길 경우 한번에 내려가는 스크롤바가 너무 적어서 손 아픈 문제 개선.
->실행시 마우스 휠 스크롤 사이즈를 10으로 늘리고, 웹툰뷰어를 종료하면 스크롤 사이즈가 원래 설정대로 돌아감.
2. 네이버의 이번달 신작 웹툰 랜덤하게 3개, 다음의 오늘차 새로운 웹툰목록 추가.
스크롤 사이즈 변경 방법론.
위의 개선점 1번에서 적어놨듯이 웹툰이 길 경우 한번에 내려가는 스크롤바가 너무 적어서 손이 아팠다. 이걸 개선하기 위한 방법론이다.
웹툰 뷰어를 시작할때 원래의 스크롤 사이즈를 저장해놓고, 10으로 변경. 웹툰 뷰어를 종료하면 스크롤 사이즈를 원래의 저장해놨던 값으로 재설정.
처음에 스크롤 사이즈 변경하는건 앞에서 프록시 값 변경하듯이 레지스트리값을 변경하면 될거라고 생각했다. 관련 레지스트리는 찾았지만 (HKEY_CURRENT_USER\Control Panel\Desktop의 WheelScrollLines값.) 이 레지스트리 값을 리부트 안하고 적용해야하는게 문제였다. 이거 하나가지고 씨름을 하다가 생코에서 어떤 고마운 분이 SPI_SETWHEELSCROLLLINES 를 찾아보라고 했고, 이걸 찾아서 삽질해본결과 성공!! win32gui.SystemParametersInfo(SPI_SETWHEELSCROLLLINES,10) 이런식으로 변경이 가능하다.
15.07.11 개선점.
1. 웹툰뷰어는 두곳에서 사용하는데, 각각의 메모장에서 리스트를 받아오다 보니 한곳의 메모장을 바꾸면 다른곳에 적용이 안됨. 그래서 그냥 내 티스토리에 적어놓고 거기서 받아와서 웹툰을 보게끔 변경.
http://qkqhxla1.tistory.com/381 요기 사용.
2. 네이버 웹툰에서의 무한로딩 버그 해결. 그런데 레진코믹스에서의 무한로딩버그는 해결못함.
15.07.13 개선점.
레진코믹스가 사이트 개편을 내부적으로 살짝 했는지...파싱이 제대로 안되서 오늘 개선했다.
레진코믹스 파싱 방법론.
레진코믹스 웹툰 회차 하나당 하나의 json형태가 존재함. 법칙과 순서의 세계에서 하나 예시를 가져옴.
{"name":"54","display":{"title":"54화 지배자의 방 편 10","type":"g","displayName":"54","artistComment":""},"properties":{"expired":false,"notForSale":false},"coin":2,"point":0,"badge":"f","updatedAt":1429660138577,"freedAt":1435762800000,"seq":155,"publishedAt":1429714800000,"id":5787913594339328}
우리가 가져올 부분은 name부분(현재 회차)과 "freedAt"이 있는지 확인여부, "badge"라는 요소가 있는지 확인을 해봐야 한다. 이유.
1. 현재는 잠겨있는데 언젠가 풀리는 회차, 현재 풀린 회차는 "freedAt" 이라는 요소가 있음.(돈내고 봐야 하는 회차는 이 요소가 없음.)
2. 현재 무료로 풀린 회차는 "badge"와 "updatedAt" 라는 요소가 있음.
이것을 이용함. 사이트 개편으로 현재 다른 방법 사용중.
case 1. 김철수씨 이야기처럼 아예 잠겨서 돈내고 봐야 하는 회차는 없는데, 조금있으면 열린 회차만 있는
웹툰들. http://www.lezhin.com/comic/ssdj2002
case 2. 법칙과 순서의 세계처럼 중간중간 아예 잠겨있는게 있고, 현재 회차의 위에는 조금 뒤면 열릴 웹툰이 있는 그런 웹툰. http://www.lezhin.com/comic/the_world
case 3. 레바툰처럼 그냥 다 열려있는 웹툰.(가장 편함.) http://www.lezhin.com/comic/revatoon
위의 사실들을 이용한다.
15.08.14
하.. 레진코믹스가 다시 사이트 개편을 했는지 일부 알고리즘이 바뀌어서 제대로 작동을 안함. 수정.
레진코믹스가 또 사이트 개편을 했는지 바로 위에서 설명했던 badge요소가 사라졌다.(이런 샹.) 그래서 최신화를 가져오는 알고리즘을 이번엔 이렇게 바꾸었다. 차라리 진작 이렇게바꿀껄 이게 더 짜기 편했다. 레진코믹스의 한화마다 json이 있는데, 위의 예시를 보면 알겠지만"freedAt":1435762800000,이라는 요소가 있다. 분석결과 이것은 무료로 풀리는 시간을 밀리세컨드로 표시해놓은것으로 보인다. 파이썬의 time.time()*1000을 해보면 저 값과 비슷해짐을 알 수 있다. 그렇다면.. 오늘 시간 - 해당 freedAt뒤의 초 한 값중에서 해당 결과값이 양수이면서, '가장 작은값'을 가져오게 되면 가장 최근에 열린 화의 위치를 가져올수 있다. (이런 방법을 생각할때, 가장 최근에 열린거일수록 가장 최근화라는 가정을 하고 만들었다.) 그리고 테스트를 해본결과 일단 내가 현재 보는 웹툰들은 다 잘 작동함을 확인할수 있었다.
15.10.20
웹툰 뷰어좀 사용해보려고 하니까 다음에서 사이트 개편해서 로직이 바뀌었다. 네이버 웹툰처럼 소스코드 보기하면 그냥 소스가 뜨는게 아니라서 개선하려면 코드 전체를 갈아엎어야 한다. 일단 보류...
캐나다와서 알게된점. 캐나다는 한국보다 거의 하루가 느리다.(17시간 이전.) 웹툰을 보려고 네이버,다음,레진을 들어가면서 알게됬는데. 네이버와 레진은 서버 시간으로 시간을 측정하는것 같은데, 다음은 내 컴퓨터의 시간으로 현재 시간을 측정한다. 그래서 네이버와 레진은 자동으로 한국 시간의 웹툰이 보이는데, 다음웹툰은 하루 전의 웹툰(캐나다 시간의)이 보인다. 나중에 수정할때 참고하자.
exe파일.
웹툰 뷰어.vol1.egg웹툰 뷰어.vol2.egg추가 개선할 점.
1. 레진코믹스의 특별한 웹툰 실행시 무한로딩되는 버그 개선.(이것만 고치면 더 개선 안한다...)
다 잘 나오는데 일부 레진코믹스 웹툰의 무한로딩되는 버그를 못고치겠다.
# -*- encoding: cp949 -*- from PyQt4 import QtGui from PyQt4 import QtCore from PyQt4.QtWebKit import* from PyQt4.QtNetwork import QNetworkAccessManager import sys import urllib2 import re import time import operator import win32gui from _winreg import * webtoon_list_page = urllib2.urlopen('http://qkqhxla1.tistory.com/381').read().decode('utf-8').split('\'sun\']</p>')[1].split('</p><div class=')[0] webtoon_list_page = re.sub('\<span id=.*?\</span\>|<p>|<br />','',webtoon_list_page) my_webtoon_naver_daum = map(lambda x:x.replace('\n',''), webtoon_list_page.split('lezin')[0].split(',')) my_webtoon_lezin = map(lambda x:x.replace('\n','').split(', '), webtoon_list_page.split('lezin')[1].split('</p>')[1:]) my_webtoon_lezin = map(lambda x:(x[0],x[1],x[2]),my_webtoon_lezin) n_today_webtoon = {} today_new_webtoon = {} original_mouse_scroll_size = 0 SPI_SETWHEELSCROLLLINES = 0x0069 def switch_wheel_scroll_size(on): #마우스 스크롤 사이즈 변경 코드. global original_mouse_scroll_size if on: original = OpenKey(HKEY_CURRENT_USER, "Control Panel\\Desktop") value,type = QueryValueEx(original, "WheelScrollLines") original_mouse_scroll_size = value win32gui.SystemParametersInfo(SPI_SETWHEELSCROLLLINES,10) else: win32gui.SystemParametersInfo(SPI_SETWHEELSCROLLLINES, int(original_mouse_scroll_size)) def get_new_webtoon(): global today_new_webtoon #이번달 네이버 신작 3개 랜덤으로 가져오기. page = urllib2.urlopen('http://comic.naver.com/webtoon/weekday.nhn').read() page = page[page.find('<h3><img src="http://static.comic.naver.net/staticImages/COMICWEB/NAVER/img/webtoon/h_new.png"'):page.find('<div class="view_type"> ')] naver_new_month_webtoon = re.findall('href="(.*?)"\>\<strong title="(.*?)"\>',page) for h,name in naver_new_month_webtoon: today_new_webtoon['http://comic.naver.com/'+h] = name.decode('utf-8') #오늘차 다음 신작만화 전체 가져오기. page = urllib2.urlopen('http://webtoon.daum.net/webtoon/').read().decode('utf-8') today = page.split('<ul class="list_timeline">')[1].split('</ul> <!-- //'+u'연재시간표'+' -->')[0] href = re.findall('<a class="thumb_timeline" href="(.*?)" title="(.*?)">',today) today_new_daum = re.findall('\<span class="ico_new"\>NEW\</span\>\s+\<span class="ico_up"\>UP\</span>\s+<a class="thumb_timeline"\s+href="(.*?)"',page) for l in list(set(today_new_daum)): for h in href: if l in h[0]: today_new_webtoon['http://webtoon.daum.net'+l] = h[1] today_new_webtoon = sorted(today_new_webtoon.iteritems(), key=operator.itemgetter(0)) def get_today_webtoon(): get_new_webtoon() global n_today_webtoon, my_webtoon_naver_daum #오늘차 네이버 웹툰 목록 얻기. days = ['mon','tue','wed','thu','fri','sat','sun'] page = urllib2.urlopen('http://comic.naver.com/webtoon/weekday.nhn').read() today = re.findall('<h4 class="(\D+)"><span>\D+</span></h4>',page.split('<div class="col col_selected">')[1])[0] if today=='sun': page = page.split('<h4 class="'+today+'"')[1].split('<div class="goto_area">')[0] else: page = page.split('<h4 class="'+today+'"')[1].split('<h4 class="'+days[days.index(today)+1]+'"')[0] href = re.findall("""<a href="(.*)" .*? class="title" title="(.*)">.*?</a>""",page) for d in href: if d[1].decode('utf-8') in my_webtoon_naver_daum: n_today_webtoon['http://comic.naver.com/'+d[0]] = d[1].decode('utf-8') #오늘차 다음 웹툰 목록 얻기. page = urllib2.urlopen('http://webtoon.daum.net/webtoon/').read().decode('utf-8') today = page.split('<ul class="list_timeline">')[1].split('</ul> <!-- //'+u'연재시간표'+' -->')[0] href = re.findall('<a class="thumb_timeline" href="(.*?)" title="(.*?)">',today) for d in href: if d[1] in my_webtoon_naver_daum: n_today_webtoon['http://webtoon.daum.net/'+d[0]] = d[1] #오늘차 레진코믹스 웹툰 목록 얻기. for link,name,today in my_webtoon_lezin: if today == days[time.localtime().tm_wday]: page = urllib2.urlopen(link+'?fb_locale=ko_KR').read().decode('utf-8').encode(sys.stdout.encoding, 'replace') print link+'?fb_locale=ko_KR','\n\n',page all_list = re.findall('\{"name":.*?"id":\d+\}',page) print all_list cur_time = time.time(); opening_time = [] for l in range(len(all_list)): if all_list[l].find('"freedAt"') != -1: opening_time.append([l,int(re.findall('"freedAt":(.*?),',all_list[l])[0])/1000]) today_new = [] for o in opening_time: if not today_new and cur_time - o[1] > 0: today_new = [o[0],cur_time - o[1]] if cur_time - o[1] > 0 and today_new[1] > (cur_time - o[1]): today_new = [o[0],cur_time - o[1]] new = re.findall('"name":"(.*?)"',all_list[today_new[0]])[0] n_today_webtoon[link+'/'+new] = name n_today_webtoon = sorted(n_today_webtoon.iteritems(), key=operator.itemgetter(0)) def fillForm(web, username, password, count_lezhin): global cnt print cnt doc = web.page().mainFrame().documentElement() doc.findFirst('input[id="email"]').evaluateJavaScript("this.value = '%s'" % username) doc.findFirst('input[id="password"]').evaluateJavaScript("this.value = '%s'" % password) doc.findFirst('div[id="auth-email"] > p > button[tabindex="3"]').evaluateJavaScript("this.click()") #버튼 위치. css에서 자식규칙. 이거 나중에 참고할 일 많을듯. 잊어버리지 말기. cnt += 1 if cnt==count_lezhin: cnt = 0 cnt = 0 def main(): global n_today_webtoon, today_new_webtoon, cnt get_today_webtoon() naver = u'네이버::'; daum = u'다음::'; lezhin = u'레진::' app = QtGui.QApplication(sys.argv) tabs = QtGui.QTabWidget() count_lezhin = len([i for i in n_today_webtoon if i[0].find('lezhin')!=-1]) #오늘자 레진코믹스 웹툰의 갯수를 구함. nam = [QNetworkAccessManager() for i in range(count_lezhin+1)] #오늘자 레진코믹스 웹툰 갯수만큼 만듬. 아래줄도 마찬가지. web1 = [QWebView() for i in range(count_lezhin+1)] today_new_webtoon = map(lambda x:(x[0],u'신작::'+x[1]),today_new_webtoon) n_today_webtoon += today_new_webtoon switch_wheel_scroll_size(True) for link,name in n_today_webtoon: #오늘자 웹툰 갯수만큼 탭을 만듬. web = QWebView() web.settings().setAttribute(QWebSettings.PluginsEnabled, True) web.load(QtCore.QUrl(link)) tabs.resize(1100, 700) #탭 하나당 크기 이정도가 적당함. tabs.move(100, 50) #탭을 표시할 위치. 별로 의미없는듯 if link.find('naver') != -1: if name.find(u'신작') != -1: tabs.addTab(web,name) else: tabs.addTab(web,naver+name) elif link.find('daum') != -1: if name.find(u'신작') != -1: tabs.addTab(web,name) else: tabs.addTab(web,daum+name) elif link.find('lezhin') != -1: web1[cnt].settings().setAttribute(QWebSettings.PluginsEnabled, True) web1[cnt].page().setNetworkAccessManager(nam[cnt]) username = 본인 레진 아이디#ex abcd1@naver.com password = 본인 레진 비밀번호 #ex 1234 web1[cnt].loadFinished.connect(lambda: fillForm(web1[cnt], username, password, count_lezhin)) #코딩시 주의! loadFinished는 말 그대로 아래 코드를 다 실행시키고 내부의 lambda함수를 실행시킴. #fillForm함수 내부에서 이상하게 cnt를 조작하는건 이러한 이유 때문. web1[cnt].load(QtCore.QUrl(link)) tabs.addTab(web1[cnt],lezhin+name) cnt += 1 if cnt == count_lezhin: cnt = 0 tabs.setWindowTitle(u'만화 뷰어.') tabs.show() _exit = app.exec_() switch_wheel_scroll_size(False) #마우스 스크롤을 원래대로 되돌림. sys.exit(_exit) if __name__ == '__main__': main()
#-*- coding: cp949 -*- from distutils.core import setup import py2exe, glob setup( windows=[{'script':'hello.py','icon_resources':[(1, 'webtoon.ico')]}], #console=['hello.py']가 아니라 앞을 windows로 주면 보기싫은 콘솔 창이 사라짐. data_files=[ ('C:\\Users\\Ko\\Desktop\\python exe\\'+u'웹툰 뷰어\\'+'imageformats',glob.glob('C:\\Python27\\Lib\\site-packages\\PyQt4\\plugins\\imageformats\\*.*')) ], options = {'py2exe': { 'bundle_files':3, 'dist_dir':'C:\\Users\\Ko\\Desktop\\python exe\\'+u'웹툰 뷰어', 'includes': ['sip','PyQt4.QtNetwork'], #그냥 py2exe로 만들었을때 이러한 모듈이 없다고 에러뜸. 이거 추가. "dll_excludes": ["MSVCP90.dll"] #이거 없다고 exe가 안만들어지는데 굳이 필요 없으므로 필요 없다고 표시해둠. }}, zipfile = None )
2016-08-09.
결국 레진코믹스 보는건 포기했다. 사이트 개편을 하도많이해서 고치다 고치다 지침. 네이버와 다음만 나오는걸로 만족했다.
네이버, 다음용
# -*- encoding: cp949 -*- from PyQt4 import QtGui from PyQt4 import QtCore from PyQt4.QtWebKit import* from PyQt4.QtNetwork import QNetworkAccessManager import sys import urllib2 import re import time import operator import win32gui from _winreg import * webtoon_list_page = urllib2.urlopen('http://qkqhxla1.tistory.com/381').read().decode('utf-8').split('\'sun\']</p>')[1].split('<p></p><div style=')[0] webtoon_list_page = re.findall('<p>(.*?)</p>',webtoon_list_page) original_mouse_scroll_size = 0 SPI_SETWHEELSCROLLLINES = 0x0069 def switch_wheel_scroll_size(on): #마우스 스크롤 사이즈 변경 코드. global original_mouse_scroll_size if on: original = OpenKey(HKEY_CURRENT_USER, "Control Panel\\Desktop") value,type = QueryValueEx(original, "WheelScrollLines") original_mouse_scroll_size = value win32gui.SystemParametersInfo(SPI_SETWHEELSCROLLLINES,10) else: win32gui.SystemParametersInfo(SPI_SETWHEELSCROLLLINES, int(original_mouse_scroll_size)) n_today_webtoon = {} def get_today_webtoon(): global n_today_webtoon, my_webtoon_naver_daum days = ['mon','tue','wed','thu','fri','sat','sun'] today = days[time.localtime().tm_wday] for list in webtoon_list_page: if list!='': l = list.split(', ') if len(l)==3 and l[2]==today: n_today_webtoon[l[0]] = l[1] else: for i in xrange(len(l)): if l[i]==today: n_today_webtoon[l[i]] = l[1] n_today_webtoon['http://comic.naver.com/webtoon/weekday.nhn'] = u'네이버 웹툰' n_today_webtoon['http://webtoon.daum.net/'] = u'다음 웹툰' n_today_webtoon = sorted(n_today_webtoon.iteritems(),key=lambda x:x[0]) def main(): global n_today_webtoon get_today_webtoon() naver = u'네이버::'; daum = u'다음::'; app = QtGui.QApplication(sys.argv) tabs = QtGui.QTabWidget() switch_wheel_scroll_size(True) for link,name in n_today_webtoon: #오늘자 웹툰 갯수만큼 탭을 만듬. web = QWebView() web.settings().setAttribute(QWebSettings.PluginsEnabled, True) web.load(QtCore.QUrl(link)) tabs.resize(1100, 700) #탭 하나당 크기 이정도가 적당함. tabs.move(100, 50) #탭을 표시할 위치. 별로 의미없는듯 if link.find('naver') != -1: if name.find(u'신작') != -1: tabs.addTab(web,name) else: tabs.addTab(web,naver+name) elif link.find('daum') != -1: if name.find(u'신작') != -1: tabs.addTab(web,name) else: tabs.addTab(web,daum+name) tabs.setWindowTitle(u'만화 뷰어.') tabs.show() _exit = app.exec_() switch_wheel_scroll_size(False) #마우스 스크롤을 원래대로 되돌림. sys.exit(_exit) if __name__ == '__main__': main()
'Python > 2.7 for fun.' 카테고리의 다른 글
아이들용 덧셈색칠퍼즐 만들기. (0) | 2015.08.14 |
---|---|
시력 테스트 자동화 스크립트 1. (0) | 2015.06.26 |
pyqt를 이용한 나만의 웹툰 뷰어 만들기2 (개선) (0) | 2015.05.21 |
나만의 편한 프록시 실행파일 만들기 2. (0) | 2015.05.14 |
나만의 편한 프록시 실행파일 만들기 1. (방법론) (0) | 2015.04.27 |
'Python/2.7 for fun.'의 다른글
- 현재글pyqt를 이용한 나만의 웹툰 뷰어 만들기3 (개선,기능추가)