Это немного сложнее, чем вы можете себе представить, и вам действительно нужна веская причина, чтобы пройти через все трудности, чтобы оправдать это. Прежде всего, пользовательский интерфейс диспетчера задач не получает информацию от tasklist.exe
, хотя вы можете получить довольно близкие результаты:
import csv
import subprocess
try:
tl_out = subprocess.check_output(["tasklist", "/fo", "csv", "/v"])
except subprocess.CalledProcessError as e:
print("Call to `tasklist` failed: {}".format(e))
exit(1)
tl_csv = csv.DictReader(tl_out.splitlines())
for row in tl_csv:
print(row) # prints a dict for each task with all available fields
# Available fields (may vary from platform to platform) are:
# 'Status', 'CPU Time', 'Image Name', 'Session Name', 'Window Title',
# 'PID', 'User Name', 'Session#', 'Mem Usage'
Однако, чтобы получить доступ к полю Description
(и многим другим из пользовательского интерфейса диспетчера задач), вам придется как минимум извлечь данные из WMI. Что еще хуже, WMIC
на В Windows 7 есть ошибка при экспорте в CSV, что еще больше усложняет все это, так как для максимальной переносимости нам нужно использовать формат list
и анализировать это сами:
import subprocess
try:
wmi_out = subprocess.check_output(["wmic", "process", "list", "full", "/format:list"])
except subprocess.CalledProcessError as e:
print("Call to `wmic` failed: {}".format(e))
exit(1)
# parse the WMI list:
wmi_entries = []
for task in wmi_out.strip().split("\r\r\n\r\r\n"):
wmi_entries.append(dict(e.split("=", 1) for e in task.strip().split("\r\r\n")))
for row in wmi_entries:
print(row) # prints a dict for each task with all available fields
# Available fields (may vary from platform to platform) are:
# 'CSName', 'CommandLine', 'Description', 'ExecutablePath', 'ExecutionState', 'Handle',
# 'HandleCount', 'InstallDate', 'KernelModeTime', 'MaximumWorkingSetSize',
# 'MinimumWorkingSetSize', 'Name', 'OSName', 'OtherOperationCount', 'OtherTransferCount',
# 'PageFaults', 'PageFileUsage', 'ParentProcessId', 'PeakPageFileUsage',
# 'PeakVirtualSize', 'PeakWorkingSetSize', 'Priority', 'PrivatePageCount', 'ProcessId',
# 'QuotaNonPagedPoolUsage', 'QuotaPagedPoolUsage', 'QuotaPeakNonPagedPoolUsage',
# 'QuotaPeakPagedPoolUsage', 'ReadOperationCount', 'ReadTransferCount', 'SessionId',
# 'Status', 'TerminationDate', 'ThreadCount', 'UserModeTime', 'VirtualSize',
# 'WindowsVersion', 'WorkingSetSize', 'WriteOperationCount', 'WriteTransferCount'
Обновление кода для Python3 (используйте кодировку для поиска по байтам):
s1 = "\r\r\n\r\r\n".encode()
s2 = "\r\r\n".encode()
for task in wmi_out.strip().split(s1):
wmi_entries.append(dict(e.split("=".encode(), 1) for e in task.strip().split(s2)))
Если вам не нужны все эти поля, вы всегда можете ограничить wmic
, чтобы получить нужные вам поля (например, wmi_out = subprocess.check_output(["wmic", "process", "get", "ProcessId,ExecutablePath,Description", "/format:list"])
, чтобы получить только Description
на ProcessId
).
Но не думайте, что ваши проблемы закончились - мы только начали. Хотя теперь у нас есть поле Description
(и несколько других для загрузки), вы заметите, что для процессов, которые не объявляют свое описание (большинство из них, очевидно, программисты Windows ленивы) или служб без описания - значение описания просто содержит имя исполняемого файла, то есть если вы используете старый добрый Блокнот, в то время как пользовательский интерфейс диспетчера задач покажет вам Notepad
в качестве описания, его запись в словаре будет иметь notepad.exe
- это потому, что пользовательский интерфейс диспетчера задач использует совершенно другой подход к списку задач и получает описание непосредственно из исполняемого файла процесса.
Таким образом, вам действительно нужен дополнительный шаг, чтобы получить описание исполняемого файла непосредственно из его таблицы ресурсов, что, вероятно, «самое простое» сделать, вызвав Win32 API, чтобы получить описание, поэтому вам нужно установить pyWin32 сначала:
import subprocess
import win32api
# gets executable description via W32API
def get_executable_desc(path, default=''):
try:
language, codepage = win32api.GetFileVersionInfo(path, "\\VarFileInfo\\Translation")[0]
return win32api.GetFileVersionInfo(path, "\\StringFileInfo\\{:04x}{:04x}\\FileDescription".format(language, codepage)) or default
except:
return default
try:
wmi_out = subprocess.check_output(["wmic", "process", "list", "full", "/format:list"])
except subprocess.CalledProcessError as e:
print("Call to `tasklist` failed: {}".format(e))
exit(1)
# parse the WMI list:
wmi_entries = []
for task in wmi_out.strip().split("\r\r\n\r\r\n"):
entry = dict(e.split("=", 1) for e in task.strip().split("\r\r\n"))
entry['Description'] = get_executable_desc(entry.get("ExecutablePath", None), entry.get("Description", None))
wmi_entries.append(entry)
for row in wmi_entries:
print(row) # prints a dict for each task with all available fields
Вуаля! Описания теперь заполняются (там, где они доступны, или, по крайней мере, содержат имя исполняемого файла), но, поскольку нам пришлось использовать Win32 API для доступа к описаниям, мы могли бы также получить список задач через него. - это быстрее и лаконичнее:
from win32api import GetFileVersionInfo, OpenProcess
from win32con import PROCESS_QUERY_INFORMATION, PROCESS_VM_READ
from win32process import EnumProcesses, EnumProcessModules, GetModuleFileNameEx
import pywintypes
# gets executable description via W32API
def get_executable_desc(path, default=''):
try:
language, codepage = GetFileVersionInfo(path, "\\VarFileInfo\\Translation")[0]
return GetFileVersionInfo(path, "\\StringFileInfo\\{:04x}{:04x}\\FileDescription".format(language, codepage)) or default
except:
return default
# gets the process list via W32API
def get_process_list():
proc_list = []
processes = EnumProcesses()
if not processes:
return [] # optionally raise an exception, no ProcessIds could be obtained
for proc in processes:
try:
handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, pywintypes.FALSE, proc)
modules = EnumProcessModules(handle)
if not modules:
continue # task died in the meantime?
path = GetModuleFileNameEx(handle, modules[0])
proc_list.append({"ProcessId": proc, "ExecutablePath": path, "Description": get_executable_desc(path, path)})
except pywintypes.error as e:
continue # optionally report the error stored in `e`
return proc_list
tasks = get_process_list()
for row in tasks:
print(row) # prints a dict for each task with ProcessId, ExecutablePath and Description fields
Это позволит получить только ProcessId, ExecutablePath и Description, но вы можете дополнительно изучить Win32 API, если вам нужно больше полей.
Опять же, я не понимаю, какое значение имеет поле Description
, чтобы пройти через все эти проблемы, но если вы действительно, очень хотите - вот как его получить.
person
zwer
schedule
18.05.2017