def __init__(self, file, mode=None): """ :param file: 要处理的文件 :param mode: 要处理的格式,不输入会有一套智能匹配算法 'rar': 'zip': docx后缀的,默认采用zip格式解压 """ # 1、确定压缩格式 name, ext = os.path.splitext(file) ext = ext.lower() if not mode: if ext in ('.docx', '.zip'): mode = 'zip' elif ext == '.rar': mode = 'rar' else: dprint(ext) # 从文件扩展名无法得知压缩格式 raise ValueError self.mode = mode # 2、确定是用的解压“引擎” if mode == 'zip': self.proc = zipfile.ZipFile(file) elif mode == 'rar': try: from unrar.rarfile import RarFile except ModuleNotFoundError: dprint( ) # 缺少unrar模块,安装详见: https://blog.csdn.net/code4101/article/details/79328636 raise ModuleNotFoundError self.proc = RarFile(file) # 3、解压文件夹目录,None表示还未解压 self.tempfolder = None
def rar_crack(self, pwd): runtime = self.show() print(f'破解已用时: {runtime} 当前密码: {pwd}', end='\r') try: rar_file = RarFile(self.filename, pwd=pwd) rar_file.extractall() print(f'破解已完成: {runtime} 压缩密码: {pwd}') with open('res.txt', 'w') as f: f.write(pwd) os._exit(0) except: pass
def extract_no_password(zipfile_path: str, extract_path: str) -> bool: """ 尝试用空密码解压\n :param zipfile_path: 压缩文件路径字符串 :param extract_path: 解压路径字符串 :return: 是否能解压成功 """ if zipfile_path.lower().endswith(".zip"): with ZipFile(zipfile_path) as file: try: file.extractall(path=extract_path, members=None, pwd=None) except RuntimeError: return False except BadZipFile: return False except error: return False except Exception as e: print("遇到未知错误", type(e), e) else: return True elif zipfile_path.lower().endswith(".rar"): with RarFile(zipfile_path) as file: try: file.extractall(path=extract_path, members=None, pwd=None) except RuntimeError: return False except BadZipFile: return False except error: return False except Exception as e: print("遇到未知错误", type(e), e) else: return True
def extract_rar(passwords: (str, ), zipfile_path: str, extract_path: str) -> str: """ 解压rar文件\n :param passwords: 密码组成的元组 :param zipfile_path: 压缩文件路径字符串 :param extract_path: 解压路径字符串 :return: 如果找到了密码,返回密码字符串;如果没找到密码,返回None """ with RarFile(zipfile_path) as file: for password in passwords: # 如果是空密码则跳过 if len(password) == 0: continue try: file.extractall(path=extract_path, members=None, pwd=password) except RuntimeError: print("尝试密码 %s 失败" % password) except BadRarFile: print("尝试密码 %s 失败" % password) except Exception as e: print("尝试密码", password, "遇到未知错误", type(e), e) else: print("尝试密码 %s 成功" % password) return password
def run(self): for root, dirs, files in os.walk(self.comic_dir, topdown=True): for file in files: if file.endswith('.cbr'): file_name = file.split('.cbr')[0] zip_file_name = file_name + '.cbz' print(zip_file_name) comic = RarFile(file) comic.testrar() print(zip_file_name) zip_comic = ZipFile(zip_file_name, 'w') self.convert_rar_to_zip(comic, zip_comic) if file.endswith('.cbz'): zip_comic = ZipFile(file) self.gather_comic_info(zip_comic)
def extract_rar(rar: rarfile.RarFile, rar_entry: rarfile.RarInfo, tmp_dir_name, passwd=None): """ Extract rar entry from archive using unrar module, also realise smart behaviour - apply a list of predefined passwords to encrypted rar entry if passwd param is not set. Look at DEFAULT_ARC_PASSWORDS in configuration. :param rar: unrar.rarfile.RarFile instance :param rar_entry: unrar.rarfile.RarInfo instance :param tmp_dir_name: path to tmp dir (string) :param passwd: password string :return: Nothing """ try: rar.extract(rar_entry.filename, tmp_dir_name, pwd=passwd) log.debug( f"===>Extracted:{rar_entry.filename} to {tmp_dir_name} without pwd" ) return except (rarfile.BadRarFile, RuntimeError) as err: # Only if no password given log.debug( f"===>Can't extract:{rar_entry.filename} to {tmp_dir_name} without pwd: {str(err)}" ) if str(err).startswith('Bad header data') or \ str(err).startswith('File is encrypted'): # may be file is encrypted for passwd in cfg.DEFAULT_ARC_PASSWORDS: # TODO - store passwords encrypted in db try: rar.extract(rar_entry.filename, tmp_dir_name, pwd=passwd) log.debug( f"===>Extracted:{rar_entry.filename} to {tmp_dir_name} with pwd" ) return except (rarfile.BadRarFile, RuntimeError) as e: # Bad password log.debug( f"===>Can't extract:{rar_entry.filename} to {tmp_dir_name} with pwd: {str(e)}" ) continue raise err
def extract_rar_volumes(rar: rarfile.RarFile, tmp_dir_name): volumes = list() for entry in rar.infolist(): num = find_rar_volume_num(entry.filename) if num: # find any volume if num == 1: # main volume log.debug( f'===>Pass main volume:{entry.filename}, would be extracted later, tmp={tmp_dir_name}' ) continue else: log.debug( f'===>Extracting volume:{entry.filename} to {tmp_dir_name}' ) extract_rar(rar, entry, tmp_dir_name) volumes.append(entry) for entry in volumes: log.debug(f"===>Delete:{entry.filename} from file list") if entry.filename in rar.NameToInfo: del rar.NameToInfo[entry.filename] del rar.filelist[rar.filelist.index(entry)]
class PackFile: def __init__(self, file, mode=None): """ :param file: 要处理的文件 :param mode: 要处理的格式,不输入会有一套智能匹配算法 'rar': 'zip': docx后缀的,默认采用zip格式解压 """ # 1、确定压缩格式 name, ext = os.path.splitext(file) ext = ext.lower() if not mode: if ext in ('.docx', '.zip'): mode = 'zip' elif ext == '.rar': mode = 'rar' else: dprint(ext) # 从文件扩展名无法得知压缩格式 raise ValueError self.mode = mode # 2、确定是用的解压“引擎” if mode == 'zip': self.proc = zipfile.ZipFile(file) elif mode == 'rar': try: from unrar.rarfile import RarFile except ModuleNotFoundError: dprint( ) # 缺少unrar模块,安装详见: https://blog.csdn.net/code4101/article/details/79328636 raise ModuleNotFoundError self.proc = RarFile(file) # 3、解压文件夹目录,None表示还未解压 self.tempfolder = None def open(self, member, pwd=None): """Return file-like object for 'member'. 'member' may be a filename or a RarInfo object. """ return self.proc.open(member, pwd) def read(self, member, pwd=None): """Return file bytes (as a string) for name.""" return self.proc.read(member, pwd) def namelist(self): """>> self.namelist() # 获得文件清单列表 1 [Content_Types].xml 2 _rels/.rels ...... 20 word/fontTable.xml 21 docProps/app.xml """ return self.proc.namelist() def setpassword(self, pwd): """Set default password for encrypted files.""" return self.proc.setpassword(pwd) def getinfo(self, name): """ >> self.getinfo('word/document.xml') # 获得某个文件的信息 <ZipInfo filename='word/document.xml' compress_type=deflate file_size=140518 compress_size=10004> """ return self.proc.getinfo(name) def infolist(self, prefix=None, zipinfo=True): """>> self.infolist() # getinfo的多文件版本 1 <ZipInfo filename='[Content_Types].xml' compress_type=deflate file_size=1495 compress_size=383> 2 <ZipInfo filename='_rels/.rels' compress_type=deflate file_size=590 compress_size=243> ...... 20 <ZipInfo filename='word/fontTable.xml' compress_type=deflate file_size=1590 compress_size=521> 21 <ZipInfo filename='docProps/app.xml' compress_type=deflate file_size=720 compress_size=384> :param prefix: 可以筛选文件的前缀,例如“word/”可以筛选出word目录下的 :param zipinfo: 返回的list每个元素是zipinfo数据类型 """ ls = self.proc.infolist() if prefix: ls = list(filter(lambda t: t.filename.startswith(prefix), ls)) if not zipinfo: ls = list(map(lambda x: x.filename, ls)) return ls def printdir(self): """Print a table of contents for the RAR file.""" return self.proc.printdir() def testrar(self): """Read all the files and check the CRC.""" return self.proc.testrar() def extract(self, member, path=None, pwd=None): """注意,如果写extract('word/document.xml', 'a'),那么提取出来的文件是在'a/word/document.xml' """ return self.proc.extract(member, path, pwd) def extractall(self, path=None, members=None, pwd=None): """Extract all members from the archive to the current working directory. `path' specifies a different directory to extract to. `members' is optional and must be a subset of the list returned by namelist(). """ return self.proc.extractall(path, members, pwd) def extractall2tempfolder(self): """将文件解压到一个临时文件夹,并返回临时文件夹目录""" if not self.tempfolder: self.tempfolder = tempfile.mkdtemp() self.proc.extractall(path=self.tempfolder) return self.tempfolder def clear_tempfolder(self): """删除创建的临时文件夹内容""" filesdel(self.tempfolder) def __enter__(self): """使用with ... as ...语法能自动建立解压目录和删除 注意:这里返回的不是PackFile对象,而是解压后的目录 """ path = self.extractall2tempfolder() return path def __exit__(self, exc_type, exc_val, exc_tb): self.clear_tempfolder()
def _open_rarfile(self): rar_filename = os.path.join(TESTS_DIR, 'test_rar.rar') rar = RarFile(rar_filename) return rar
def _open_rarfile(self): rar_filename = os.path.join(TESTS_DIR, 'test_corrupted.rar') rar = RarFile(rar_filename) rar.setpassword('testing') return rar
def _open_rarfile(self): rar_filename = os.path.join(TESTS_DIR, 'test_password.rar') rar = RarFile(rar_filename, pwd='password') return rar
def __init__(self, path): if '.zip' in path: self.xfile = ZipFile(path) else: # Always going to be .rar -- see filelist.getMods self.xfile = RarFile(path) self.archiveformat = ''
class Loader: def __init__(self, path): if '.zip' in path: self.xfile = ZipFile(path) else: # Always going to be .rar -- see filelist.getMods self.xfile = RarFile(path) self.archiveformat = '' def howMany(self): return len(self.xfile.namelist()) def checkSafe(self, name): if name[0] != '/' and not '..' in name: return True else: return False def getType(self): for basename in self.xfile.namelist(): name = basename.replace('\\','/') if 'resources/' in name: self.archiveformat = 'resourcesdir' return else: split = name.split('/') for bfile in basefiles: if bfile in split: found = split.index(bfile) if found == 0: self.archiveformat = 'rootdir' return else: self.archiveformat = 'nameddir' self.dirname = split[found-1] + '/' return self.archiveformat = 'notmod' def extract(self): for basename in self.xfile.namelist(): name = basename.replace('\\','/') skip = False if self.archiveformat == 'resourcesdir' and 'resources/' in name: innerpath = name.split('resources/')[1] elif self.archiveformat == 'rootdir': innerpath = name elif self.archiveformat == 'nameddir' and self.dirname in name: innerpath = name.split(self.dirname)[1] elif self.archiveformat == 'notmod': print('Not a mod archive in a format I recognize.') return False else: skip = True if not self.checkSafe(name): print('"'+name+'" is considered to be unsafe.') skip = True if not skip: innerpath = innerpath.lower() joined = ( RESPATH + innerpath ).replace('\\','/') dirpath = '/'.join(joined.split('/')[:-1]) if '.' in joined.split('/')[-1]: isfile = True else: isfile = False if WINDOWS: for string in name, joined, dirpath: string = string.replace('/','\\') print('Internal Path: '+name) print('Extraction Path: '+joined) if isfile: if not os.path.exists(dirpath): os.makedirs(dirpath) if os.path.exists(joined): print('Conflict at "' + joined + '"') with open(joined, 'wb') as location: location.write(self.xfile.read(basename)) def load(self): if self.archiveformat == '': self.getType() self.extract()