{"id":381912,"date":"2024-06-29T03:57:21","date_gmt":"2024-06-29T03:57:21","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=381912"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=381912","title":{"rendered":"<span>\u041f\u043e\u0438\u0441\u043a \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/58d\/c7e\/e3f\/58dc7ee3f5af5e8d639098a39ca8ad6b.png\" width=\"1280\" height=\"720\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/58d\/c7e\/e3f\/58dc7ee3f5af5e8d639098a39ca8ad6b.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.\u00a0 \u0427\u0442\u043e\u0431\u044b \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0443\u0434\u043e\u0431\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c. \u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 Python \u0435\u0441\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c click (\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 pip install click). \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u0432. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b: search_path \u2014 \u043f\u0443\u0442\u044c \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043a\u0430\u0442\u044c, \u043b\u0438\u0431\u043e \u0444\u0430\u0439\u043b \u0441 \u043f\u0443\u0442\u044f\u043c\u0438 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435: \u0440\u0435\u0436\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b (\u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u043b\u0438 \u0431\u0435\u0437), \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438, \u0444\u043e\u0440\u043c\u0430\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 (excel, csv, sqlite) \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u0436\u0435\u043b\u0430\u043d\u0438\u044e.<\/p>\n<pre><code>@click.command() @click.argument('search_path',                 type=click.Path(resolve_path=True,                                 dir_okay=True,                                 file_okay=True),                 required=True) @click.option('--concurrent_mode', '-cm',               type=click.STRING,               required=False,               default=\"None\",               help=\"Concurrent search execution(multi or single).\"                    \" Multi allows multiprocessing and threading\") @click.option('--output_path', '-o',               type=click.STRING,               required=False,               default='results',               help=\"Output filename(without extension)\") @click.option('--output_type', '-ot', '-out',               type=click.STRING,               required=False,               default='sqlite',               help=\"Format for output data((excel, csv, sqlite, mssql)\") ... def main(search_path, output_path, concurrent_mode, output_type):     \"\"\"     Starts search info(cards numbers) in files in path      search_path: path to search or json file with paths     \"\"\"     ...  if __name__ == \"__main__\":     main()<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0438\u0441\u043a\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u00a0<em>main().<\/em>\u00a0\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u0437\u043e\u0432 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>multi_mode = True if not concurrent_mode.lower() == \"single\" else False search_in_files(search_path, file_types, output_path, maxsize,                 buffer_size, clear_results, clear_log, continue_option,                 multi_mode, output_type, debug, include)<\/code><\/pre>\n<p>\u0421\u043e\u0432\u0435\u0440\u0448\u0438\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043e\u0448\u0438\u0431\u043e\u043a. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c\u00a0<em>logging.<\/em>\u00a0\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0444\u0430\u0439\u043b \u043b\u043e\u0433\u0430.<\/p>\n<pre><code>LOGGING_FORMAT = ('%(asctime)s %(levelname)s %(filename)s - '                   '%(funcName)s %(message)s') logging.basicConfig(filename=\"program_log.log\", filemode='a',                     level=logging.INFO, format=LOGGING_FORMAT)<\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u044b\u0439 \u043f\u0443\u0442\u044c, \u043b\u0438\u0431\u043e \u0444\u0430\u0439\u043b \u0441 \u043f\u0443\u0442\u044f\u043c\u0438. \u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0444\u0430\u0439\u043b \u044d\u0442\u043e \u0438\u043b\u0438 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043a\u043b\u0430\u0441\u0441\u00a0<em>Path<\/em>\u00a0\u043c\u043e\u0434\u0443\u043b\u044f\u00a0<em>pathlib.<\/em>\u00a0\u0412\u044b\u0431\u043e\u0440 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0434\u0432\u0443\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<pre><code>searching_path_obj = Path(search_path) if searching_path_obj.is_dir():     search_type = 'one' else:     search_type = searching_path_obj.suffix     search_type = search_type[1:]<\/code><\/pre>\n<p>\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0441 \u043f\u0443\u0442\u044f\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u043f\u0438\u0448\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c\u0438 \u0442\u0438\u043f \u0432\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0443\u0442\u0438 (\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c, \u0444\u0430\u0439\u043b \u0444\u043e\u0440\u043c\u0430\u0442\u0430 csv \u0438\u043b\u0438 json) \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u2013 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<pre><code>PATH_FILLER = {     'one': add_search_dict,     'json': add_search_from_json,     'csv': add_searches_from_csv }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439 \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u0438\u043c\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430, \u043f\u0443\u0442\u044c. \u0421\u043b\u043e\u0432\u0430\u0440\u0438 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0443\u0441\u043b\u043e\u0432\u0438\u0439.<br \/>\u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0438 \u043f\u0443\u0442\u044c \u043a \u0444\u0430\u0439\u043b\u0443 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<br \/>\u0422\u0430\u043a\u0436\u0435 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u2013 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0438\u0445 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 search_type:<\/p>\n<pre><code>SEARCH_TYPES = [\"one\", \"json\", \"csv\"]  if search_type not in SEARCH_TYPES:     types = \",\".join(SEARCH_TYPES)     message = (f\"\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f \u043f\u043e\u0438\u0441\u043a\u0430!\"                 f\" \u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432: {types}\")     print(message)     logging.error(message)     return<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e:<\/p>\n<pre><code># \u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 search_paths = []  # \u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 PATH_FILLER[search_type](search_paths, search_path)<\/code><\/pre>\n<p><strong>\u041c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0447\u0430\u0441\u0442\u044f\u043c\u0438<\/strong><\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0433\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438\u00a0<em>ThreadPoolExecutor\u00a0<\/em>\u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u00a0<em>tqdm<\/em>\u00a0(pip install tqdm).<\/p>\n<pre><code>futures = [] with ThreadPoolExecutor(max_workers=max_threads) as executor:     for proc_id, search_dict in enumerate(paths_list):         source = SearchSource(search_dict['name'],                               search_dict['id'],                               search_dict['path'])         futures.append(executor.submit(find_in_path,                                        source,                                        allowed_types,                                        max_filesize=max_filesize,                                        max_buffer_size=max_buffer_size,                                        continue_state=continue_state,                                        debug_mode=debug_mode))      progress_bar = tqdm(as_completed(futures),                         total=len(paths_list),                         desc=\"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0424\u0418\u0420\u043e\u0432\",                         bar_format='{desc:&lt;15} '                                    '{percentage:3.0f}%|{bar:20}{r_bar}')     for _ in progress_bar:         pass<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u0434\u0430\u0442\u0430\u0444\u0440\u0435\u0439\u043c \u043c\u043e\u0434\u0443\u043b\u044f\u00a0<em>pandas<\/em>\u00a0(pip install pandas). \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b, \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439 \u0435\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0439\u0434\u0451\u0442 \u043d\u0435 \u0442\u0430\u043a \u0438 \u0441\u043a\u0440\u0438\u043f\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u0443.<\/p>\n<pre><code>interim_result = [] common_uid = generate_uid() for result in files_gen:      current_num += 1     result.save_to_dataframe(interim_result, source_search.path)     total_fs_size += result.size     if current_num % batch_size == 0:         batch_num += 1         progress_state = batch_num * batch_size         info_message = (f\"\u041f\u043e\u0442\u043e\u043a {process_thread_id}.{subprocess_postfix} \"                         f\"\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e: {progress_state} \u0444\u0430\u0439\u043b\u043e\u0432.\")         print(info_message)      if current_num > 0 and current_num % FILES_IN_POOL == 0:         stat = SearchStat(current_num, total_fs_size)         search_result = pd.DataFrame(interim_result,                                      columns=REPORT_COLUMNS)          save_interim(search_result, source_search, stat,                      part_num, common_uid)         interim_result = []         part_num += 1  if interim_result:     stat = SearchStat(current_num, total_fs_size)     search_result = pd.DataFrame(interim_result,                                  columns=REPORT_COLUMNS)     save_interim(search_result, source_search, stat,                  part_num, common_uid) else:     uid = generate_uid()     save_dir_progress(source_search, SearchStat(0, 0),                       uid, \"\u041d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0430\")<\/code><\/pre>\n<p>\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0432 FILES_IN_POOL, \u0430 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0434\u043b\u044f \u043e\u0442\u0447\u0451\u0442\u0430 \u043e\u043f\u0438\u0448\u0435\u043c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 REPORT_COLUMNS (\u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0440\u043e\u043a).<\/p>\n<p><strong>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0430\u0440\u0445\u0438\u0432\u043e\u0432<\/strong><\/p>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e\u00a0<em>os.walk\u00a0<\/em>\u0434\u043b\u044f \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e\u0433\u043e \u043e\u0431\u0445\u043e\u0434\u0430 \u043f\u043e \u0444\u0430\u0439\u043b\u0430\u043c:<\/p>\n<pre><code>for root, dirs, files in os.walk(path):     for file in files:         file_path = os.path.join(root, file)         try:             file_obj = File(file_path,                             thread_id,                             None,                             max_buffer_size)             file_suffix = file_obj.extension         except Exception as ex:             error_message = (f\"{str(ex)}. \u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \"                              f\"\u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0430\u0439\u043b\u0443 {os.path.join(root, file)}\")             logging.error(error_message)             file_suffix = '!NONE!'          proc_res, res_info = file_obj.process(max_filesize)         result = SearchResult(file_obj.path, proc_res, res_info,                                   file_obj.size, file_suffix)         yield result<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e \u043d\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441:<\/p>\n<pre><code>class File:     \"\"\"     File class with file info.      Method file processing calling processing functions      for each filetype (document, pdf, xlxs, image)      \"\"\"     # \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0451\u043c \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e     PROCESSING_MAX_SIZE = 100       def __init__(self, file_path, process_thread_id=1,                  subprocess_id=None, buffer_size=314_572_800):         path_obj = Path(file_path)         self.name = path_obj.name         self.extension = path_obj.suffix         self.flat_name = path_obj.stem         self.parent_directory = str(path_obj.parent)         self.path = file_path         self.process_thread_id = process_thread_id         self.buffer_size = buffer_size         self.subprocess_id = subprocess_id         self.size = os.path.getsize(self.path)<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0444\u0430\u0439\u043b\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u00a0<em>process()<\/em>\u00a0\u043a\u043b\u0430\u0441\u0441\u0430\u00a0<em>File.<\/em><\/p>\n<pre><code>def process(self, limit_size: int = 100):     \"\"\"     Process file and starts search inside      :param limit_size: max file size in MB     :return:     \"\"\"     if limit_size is None:         limit_size = File.PROCESSING_MAX_SIZE     file_size_in_mb = self.size \/ (1024 * 1024)  # \u0440\u0430\u0437\u043c\u0435\u0440 \u0432 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430\u0445      if self.extension in CRITICAL_FILE_EXT:         return self.find_cards(critical=True)      if file_size_in_mb > limit_size:         return self.get_max_size_exceed()      if self.extension in USUAL_SUFFIXES:         return self.find_in_file()     elif self.extension in ARCHIVES_SUFFIXES:         result = self.find_in_zip()         remove_dir(self.form_tempdir_name(TEMP_ARCHIVES_PATH))         return result     elif self.extension in OLD_SUFFIXES:         temp_dir = self.form_tempdir_name(TEMP_PATH)         recreate_tempdir(temp_dir)         result = self.find_in_olddoc()         remove_dir(temp_dir)         return result      return self.get_unsupported_result()<\/code><\/pre>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0430\u0440\u0445\u0438\u0432\u043e\u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0438\u0445 \u043f\u0440\u0438\u0439\u0434\u0451\u0442\u0441\u044f \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438 \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043a\u0430\u043a \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u0440\u0445\u0438\u0432\u043e\u0432 \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 (\u0435\u0441\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438\u00a0<em>zip, tarfile\u00a0<\/em>\u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c), \u043d\u043e \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447, \u0432 \u043a\u0430\u043a\u0438\u0445 \u0446\u0435\u043b\u044f\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0441\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430\u00a0<em>rar<\/em>\u00a0\u0444\u043e\u0440\u043c\u0430\u0442\u0430. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044c\u00a0<em>patoolib\u00a0<\/em>(pip install patool).<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0430\u0440\u0445\u0438\u0432\u043e\u0432 \u0441\u0442\u043e\u0438\u0442 \u0443\u0447\u0435\u0441\u0442\u044c, \u0447\u0442\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433\u0438\u0435 \u0430\u0440\u0445\u0438\u0432\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0430\u0440\u0445\u0438\u0432\u044b \u0441\u0442\u043e\u0438\u0442 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e. \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u0440\u0445\u0438\u0432\u043e\u0432 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0438\u0436\u0435:<\/p>\n<pre><code>class Archive(File):     def __init__(self, path, temp_dir=None):         super().__init__(path, 1, subprocess_id=None,                          buffer_size=314_572_800)         self.temp_dir = TEMP_ARCHIVES_PATH if temp_dir is None else temp_dir      def extract(self, out_path: str = TEMP_PATH, recursive=True,                 changed_path=None, extract_level=1):         \"\"\"         Extracts all data from archive         :param extract_level: current extraction depth         :param recursive: True for recursive extract(by default)         :param out_path: Path to extract archive         :param changed_path: Path for second and more extract         :return:         \"\"\"         source_path = self.path if changed_path is None else changed_path         try:             patoolib.extract_archive(source_path, verbosity=-1,                                      outdir=out_path,                                      interactive=False)             if changed_path is not None:                 os.remove(source_path)         except Exception as ex:             logging.error(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0438 \u0430\u0440\u0445\u0438\u0432\u0430 {self.path}: {ex}\")             return         if recursive:             for root, dirs, files in os.walk(out_path):                 for file in files:                     pth = Path(root) \/ file                     suffix = pth.suffix                     if suffix in ARCHIVES_SUFFIXES:                         try:                             extract_dir = str(pth.parent)                             if extract_level > 999:                                 # \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e                                 # \u0430\u0440\u0445\u0438\u0432\u0430 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441                                 return                             self.extract(extract_dir, recursive=True,                                          changed_path=f\"{pth}\",                                          extract_level=extract_level + 1)                         except Exception as ex:                             logging.error(f\" \u041f\u0440\u043e\u0445\u043e\u0434 \u043f\u043e \u0430\u0440\u0445\u0438\u0432\u0443.\"                                           f\"\u0424\u0430\u0439\u043b {pth} \u041e\u0448\u0438\u0431\u043a\u0430 - {ex}\")<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0443\u0434\u043e\u0431\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441.<\/p>\n<pre><code>class SearchResult:     \"\"\"     Represents search results      Attributes:         result(bool) : True if success, else False         info(str):  additional string description         size(int): file size         ext(str): file extension     \"\"\"     def __init__(self, file_path: str, result: bool = None,                  info: str = None, size=0, ext=None):         \"\"\"          :param result: result : True if success, else False         :param info:  additional string description         :param size: file size         :param ext: file extension         \"\"\"         self.__result = result         self.__info = info         self.__size = size         self.__ext = ext         self.__path = file_path<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0444\u0430\u0439\u043b\u043e\u0432 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0414\u043b\u044f \u0438\u0445 \u0432\u044b\u0437\u043e\u0432\u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u044c.<\/p>\n<pre><code>process_functions = {     '.docx': docx2txt.process,     '.txt': process_txt,     '.xls': extract_text_xls,     '.xlsx': extract_text_xlsx,     '.xlsm': extract_text_xlsx,     '.xlsb': extract_text_xlsb,     '.rtf': extract_text_rtf,     '.csv': extract_csv,     '.pdf': extract_text_from_pdf, }  try:     text = process_functions[self.extension](self.path) except Exception as ex:     logging.error(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0444\u0430\u0439\u043b\u0430 {self.path}: {ex}\")<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Python, \u0442\u0430\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u2013 \u043c\u043e\u0434\u0443\u043b\u0438\u00a0<em>pandas<\/em>,\u00a0<em>pyexcel<\/em>,\u00a0<em>xlrd<\/em>\u00a0; \u0444\u0430\u0439\u043b\u043e\u0432 Word \u2013 \u043c\u043e\u0434\u0443\u043b\u0438\u00a0<em>docx2txt<\/em>,\u00a0<em>win32com<\/em>\/\u043f\u0430\u043a\u0435\u0442 LibreOffice; rtf \u2013\u043c\u043e\u0434\u0443\u043b\u044c\u00a0<em>striprtf<\/em><strong>;\u00a0<\/strong>pdf \u0444\u0430\u0439\u043b\u043e\u0432 \u2013 \u043c\u043e\u0434\u0443\u043b\u044c\u00a0<em>pdfminer<\/em>.<\/p>\n<p><strong>\u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443<\/strong><\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0435\u043c\u00a0<em>re.<\/em>\u00a0\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043a\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c, \u043a\u0430\u043a \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0438\u0445 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 SEARCH_REGEXPS.<\/p>\n<pre><code>def search_info(text):     \"\"\"     Search info     :param text: text in str format     :return: results count and info     \"\"\"     results = []     for pattern in SEARCH_REGEXPS:         finds = re.findall(pattern, text)         for res in finds:                        results.append(res)     return len(results), \",\".join(results)<\/code><\/pre>\n<p><strong>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432<\/strong><\/p>\n<p>\u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u044b \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435. \u0414\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<pre><code>RESULT_SAVERS = {     'sqlite': sqlite_save,     'mssql': mssql_save,     'csv': save_csv,     'excel': save_excel,     'xlsx': save_excel,  }   def process_results(result_type, output_tablename='results'):     \"\"\"     Unite all results from RESULTS_PATH directory      :param result_type: result format for save (sqlite, mssql, csv)     :param output_tablename: out table postfix for name     \"\"\"     result_dirs = load_setting(\"RESULT_DIRS\")     for result_dir in result_dirs:         print(f'\u0427\u0442\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 {result_dir}..')         # \u0418\u043c\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b\/\u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f         outname = f\"{output_tablename}-{result_dir}\"         path_to_process = Path(result_dir)         dataframes = []         result_paths = []         if path_to_process.exists():             result_paths = [p for p in path_to_process.iterdir()]         for path in tqdm(result_paths, desc=\"\u0427\u0442\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\",                          bar_format='{desc:&lt;15} {percentage:3.0f}%|'                                     '{bar:20}{r_bar}'):             try:                 if path.suffix == '.xlsx':                     dataframes.append(pd.read_excel(str(path),                                                     sheet_name=0))                 elif path.suffix == '.csv':                     dataframes.append(pd.read_csv(str(path),                                                   encoding='cp1251',                                                   sep=';'))             except Exception as ex:                 print(F\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0444\u0430\u0439\u043b\u0430 {path}. \u041e\u0448\u0438\u0431\u043a\u0430: {ex}\")          print('\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445...')         if dataframes:             result_frame = pd.concat(dataframes)             # \u0423\u0431\u0438\u0440\u0430\u0435\u043c \u043b\u0438\u0448\u043d\u0438\u0439 \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c\u0438 id             remove_first = load_setting(\"REMOVE_FIRST\")             if remove_first:                 result_frame.drop(result_frame.columns[[0]], axis=1,                                   inplace=True)             print('\u0417\u0430\u043f\u0438\u0441\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432..')             if result_type not in RESULT_SAVERS:                 print(f\"\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 {result_type}!!!\")             try:                 RESULT_SAVERS[result_type](outname, result_frame)             except Exception as ex:                 print(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432 {result_type}: {ex}\")             print('\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u043e\u0432 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e!')         else:             print('\u0414\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442!')<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438\u00a0<em>sqlalchemy, pymssql, pandas.\u00a0<\/em>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u044b. \u041a\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0411\u0414 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<pre><code>def get_connection_settings():     global DATABASE_NAME, DOMAIN, DB_SERVER     DATABASE_NAME = load_setting('DATABASE')     DOMAIN = load_setting('DOMAIN')     DB_SERVER = load_setting('DB_SERVER')   get_connection_settings()   def sqlite_save(table_name: str, data: pd.DataFrame):     \"\"\"     Saves pd dataframe in sqlite db      :param db_name: database name     :param table_name:  table name in database     :param data: dataFrame to save      \"\"\"     engine = create_engine(f'sqlite:\/\/\/{DATABASE_NAME}.db')     data.to_sql(f'{table_name}', con=engine, if_exists='append',                 method='multi')   def mssql_save(table_name: str, data: pd.DataFrame):     \"\"\"     Saves pd dataframe in sqlite db      :param table_name:  table name in database     :param data: dataFrame to save      \"\"\"     with pymssql.connect(server=DB_SERVER, database=DATABASE_NAME) as con:         engine = create_engine('mssql+pymssql:\/\/', creator=lambda: con)         data.to_sql(f'SearchDpk_{table_name}', con=engine,    if_exists='append',                     method='multi', chunksize=500)<\/code><\/pre>\n<p>\u0412\u043e\u0442 \u0442\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/22e\/7de\/cec\/22e7decec46b0278a52154dfa7b24aaa.png\" width=\"974\" height=\"266\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/22e\/7de\/cec\/22e7decec46b0278a52154dfa7b24aaa.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430\u0445.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/583344\/\"> https:\/\/habr.com\/ru\/articles\/583344\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.\u00a0 \u0427\u0442\u043e\u0431\u044b \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0443\u0434\u043e\u0431\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c. \u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 Python \u0435\u0441\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c click (\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 pip install click). \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u0432. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b: search_path \u2014 \u043f\u0443\u0442\u044c \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043a\u0430\u0442\u044c, \u043b\u0438\u0431\u043e \u0444\u0430\u0439\u043b \u0441 \u043f\u0443\u0442\u044f\u043c\u0438 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435: \u0440\u0435\u0436\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b (\u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u043b\u0438 \u0431\u0435\u0437), \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438, \u0444\u043e\u0440\u043c\u0430\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 (excel, csv, sqlite) \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u0436\u0435\u043b\u0430\u043d\u0438\u044e.<\/p>\n<pre><code>@click.command() @click.argument('search_path',                 type=click.Path(resolve_path=True,                                 dir_okay=True,                                 file_okay=True),                 required=True) @click.option('--concurrent_mode', '-cm',               type=click.STRING,               required=False,               default=\"None\",               help=\"Concurrent search execution(multi or single).\"                    \" Multi allows multiprocessing and threading\") @click.option('--output_path', '-o',               type=click.STRING,               required=False,               default='results',               help=\"Output filename(without extension)\") @click.option('--output_type', '-ot', '-out',               type=click.STRING,               required=False,               default='sqlite',               help=\"Format for output data((excel, csv, sqlite, mssql)\") ... def main(search_path, output_path, concurrent_mode, output_type):     \"\"\"     Starts search info(cards numbers) in files in path      search_path: path to search or json file with paths     \"\"\"     ...  if __name__ == \"__main__\":     main()<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0438\u0441\u043a\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u00a0<em>main().<\/em>\u00a0\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u0437\u043e\u0432 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>multi_mode = True if not concurrent_mode.lower() == \"single\" else False search_in_files(search_path, file_types, output_path, maxsize,                 buffer_size, clear_results, clear_log, continue_option,                 multi_mode, output_type, debug, include)<\/code><\/pre>\n<p>\u0421\u043e\u0432\u0435\u0440\u0448\u0438\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043e\u0448\u0438\u0431\u043e\u043a. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c\u00a0<em>logging.<\/em>\u00a0\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0444\u0430\u0439\u043b \u043b\u043e\u0433\u0430.<\/p>\n<pre><code>LOGGING_FORMAT = ('%(asctime)s %(levelname)s %(filename)s - '                   '%(funcName)s %(message)s') logging.basicConfig(filename=\"program_log.log\", filemode='a',                     level=logging.INFO, format=LOGGING_FORMAT)<\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u044b\u0439 \u043f\u0443\u0442\u044c, \u043b\u0438\u0431\u043e \u0444\u0430\u0439\u043b \u0441 \u043f\u0443\u0442\u044f\u043c\u0438. \u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0444\u0430\u0439\u043b \u044d\u0442\u043e \u0438\u043b\u0438 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043a\u043b\u0430\u0441\u0441\u00a0<em>Path<\/em>\u00a0\u043c\u043e\u0434\u0443\u043b\u044f\u00a0<em>pathlib.<\/em>\u00a0\u0412\u044b\u0431\u043e\u0440 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0434\u0432\u0443\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<pre><code>searching_path_obj = Path(search_path) if searching_path_obj.is_dir():     search_type = 'one' else:     search_type = searching_path_obj.suffix     search_type = search_type[1:]<\/code><\/pre>\n<p>\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0441 \u043f\u0443\u0442\u044f\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u043f\u0438\u0448\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c\u0438 \u0442\u0438\u043f \u0432\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0443\u0442\u0438 (\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c, \u0444\u0430\u0439\u043b \u0444\u043e\u0440\u043c\u0430\u0442\u0430 csv \u0438\u043b\u0438 json) \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u2013 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<pre><code>PATH_FILLER = {     'one': add_search_dict,     'json': add_search_from_json,     'csv': add_searches_from_csv }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439 \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u0438\u043c\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430, \u043f\u0443\u0442\u044c. \u0421\u043b\u043e\u0432\u0430\u0440\u0438 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0443\u0441\u043b\u043e\u0432\u0438\u0439.<br \/>\u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0438 \u043f\u0443\u0442\u044c \u043a \u0444\u0430\u0439\u043b\u0443 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<br \/>\u0422\u0430\u043a\u0436\u0435 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u2013 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0438\u0445 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 search_type:<\/p>\n<pre><code>SEARCH_TYPES = [\"one\", \"json\", \"csv\"]  if search_type not in SEARCH_TYPES:     types = \",\".join(SEARCH_TYPES)     message = (f\"\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f \u043f\u043e\u0438\u0441\u043a\u0430!\"                 f\" \u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432: {types}\")     print(message)     logging.error(message)     return<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e:<\/p>\n<pre><code># \u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 search_paths = []  # \u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 PATH_FILLER[search_type](search_paths, search_path)<\/code><\/pre>\n<p><strong>\u041c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0447\u0430\u0441\u0442\u044f\u043c\u0438<\/strong><\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0433\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438\u00a0<em>ThreadPoolExecutor\u00a0<\/em>\u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u00a0<em>tqdm<\/em>\u00a0(pip install tqdm).<\/p>\n<pre><code>futures = [] with ThreadPoolExecutor(max_workers=max_threads) as executor:     for proc_id, search_dict in enumerate(paths_list):         source = SearchSource(search_dict['name'],                               search_dict['id'],                               search_dict['path'])         futures.append(executor.submit(find_in_path,                                        source,                                        allowed_types,                                        max_filesize=max_filesize,                                        max_buffer_size=max_buffer_size,                                        continue_state=continue_state,                                        debug_mode=debug_mode))      progress_bar = tqdm(as_completed(futures),                         total=len(paths_list),                         desc=\"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0424\u0418\u0420\u043e\u0432\",                         bar_format='{desc:&lt;15} '                                    '{percentage:3.0f}%|{bar:20}{r_bar}')     for _ in progress_bar:         pass<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u0434\u0430\u0442\u0430\u0444\u0440\u0435\u0439\u043c \u043c\u043e\u0434\u0443\u043b\u044f\u00a0<em>pandas<\/em>\u00a0(pip install pandas). \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b, \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439 \u0435\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0439\u0434\u0451\u0442 \u043d\u0435 \u0442\u0430\u043a \u0438 \u0441\u043a\u0440\u0438\u043f\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u0443.<\/p>\n<pre><code>interim_result = [] common_uid = generate_uid() for result in files_gen:      current_num += 1     result.save_to_dataframe(interim_result, source_search.path)     total_fs_size += result.size     if current_num % batch_size == 0:         batch_num += 1         progress_state = batch_num * batch_size         info_message = (f\"\u041f\u043e\u0442\u043e\u043a {process_thread_id}.{subprocess_postfix} \"                         f\"\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e: {progress_state} \u0444\u0430\u0439\u043b\u043e\u0432.\")         print(info_message)      if current_num > 0 and current_num % FILES_IN_POOL == 0:         stat = SearchStat(current_num, total_fs_size)         search_result = pd.DataFrame(interim_result,                                      columns=REPORT_COLUMNS)          save_interim(search_result, source_search, stat,                      part_num, common_uid)         interim_result = []         part_num += 1  if interim_result:     stat = SearchStat(current_num, total_fs_size)     search_result = pd.DataFrame(interim_result,                                  columns=REPORT_COLUMNS)     save_interim(search_result, source_search, stat,                  part_num, common_uid) else:     uid = generate_uid()     save_dir_progress(source_search, SearchStat(0, 0),                       uid, \"\u041d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0430\")<\/code><\/pre>\n<p>\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0432 FILES_IN_POOL, \u0430 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0434\u043b\u044f \u043e\u0442\u0447\u0451\u0442\u0430 \u043e\u043f\u0438\u0448\u0435\u043c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 REPORT_COLUMNS (\u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0440\u043e\u043a).<\/p>\n<p><strong>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0430\u0440\u0445\u0438\u0432\u043e\u0432<\/strong><\/p>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e\u00a0<em>os.walk\u00a0<\/em>\u0434\u043b\u044f \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e\u0433\u043e \u043e\u0431\u0445\u043e\u0434\u0430 \u043f\u043e \u0444\u0430\u0439\u043b\u0430\u043c:<\/p>\n<pre><code>for root, dirs, files in os.walk(path):     for file in files:         file_path = os.path.join(root, file)         try:             file_obj = File(file_path,                             thread_id,                             None,                             max_buffer_size)             file_suffix = file_obj.extension         except Exception as ex:             error_message = (f\"{str(ex)}. \u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \"                              f\"\u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0430\u0439\u043b\u0443 {os.path.join(root, file)}\")             logging.error(error_message)             file_suffix = '!NONE!'          proc_res, res_info = file_obj.process(max_filesize)         result = SearchResult(file_obj.path, proc_res, res_info,                                   file_obj.size, file_suffix)         yield result<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e \u043d\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441:<\/p>\n<pre><code>class File:     \"\"\"     File class with file info.      Method file processing calling processing functions      for each filetype (document, pdf, xlxs, image)      \"\"\"     # \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0451\u043c \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e     PROCESSING_MAX_SIZE = 100       def __init__(self, file_path, process_thread_id=1,                  subprocess_id=None, buffer_size=314_572_800):         path_obj = Path(file_path)         self.name = path_obj.name         self.extension = path_obj.suffix         self.flat_name = path_obj.stem         self.parent_directory = str(path_obj.parent)         self.path = file_path         self.process_thread_id = process_thread_id         self.buffer_size = buffer_size         self.subprocess_id = subprocess_id         self.size = os.path.getsize(self.path)<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0444\u0430\u0439\u043b\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u00a0<em>process()<\/em>\u00a0\u043a\u043b\u0430\u0441\u0441\u0430\u00a0<em>File.<\/em><\/p>\n<pre><code>def process(self, limit_size: int = 100):     \"\"\"     Process file and starts search inside      :param limit_size: max file size in MB     :return:     \"\"\"     if limit_size is None:         limit_size = File.PROCESSING_MAX_SIZE     file_size_in_mb = self.size \/ (1024 * 1024)  # \u0440\u0430\u0437\u043c\u0435\u0440 \u0432 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430\u0445      if self.extension in CRITICAL_FILE_EXT:         return self.find_cards(critical=True)      if file_size_in_mb > limit_size:         return self.get_max_size_exceed()      if self.extension in USUAL_SUFFIXES:         return self.find_in_file()     elif self.extension in ARCHIVES_SUFFIXES:         result = self.find_in_zip()         remove_dir(self.form_tempdir_name(TEMP_ARCHIVES_PATH))         return result     elif self.extension in OLD_SUFFIXES:         temp_dir =<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-381912","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/381912","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=381912"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/381912\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=381912"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=381912"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=381912"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}