Python/2.7 for fun.

pyqt를 이용한 나만의 웹툰 뷰어 만들기2 (개선)

qkqhxla1 2015. 5. 21. 11:54

추가 개선 : http://qkqhxla1.tistory.com/358


1차 제작 : http://qkqhxla1.tistory.com/333




내 프로그램은 메모장에서 글을 읽어와서 여기서 파싱작업을 한다.

현재 메모장 내용.


신의 탑,낚시신공,마음의소리,하이브,하루 3컷,복학왕,하나(HANA),전자오락수호대,제페토,갓 오브 하이스쿨,후레자식,아메리카


노 엑소더스,


무빙,왈퐈,귀신,파인,에스탄시아 3,70,블랙 베히모스,시동,늑대처럼 울어라,브레이커2,체이서,무장,치삼만화,죽음이 본다,국민


사형투표,꽃드림,마샬아츠


lezin

http://www.lezhin.com/comic/ssdj2002, 김철수씨 이야기, mon

http://www.lezhin.com/comic/mansion_in_the_dream, 몽중저택, wed

http://www.lezhin.com/comic/the_world, 법칙과 순서의 세계, thu

http://www.lezhin.com/comic/revatoon, 레바툰, fri


이런식으로 되있다. 레진코믹스는 웹툰을 보려면 로그인을 해야 되서 어떻게 할까 고민하다 아래 소스코드를 찾았다.


아래 코드는 구글에 자동으로 로그인하는 소스코드 예제이다. 소스코드 안에 아이디와 비밀번호를 집어넣으면 구글에 로그인되는걸 볼수 있다. 이걸 기초로 사용해서 내 프로그램에 집어넣었다.

# -*- encoding: cp949 -*-
import sys
from PyQt4.QtCore import QUrl
from PyQt4.QtGui import QApplication
from PyQt4.QtWebKit import QWebView
from PyQt4.QtNetwork import QNetworkAccessManager
from PyQt4 import QtCore
from PyQt4.QtWebKit import QWebSettings
def fillForm(web, username, password):
    print "Filling in the form"
    doc = web.page().mainFrame().documentElement()

    print "Finding username tag"
    user = doc.findFirst("input[id=Email]")
    print "Finding passwd tag"
    passwd = doc.findFirst("input[id=Passwd]")    

    print "Setting information"
    user.evaluateJavaScript("this.value = '%s'" % username)
    passwd.evaluateJavaScript("this.value = '%s'" % password)    
    button = doc.findFirst("input[id=signIn]")
    button.evaluateJavaScript("this.click()")

def doLogin(web, url, username, password):        
    web.loadFinished.connect(lambda: fillForm(web, username, password))
    web.load(url)
    web.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    nam = QNetworkAccessManager()
    web = QWebView()

    settings = web.settings()
    settings.setAttribute(QWebSettings.PluginsEnabled, True)

    web.page().setNetworkAccessManager(nam)
    url = QUrl(r"https://accounts.google.com/Login")
    username = 본인 구글 아이디#ex abcd1@naver.com
    password = 본인 구글 비밀번호#ex 1234
    doLogin(web, url, username, password)
    app.exec_()

이런식으로 로그인 부분을 구현할 수 있다. 네이버나 다음은 로그인 안해도 웹툰을 볼수 있으므로 그냥 웹툰 탭을 만들고, 레진 관련된 웹툰의 탭을 만들때만 로그인 정보를 넘겨서 로그인을 시켜주면 된다.


소스코드.

# -*- 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
     
my_webtoon_naver_daum = map(lambda x:unicode(x.replace('\n',''),'cp949'), open('webtoon_list.txt','r').read().split('lezin')[0].split(','))
my_webtoon_lezin = map(lambda x:x.replace('\n','').split(', '), open('webtoon_list.txt','r').read().split('lezin')[1].split('\n')[1:])
my_webtoon_lezin = map(lambda x:(x[0],unicode(x[1],'cp949'),x[2]),my_webtoon_lezin)
n_today_webtoon = {}
   
def get_today_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).read().decode('utf-8')
            all_list = re.findall('\{"episodeId".*?"freed":\d+\}',page) #전체 목록 리스트를 가져와서
            try: #무료로 풀린 웹툰 파싱해서 가져오는거. 이거 자주 에러남 자주 볼것.
                #print map(lambda x:1 if (x.find('"free":false') != -1 and x.find('"freeDate":""') == -1) else 0,all_list),'\n\n'
                all_list = all_list[:map(lambda x:1 if x.find('"free":false') != -1 and x.find('"freeDate":""') == -1 else 0,all_list).index(1)] #아직 무료가 안풀린 웹툰 범위까지 전부 가져와서
            except: #그냥 가장 위의 웹툰만 가져오면 되는거. 레진코믹스 같은거.
                all_list = all_list[:map(lambda x:1 if x.find('"free":true') != -1 else 0,all_list).index(1,-1) + 1]
            href = [i for i in map(lambda x:re.findall('"episodeId":"(.*?)".*?"free":true',x),all_list) if i != []][-1][-1] #free가 true인 화의 끝부분이 최신 무료회차.
            #print href
            n_today_webtoon['http://www.lezhin.com/comic/'+href] = name
    #print n_today_webtoon
   
    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, 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)]
       
   
    for link,name in n_today_webtoon: #오늘자 웹툰 갯수만큼 탭을 만듬.
        web = QWebView()
        web.settings().setAttribute(QWebSettings.PluginsEnabled, True)
        web.load(QtCore.QUrl(link))
         
        vBoxlayout    = QtGui.QVBoxLayout()
        vBoxlayout.addWidget(web)
        tab1    = QtGui.QWidget()    
        tab1.setLayout(vBoxlayout) #레이아웃을 위에 만든 vBoxlayout으로.
     
        tabs.resize(1100, 700) #탭 하나당 크기 이정도가 적당함.
        tabs.move(100, 50) #탭을 표시할 위치. 별로 의미없는듯
   
        if link.find('naver') != -1:
            tabs.addTab(tab1,naver+name)
        elif link.find('daum') != -1:
            tabs.addTab(tab1,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()
    sys.exit(app.exec_())
         
if __name__ == '__main__':
    main()


setup.py #exe가 만들어지는 경로의 txt파일에 기본적으로 내가 좋아하는 목록들을 써놓았다.

#-*- 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
     )

open('C:\\Users\\Ko\\Desktop\\python exe\\'+u'웹툰 뷰어'+'\\webtoon_list.txt','w').write('''신의 탑,낚시신공,마음의소리,하이브,하루 3컷,복학왕,하나(HANA),전자오락수호대,제페토,갓 오브 하이스쿨,후레자식,아메리카노 엑소더스,

무빙,왈퐈,귀신,파인,에스탄시아 3,70,블랙 베히모스,시동,늑대처럼 울어라,브레이커2,체이서,무장,치삼만화,죽음이 본다,국민사형투표,꽃드림,마샬아츠

lezin
http://www.lezhin.com/comic/ssdj2002, 김철수씨 이야기, mon
http://www.lezhin.com/comic/mansion_in_the_dream, 몽중저택, wed
http://www.lezhin.com/comic/the_world, 법칙과 순서의 세계, thu
http://www.lezhin.com/comic/revatoon, 레바툰, fri''')  



2015/06/08 

개선하면 좋을것 같은것.

1. 새로 나온 만화는 따로 오른쪽 탭에 보여주는거 추가.(매번 확인하는거 귀찮다.)