漫画はもうお金を使いません。Pythonはある漫画の脚本とソースを取得します。


一、工具
  • python 3
  • 第三者類庫requests
  • python 3-pyqt 5(GUI依存、GUIなしで装着できます)
  • uuntuシリーズのシステムは、以下のコマンドを使用してインストールに依存します。
    URLフォーマット:漫画のトップページのURL、例えばhttp://m.ac.qq.com/Comic/view/id/518333(モバイル版)またはhttp://ac.qq.com/Comic/comicInfo/id/17114http://ac.qq.com/naruto(PC版)
    注意:NARUTO-ナルト-彩漫はm.ac.qq.comを訪問してNARUTO-ナルト-を検索する必要があります。
    二、コマンドラインヘルプ
    
    usage: getComic.py [-h] [-u URL] [-p PATH] [-d] [-l LIST]
     
    *      ,      ,        *
                 。
     
    optional arguments:
      -h, --help            show this help message and exit
      -u URL, --url URL              ,         url: 
                            http://ac.qq.com/Comic/comicInfo/id/511915
                            http://m.ac.qq.com/Comic/comicInfo/id/505430
                            http://pad.ac.qq.com/Comic/comicInfo/id/505430
                            http://ac.qq.com/naruto
      -p PATH, --path PATH        。   : /home/fengyu/tencent_comic
      -d, --dir                         (             )
      -l LIST, --list LIST            ,          。    : 
                            N -         , -l 1,    1 
                            N,N... -            ,  "-l 1,3,5",   1,3,5 
                            N-N... -           ,  "-l 10-50",   [10,50] 
                                -          ,  "-l 1,3,5-7,11-111"
    
    三、GUIプレビュー効果
    不連続なチャプター選択のダウンロードをサポートします。
    windowsプレビューの効果:

    deepin/Linuxプレビューの効果:

    四、全部のソースコード
    
    import requests
    import re
    import json
    import os
    import argparse
     
    requestSession = requests.session()
    UA = 'Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X; en-us) \
            AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 \
            Mobile/9B176 Safari/7534.48.3' # ipad UA
    requestSession.headers.update({'User-Agent': UA})
     
    class ErrorCode(Exception):
        '''      :
            1: URL   
            2: URL        URL
            3:     '''
        def __init__(self, code):
            self.code = code
     
        def __str__(self):
            return repr(self.code)
     
    def isLegelUrl(url):
        legal_url_list = [
            re.compile(r'^http://ac.qq.com/Comic/[Cc]omicInfo/id/\d+/?$'),
            re.compile(r'^http://m.ac.qq.com/Comic/[Cc]omicInfo/id/\d+/?$'),
            re.compile(r'^http://ac.qq.com/\w+/?$'),
            re.compile(r'^http://pad.ac.qq.com/Comic/[Cc]omicInfo/id/\d+/?$')
        ]
     
        for legal_url in legal_url_list:
            if legal_url.match(url):
                return True
        return False
     
    def getId(url):
        if not isLegelUrl(url):
            print('      url!     url       -h|--help        。')
            raise ErrorCode(1)
     
        numRE = re.compile(r'\d+$')
        
        id = numRE.findall(url)
        if not id:
            get_id_request = requestSession.get(url)
            url = get_id_request.url
            id = numRE.findall(url)
            if not isLegelUrl(url) or not id:
                print('         URL,   http://m.ac.qq.com,  '
                '     。
    ' ' : ' 'http://m.ac.qq.com/Comic/comicInfo/id/xxxxx (xxxxx )') raise ErrorCode(2) return id[0] def getContent(id): getComicInfoUrl = 'http://pad.ac.qq.com/GetData/getComicInfo?id={}'.format(id) requestSession.headers.update({'Cookie': 'ac_refer=http://pad.ac.qq.com'}) requestSession.headers.update({'Referer': 'http://pad.ac.qq.com'}) getComicInfo = requestSession.get(getComicInfoUrl) comicInfoJson = getComicInfo.text comicInfo = json.loads(comicInfoJson) comicName = comicInfo['title'] comicIntrd = comicInfo['brief_intrd'] getChapterListUrl = 'http://pad.ac.qq.com/GetData/getChapterList?id={}'.format(id) getChapterList = requestSession.get(getChapterListUrl) contentJson = json.loads(getChapterList.text) count = contentJson['length'] sortedContentList = [] for i in range(count + 1): for item in contentJson: if isinstance(contentJson[item], dict) and contentJson[item].get('seq') == i: sortedContentList.append({item: contentJson[item]}) break return (comicName, comicIntrd, count, sortedContentList) def getImgList(contentJson, id): cid = list(contentJson.keys())[0] getPicHashURL = 'http://pad.ac.qq.com/View/mGetPicHash?id={}&cid={}'.format(id, cid) picJsonPage = requestSession.get(getPicHashURL).text picJson = json.loads(picJsonPage) count = picJson['pCount'] # pHash = picJson['pHash'] sortedImgDictList = [] for i in range(1, count + 1): for item in pHash: if pHash[item]['seq'] == i: sortedImgDictList.append(pHash[item]) break imgList = [] for imgDict in sortedImgDictList: k = imgDict['cid'] m = imgDict['pid'] j = int(id) uin = max(j + k + m, 10001) l = [j % 1000 // 100, j % 100, j, k] n = '/mif800/' + '/'.join(str(j) for j in l) + '/' h = str(m) + '.mif2' g="http://ac.tc.qq.com/store_file_download?buid=15017&uin="+str(uin)+"&dir_path="+n+"&name="+h imgList.append(g) return imgList def downloadImg(imgUrlList, contentPath, one_folder=False): count = len(imgUrlList) print(' {} '.format(count)) i = 1 for imgUrl in imgUrlList: print('\r {} ...'.format(i), end = '') if not one_folder: imgPath = os.path.join(contentPath, '{0:0>3}.jpg'.format(i)) else: imgPath = contentPath + '{0:0>3}.jpg'.format(i) i += 1 # if os.path.isfile(imgPath): continue try: downloadRequest = requestSession.get(imgUrl, stream=True) with open(imgPath, 'wb') as f: for chunk in downloadRequest.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) f.flush() except (KeyboardInterrupt, SystemExit): print('

    , !') if os.path.isfile(imgPath): os.remove(imgPath) raise ErrorCode(3) print(' !
    ') def parseLIST(lst): ''' -l|--list , ''' legalListRE = re.compile(r'^\d+([,-]\d+)*$') if not legalListRE.match(lst): raise LISTFormatError(lst + ' : ' + r'^\d+([,-]\d+)*$') # , parsedLIST = [] sublist = lst.split(',') numRE = re.compile(r'^\d+$') for sub in sublist: if numRE.match(sub): if int(sub) > 0: # 0 parsedLIST.append(int(sub)) else: print(' : 0, ') else: splitnum = list(map(int, sub.split('-'))) maxnum = max(splitnum) minnum = min(splitnum) #min-max max-min if minnum == 0: minnum = 1 # 0 print(' : 0, ') parsedLIST.extend(range(minnum, maxnum+1)) parsedLIST = sorted(set(parsedLIST)) # return parsedLIST def main(url, path, lst=None, one_folder=False): '''url: 。 path: 。 lst: (-l|--list )''' try: if not os.path.isdir(path): os.makedirs(path) id = getId(url) comicName,comicIntrd,count,contentList = getContent(id) contentNameList = [] for item in contentList: for k in item: contentNameList.append(item[k]['t']) print(' : {}'.format(comicName)) print(' : {}'.format(comicIntrd)) print(' : {}'.format(count)) print(' :') try: print('
    '.join(contentNameList)) except Exception: print('
    ') forbiddenRE = re.compile(r'[\\/":*?<>|]') #windows \ / : * ? " < > | comicName = re.sub(forbiddenRE, '_', comicName) # windows _ comicPath = os.path.join(path, comicName) if not os.path.isdir(comicPath): os.makedirs(comicPath) print() if not lst: contentRange = range(1, len(contentList) + 1) else: contentRange = parseLIST(lst) for i in contentRange: if i > len(contentList): print(' : {} ,' ' ,' ' '.format(len(contentList))) break contentNameList[i - 1] = re.sub(forbiddenRE, '_', contentNameList[i - 1]) # windows _ contentPath = os.path.join(comicPath, ' {0:0>4} -{1}'.format(i, contentNameList[i - 1])) try: print(' {0:0>4} : {1}'.format(i, contentNameList[i -1])) except Exception: print(' {0:0>4} : {1}'.format(i)) if not one_folder: if not os.path.isdir(contentPath): os.mkdir(contentPath) imgList = getImgList(contentList[i - 1], id) downloadImg(imgList, contentPath, one_folder) except ErrorCode as e: exit(e.code) if __name__ == '__main__': defaultPath = os.path.join(os.path.expanduser('~'), 'tencent_comic') parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description='* , , *
    ' ' 。') parser.add_argument('-u', '--url', help=' , url:
    ' 'http://ac.qq.com/Comic/comicInfo/id/511915
    ' 'http://m.ac.qq.com/Comic/comicInfo/id/505430
    ' 'http://pad.ac.qq.com/Comic/comicInfo/id/505430
    ' 'http://ac.qq.com/naruto') parser.add_argument('-p', '--path', help=' 。 : {}'.format(defaultPath), default=defaultPath) parser.add_argument('-d', '--dir', action='store_true', help=' ( )') parser.add_argument('-l', '--list', help=(" , 。 :
    " "N - , -l 1, 1
    " 'N,N... - , "-l 1,3,5", 1,3,5
    ' 'N-N... - , "-l 10-50", [10,50]
    ' ' - , "-l 1,3,5-7,11-111"')) args = parser.parse_args() url = args.url path = args.path lst = args.list one_folder = args.dir if lst: legalListRE = re.compile(r'^\d+([,-]\d+)*$') if not legalListRE.match(lst): print('LIST , --help !') exit(1) if not url: url = input(' : ') path = input(' ( : {}): '.format(defaultPath)) if not path: path = defaultPath main(url, path, lst, one_folder)
    五、ソースのダウンロード
    
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    import getComic
    import os
    import re
    import sys
     
    class TencentComicDownloader(QWidget):
        def __init__(self, parent=None):
            super(TencentComicDownloader, self).__init__(parent)
     
            nameLabel = QLabel("    :")
     
            self.nameLine = QLineEdit()
     
            self.analysisButton = QPushButton("  ")
            self.analysisButton.clicked.connect(self.anaysisURL)
            self.nameLine.returnPressed.connect(self.analysisButton.click)
     
            pathLineLabel = QLabel("    :")
            self.pathLine = QLineEdit()
            defaultPath = os.path.join(os.path.expanduser('~'), 'tencent_comic')
            self.pathLine.setText(defaultPath)
            
            self.browseButton = QPushButton("  ")
            self.browseButton.clicked.connect(self.getPath)
     
            comicNameLabel = QLabel("   : ")
            self.comicNameLabel = QLabel("  ")
            self.one_folder_checkbox = QCheckBox("   ")
            
            comicIntroLabel = QLabel("  : ")
            self.comicIntro = QLabel("  ")
            self.comicIntro.setWordWrap(True)
     
            chapterGroupBox = QGroupBox("    :")
            
            self.chapterListView = QListWidget(chapterGroupBox)
            self.chapterListView.setSelectionMode(QAbstractItemView.ExtendedSelection)
            self.chapterListView.setEnabled(False)
     
            groupBoxLayout = QHBoxLayout(chapterGroupBox)
            groupBoxLayout.addWidget(self.chapterListView)
     
            self.downloadButton = QPushButton("    ")
            self.statusLabel = QLabel("           ,     ")
            self.statusLabel.setWordWrap(True)
     
            self.downloadButton.setEnabled(False)
            self.downloadButton.clicked.connect(self.download)
     
            mainLayout = QGridLayout()
            mainLayout.addWidget(nameLabel, 0, 0)
            mainLayout.addWidget(self.nameLine, 0, 1)
            mainLayout.addWidget(self.analysisButton, 0, 2)
            mainLayout.addWidget(pathLineLabel, 1, 0)
            mainLayout.addWidget(self.pathLine, 1, 1)
            mainLayout.addWidget(self.browseButton, 1, 2)
            mainLayout.addWidget(comicNameLabel, 2, 0)
            mainLayout.addWidget(self.comicNameLabel, 2, 1, 1, 2)
            mainLayout.addWidget(self.one_folder_checkbox, 2, 2)
            mainLayout.addWidget(comicIntroLabel, 3, 0)
            mainLayout.addWidget(self.comicIntro, 3, 1, 1, 2)
            mainLayout.addWidget(chapterGroupBox, 4, 0, 1, 3)
            mainLayout.addWidget(self.downloadButton, 5, 2)
            mainLayout.addWidget(self.statusLabel, 5, 0, 1, 2)
     
            self.setLayout(mainLayout)
            self.setWindowTitle("      ")
            self.setGeometry(400, 300, 800, 500)
     
        def setStatus(self, status):
            self.statusLabel.setText(status)
     
        def enableWidget(self, enable):
            widgets_list = [
                    self.downloadButton,
                    self.nameLine,
                    self.pathLine,
                    self.chapterListView,
                    self.analysisButton,
                    self.browseButton,
                    self.one_folder_checkbox
            ]
            for widget in widgets_list:
                widget.setEnabled(enable)
     
            if enable:
                self.downloadButton.setText('    ')
                self.chapterListView.setFocus()
     
        def getPath(self):
            path = str(QFileDialog.getExistingDirectory(self, "      "))
            if path:
                self.pathLine.setText(path)
     
        def anaysisURL(self):
            url = self.nameLine.text()
     
            self.downloadButton.setEnabled(False)
            self.comicNameLabel.setText("  ")
            self.comicIntro.setText("  ")
            self.chapterListView.clear()
            self.chapterListView.setEnabled(False)
     
            try:
                if getComic.isLegelUrl(url):
                    self.id = getComic.getId(url)
                    self.comicName,self.comicIntrd,self.count,self.contentList = getComic.getContent(self.id)
     
                    self.contentNameList = []
                    for item in self.contentList:
                        for k in item:
                            self.contentNameList.append(item[k]['t'])
                    
                    self.comicNameLabel.setText(self.comicName)
                    self.comicIntro.setText(self.comicIntrd)
                    self.chapterListView.setEnabled(True)
                    self.downloadButton.setEnabled(True)
                    self.chapterListView.setFocus()
                    self.statusLabel.setText('               ')
     
                    for i in range(len(self.contentNameList)):
                        self.chapterListView.addItem(' {0:0>4} -{1}'.format(i+1, self.contentNameList[i]))
                        self.chapterListView.item(i).setSelected(True)
     
                    self.downloadButton.setEnabled(True)
     
                else:
                    self.statusLabel.setText('<font color="red">   URL  !            !</font>')
     
            except getComic.ErrorCode as e:
                if e.code == 2:
                    self.statusLabel.setText('<font color="red">        URL,   http://m.ac.qq.com       </font>')
     
            except KeyError:
                self.statusLabel.setText('<font color="red">      </font>')
     
        def download(self):
            self.downloadButton.setText("   ...")
            one_folder = self.one_folder_checkbox.isChecked()
     
            self.enableWidget(False)
     
            selectedChapterList = [ item.row() for item in self.chapterListView.selectedIndexes() ]
     
            path = self.pathLine.text()
            comicName = self.comicName
            forbiddenRE = re.compile(r'[\\/":*?<>|]') #windows        \ / : * ? " < > |
            comicName = re.sub(forbiddenRE, '_', comicName) # windows           _
            comicPath = os.path.join(path, comicName)
     
            if not os.path.isdir(comicPath):
                os.makedirs(comicPath)
     
            self.downloadThread = Downloader(selectedChapterList, comicPath, self.contentList, self.contentNameList, self.id, one_folder)
            self.downloadThread.output.connect(self.setStatus)
            self.downloadThread.finished.connect(lambda: self.enableWidget(True))
            self.downloadThread.start()
            
    class Downloader(QThread):
        output = pyqtSignal(['QString'])
        finished = pyqtSignal()
     
        def __init__(self, selectedChapterList, comicPath, contentList, contentNameList, id, one_folder=False, parent=None):
            super(Downloader, self).__init__(parent)
     
            self.selectedChapterList = selectedChapterList
            self.comicPath = comicPath
            self.contentList = contentList
            self.contentNameList = contentNameList
            self.id = id
            self.one_folder = one_folder
     
        def run(self):
            try:
                for i in self.selectedChapterList:
                    outputString = '     {0:0>4} : {1}...'.format(i+1, self.contentNameList[i])
                    print(outputString)
                    self.output.emit(outputString)
                    forbiddenRE = re.compile(r'[\\/":*?<>|]') #windows        \ / : * ? " < > |
                    self.contentNameList[i] = re.sub(forbiddenRE, '_', self.contentNameList[i])
                    contentPath = os.path.join(self.comicPath, ' {0:0>4} -{1}'.format(i+1, self.contentNameList[i]))
                    if not self.one_folder:
                        if not os.path.isdir(contentPath):
                            os.mkdir(contentPath)
                    imgList = getComic.getImgList(self.contentList[i], self.id)
                    getComic.downloadImg(imgList, contentPath, self.one_folder)
                    
                    self.output.emit('  !')
           
            except Exception as e:
                self.output.emit('<font color="red">{}</font>
    ' ' ! '.format(e)) raise finally: self.finished.emit() if __name__ == '__main__': app = QApplication(sys.argv) main = TencentComicDownloader() main.show() app.exec_()
    これはもうお金を使って漫画を買う必要がないです。Pythonは漫画の脚本とソースの文章をダウンロードして紹介しました。漫画の内容に関しては、以前の文章を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。