2017-04-05 129 views
-1

我想通過我的Python程序來篩選屏幕打印。如何過濾Python屏幕打印?

理想情況下,最好指定一個「打印黑名單」,比如這個。

*FutureWarning* 
INFO* 

當部分屏幕打印輸出符合上述圖案之一時,整個打印輸出將被濾除。

我很驚訝沒有人還沒有問這個問題,因爲我認爲這是非常有用的,因爲沒有它,我需要通過不同類型的屏幕打印輸出並相應地處理它們。你可以想象其中一些可能是由於print,部分原因是由於warning等造成的。

我從bash運行我的Python腳本,因此也歡迎使用基於bash的方法!

+1

「screen print」是什麼意思?您的描述似乎涉及通過各種渠道打印到共生輸出設備(通常是命令窗口)的消息,但術語不匹配。你的半個例子沒有給出足夠的細節以確定,問題的形式與SO的特異性標準並不相符。 – Prune

+0

我想也許他正在尋找'grep -v -E「(列表|黑名單|字詞列表)」' – mbarkhau

回答

1

我想通過我的Python程序過濾屏幕打印。

您可以使用Python的logging模塊,路由所有打印和警告輸出通過它:

# in your main module 
import logging 

# -- log all output to myapp.log 
logging.basicConfig(filename='myapp.log', level=logging.DEBUG) 
# -- OR log all output to console 
logging.basicConfig(level=logging.DEBUG) 
# route all output to logging 
logging.captureWarnings(True) 
print = logging.info 

有了這個添加自己的Filter過濾所有輸出按照需要的關鍵字:

# define Filter in its own module, say logfilter.py 
class OutputFilter(logging.Filter): 
    def __init__(self, keywords, name=None): 
     super(OutputFilter, self).__init__(name) 
     self.keywords = keywords 

    def filter(self, record): 
     msg = record.getMessage() 
     return not any(k in msg for k in self.keywords) 

# add this in your main module 
from logfilter import OutputFilter 
flt = OutputFilter(['*FutureWarning*', 'INFO*']) 
logger = logging.getLogger() # root logger 
logger.addFilter(flt) 
warnLogger = logging.getLogger('py.warnings') # warnings logger 
warnLogger.addFilter(flt) 

(...)沒有它,我需要通過不同類型的屏幕打印輸出並相應地處理它們。

如果你可以改變的源代碼,最好是經常使用的模塊記錄,而不是打印:

# in any module with output, right after imports 
logger = logging.getLogger(__name__) 
... 
# instead of print 
logger.info(...) 
logger.error(...) 
logger.debug(...) 

的優點是logging允許你在什麼輸出並在很精細的控制,同時從中心位置配置所有內容。例如,雖然上面使用適用於所有日誌記錄輸出的根日誌記錄器,但應用程序的每個模塊都可以擁有自己的記錄器,並具有其特定配置,例如,

# somewhere in your main module 
# -- basic config is to console 
logging.basicConfig(level=logging.DEBUG) 
# -- module A output should go into its own file 
logger = logging.getLogger('path.to.module.A') 
handler = logging.FileHandler(filename='myapp-A.log') # see above 
logger.setHandler(handler) 
logger.setLevel(logging.INFO) 

# path/to/module/A.py 
# -- right at the top of the module 
import logging 
logger = logging.getLogger(__name__) 
... 
# in the actual code 
logger.info('info message') 

此示例將路由通過模塊A中的所有信息消息到文件myapp-A.log而所有其它輸出變爲到終端。

注意:所有示例均從Python Logging Cookbook採用。請查看tutorial以獲得更深入的解釋。

1

您可以將print變量綁定到您的自定義函數,以檢查您不想查看的任何輸出。

下面是一個例子:

>>> def print(*args, **kwargs): 
...  import builtins 
...  if not any(str(s).startswith('INFO') for s in args): 
...    builtins.print(*args, **kwargs) 
+0

謝謝!但是如果除了'print'之外還有其他的命令可以打印出來呢? –

+2

@SibbsGambling你可以看看用'io.TextIOWrapper'子類的自定義對象代替'sys.stdout',但我不推薦它。查看其他答案。 – Rishav

1

你說你願意做的bash。你可以寫另一個腳本,說filter.py

from sys import stdin 

def print_filtered(line): 
    if line.startswith("print this"): 
     print(line, end='') # The line includes its own newline character 

for line in stdin: 
    print_filtered(line) 

當然,你可以把你在print_filtered()想要的任何過濾選項。你甚至可以做一些替換;也許你想在打印之前刪除字符串的print this部分。

現在,你想要的任何程序已濾波輸出,你可以像這樣運行:

$ python myfile.py | python filter.py 

Rishav在他的評論中也提到,你可以用自定義對象替換sys.stdout。我真的不喜歡這個想法,但你能做到這一點的東西是這樣的:

import sys 

class FilteredPrinter(object): 
    def __init__(self, filtered_print, stdout): 
     self._filtered_print = filtered_print 
     self._stdout = stdout 

    def _write(self, string): 
     self._filtered_print(string, self._stdout) 

    def __getattr__(self, attr): 
     if attr == 'write': 
      return self._write 
     return getattr(self._stdout, attr) 


def filtered_print(string, stdout): 
    if string == "\n" or string.startswith("print this"): 
     stdout.write(string) 

sys.stdout = FilteredPrinter(filtered_print, sys.stdout) 
print("print this: my text") 
print("print this text") 
print("Don't print this") 

有了這個解決方案,您可以指定任何你想要的過濾器;你也可以用sys.stderr來做到這一點。如果你想回到老,請使用sys.stdout = sys.stdout._stdout。請注意,print函數調用sys.stdout.write()每個參數一次,並再次爲換行符。也就是說,調用print("first", "second")會做到這一點:

sys.stdout.write("first") 
sys.stdout.write(" ") 
sys.stdout.write("second") 
sys.stdout.write("\n") 

所以只要確保你寫過濾功能時,記住這一點。

+0

+1謝謝!但不會'python myfile.py | python filter.py' make'filter.py'在'myfile.py'完成後運行?那時候,屏幕上已經有東西了?就我而言,'myfile.py'是一個長時間運行的腳本,可以不斷在屏幕上進行打印。 –

+0

@sibbs:輸出是管道輸出,因此絕對不會打印,除非myfilter.py打印它。我很確定myfilter.py能夠實時處理它,但是你可以運行測試。 – zondo

+0

嗯,是因爲我'cmd =「python myfile.py | python filter.py」; eval $ {cmd}'?它不會實時停止打印。 –