Opening links in txt file in headless browser in python - python

I have been having a problem running the code below and suspect the problem is with link.strip(). The program is running in a linux environment and it is supposed to open multiple links contained in a text files and opens them for snort to scan for malware. The file name is defined in the terminal before the code is executed.
import os
import subprocess
import time
import argparse
def read_links_from_file(file_path):
links = []
with open(file_path, 'r') as file:
for line in file:
links.append(line.strip())
return links
def open_links_in_chrome(links, headless=True):
options = '--headless' if headless else ''
for link in links:
subprocess.call('google-chrome {options} --app={link}', shell=True)
time.sleep(1)
def run_snort(interface):
subprocess.call(f'snort -i {interface}', shell=True)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--file', help='Path to file containing links', required=True)
parser.add_argument('--interface', help='Network interface for Snort to listen on', required=True)
parser.add_argument('--headless', help='Run Chrome in headless mode', action='store_true')
args = parser.parse_args()
file_path = args.file
interface = args.interface
headless = args.headless
links = read_links_from_file(file_path)
snort_process = subprocess.Popen(['snort', '-i', interface])
open_links_in_chrome(links, headless)
snort_process.terminate()
if __name__ == '__main__':
main()
I tried reconfiguring the applications and rewrote the code but I'm not sure if I preserved the right code but
links.append(line.strip())
doesn't seem to be the right way to go. I have also changed the sleep time from 5 to 1
After some tinkering I ended up with the following error
Acquiring network traffic from "eth0". ERROR: Can't start DAQ (-1) - socket: Operation not permitted! Fatal Error, Quitting.. libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name
= (null) [121024:121024:0217/122814.243731:ERROR:gpu_memory_buffer_support_x11.cc(49)] dri3 extension not supported. [121070:8:0217/122815.025776:ERROR:command_buffer_proxy_impl.cc(128)] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer. Fontconfig error: Cannot load default config file: No such file: (null)

I have been having a problem running the code below and suspect the problem is with link.strip().
I assume you mean line.strip() (you're not calling link.strip() anywhere in your code). If you think the code is problematic, let's test it. If I have a file that contains a list of four URLs in file urls.txt:
https://google.com
https://stackoverflow.com
https://www.npr.org/programs/wait-wait-dont-tell-me/
https://www.nyan.cat/
And then run the following code:
import sys
def read_links_from_file(file_path):
links = []
with open(file_path, 'r') as file:
for line in file:
links.append(line.strip())
return links
links = read_links_from_file('urls.txt')
for i, link in enumerate(links):
print(f'{i}: {link}')
I get the following output:
0: https://google.com
1: https://stackoverflow.com
2: https://www.npr.org/programs/wait-wait-dont-tell-me/
3: https://www.nyan.cat/
That suggest your read_links_from_file function works as expected.
On the other hand, you're doing more work than is necessary. The default behavior of a Python file object is to act as an iterator over the lines in the file, so instead of writing this:
def read_links_from_file(file_path):
links = []
with open(file_path, 'r') as file:
for line in file:
links.append(line.strip())
return links
links = read_links_from_file(args.file)
open_links_in_chrome(links, args.headless)
You can just delete the read_links_from_file functions and pass the open file:
with open(args.file) as links:
open_links_in_chome((line.strip() for line in links), args.headless)
I'm cheating a bit here because in stead of simply iterating over the file I'm using a generator expression to take care of stripping the end-of-line character.
You have an error in your open_links_in_chrome function. You have written:
subprocess.call('google-chrome {options} --app={link}', shell=True)
This will result in running the literal command line...
chrome {options} --app={link}
...because you are neither using a Python f-string nor are you calling the .format() method. You need to write the function like this in order to run Chrome as expected:
def open_links_in_chrome(links, headless=True):
options = '--headless' if headless else ''
for link in links:
subprocess.call(f'google-chrome {options} --app={link}', shell=True)
time.sleep(1)
This introduces a new problem: this will successfully open Chrome with the first URL, but Chrome will never exit, so your code won't continue past this point.
Rather than trying to fix this, I would suggest using a browser automation library like Playwright or Selenium. Here's your code rewritten to use Playwright:
import playwright
from playwright.sync_api import sync_playwright
import subprocess
import time
import argparse
import signal
def open_links_in_chrome(links, headless=True):
with sync_playwright() as p:
browser = p.chromium.launch(headless=headless)
page = browser.new_page()
for link in links:
print(f'fetching {link}')
try:
page.goto(link)
except playwright._impl._api_types.TimeoutError:
print(f'{link} timed out.')
time.sleep(1)
browser.close()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--file', help='Path to file containing links', required=True)
parser.add_argument('--interface', help='Network interface for Snort to listen on', required=True)
parser.add_argument('--headless', help='Run Chrome in headless mode', action='store_true')
args = parser.parse_args()
snort_process = subprocess.Popen(['snort', '-i', args.interface])
with open(args.file) as links:
open_links_in_chrome((line.strip() for line in links), headless=args.headless)
snort_process.terminate()
if __name__ == '__main__':
main()
If we run this -- assuming we have followed the Playwright installation instructions -- we see as output:
fetching https://google.com
fetching https://stackoverflow.com
fetching https://www.npr.org/programs/wait-wait-dont-tell-me/
fetching https://www.nyan.cat/
In my tests I've replaced snort with tcpdump, and examining the resulting packet capture I can see that we're making the expected network requests:
$ tcpdump -r packets port 53 | grep -E 'A\? (google.com|stackoverflow.com|www.npr.org|www.nyan.cat)'
reading from file packets, link-type EN10MB (Ethernet), snapshot length 262144
20:23:37.319272 IP madhatter.52135 > _gateway.domain: 52609+ A? stackoverflow.com. (35)
20:23:38.811385 IP madhatter.39144 > _gateway.domain: 15910+ AAAA? www.npr.org. (29)
20:23:38.811423 IP madhatter.52655 > _gateway.domain: 13756+ A? www.npr.org. (29)
20:23:41.214261 IP madhatter.46762 > _gateway.domain: 20587+ AAAA? www.nyan.cat. (30)
20:23:41.214286 IP madhatter.43846 > _gateway.domain: 12335+ A? www.nyan.cat. (30)

Related

Record Error from CMD in output with Python

I am trying to run the below code - and what it does is run the commands in a file line by line and extract the results from the cmd into a new file. the command looks something like this 'ping (host name)' with many hosts and a line for each host.
some hosts fail in the cmd, as in it cannot find a response - usually when that happens the code breaks, so that is why I have the try and except below. but I am struggling to make the except section record the failed items in the same document (if possible).
so for example if ping (host name3) failed - I want it to record that message and store in the file.
If you have a better way of doing all of this please let me know!
command_path = pathlib.Path(r"path to the file with commands")
command_file = command_path.joinpath('command file.txt')
commands = command_file.read_text().splitlines()
#print(commands)
try:
for command in commands:
#Args = command.split()
#print(f"/Running: {Args[0]}")
outputfile = subprocess.check_output(command)
print(outputfile.decode("utf-8"))
results_path = command_path.joinpath(f"Passed_Results.txt")
results = open(results_path, "a")
results.write('\n' + outputfile.decode("utf-8"))
results.close()
except:
#this is where I need help.
I got a response on a different question that I was able to augment into this. I essentially broke my entire code down and rewrote as follows. this worked for me, However if you are able to provide insight on a faster processing time for this. PLEASE LET ME KNOW
cmds_file = pathlib.Path(r"C:\Users'path to file here').joinpath("Newfile.txt")
output_file = pathlib.Path(r"C:\Users'path to file
here').joinpath("All_Results.txt")
with open(cmds_file, encoding="utf-8") as commands, open(output_file, "w",
encoding="utf-8") as output:
for command in commands:
command = shlex.split(command)
output.write(f"\n# {shlex.join(command)}\n")
output.flush()
subprocess.run(command, stdout=output, encoding="utf-8")

nagios core external agent using python scripting

I have a bash script for performing the passive checks i.e., external agent/application. I tried converting the bash script into python but when I execute the file I don't see any kind of responses on my nagios core interface regarding my passive check result.
import os
import datetime
CommandFile='/usr/local/nagios/var/rw/nagios.cmd'
datetime = datetime.datetime.now()
os.stat(CommandFile)
f = open(CommandFile, 'w')
f.write("/bin/echo " + str(datetime) + " PROCESS_SERVICE_CHECK_RESULT;compute-1;python dummy;0;I am dummy python")
f.close()
my bash script code is:
#!/bin/sh
# Write a command to the Nagios command file to cause
# it to process a service check result
echocmd="/bin/echo"
CommandFile="/usr/local/nagios/var/rw/nagios.cmd"
# get the current date/time in seconds since UNIX epoch
datetime=`date +%s`
# create the command line to add to the command file
cmdline="[$datetime] PROCESS_SERVICE_CHECK_RESULT;host-name;dummy bash;0;I am dummy bash"
# append the command to the end of the command file
`$echocmd $cmdline >> $CommandFile`
Changed my code, now its working perfectly fine. I can see the response in the Nagios interface.
import time
import sys
HOSTNAME = "compute-1"
service = "python dummy"
return_code = "0"
text = "python dummy is working .....I am python dummy"
timestamp = int(time.time())
nagios_cmd = open("/usr/local/nagios/var/rw/nagios.cmd", "w")
nagios_cmd.write("[{timestamp}] PROCESS_SERVICE_CHECK_RESULT;{hostname};{service};{return_code};{text}\n".format
(timestamp = timestamp,
hostname = HOSTNAME,
service = service,
return_code = return_code,
text = text))
nagios_cmd.close()

How to write/append PING results to output file

Fairly new to Python so forgive the basic question and my repetitive coding. I'm trying to write a script that PINGs a network segment then writes the results to a couple of TXT files.
I have the PING scan part working just fine with some code I found online, just cant get the results to save in the files. The files get created but they are blank.
Can someone check this out and give me some recommendations?
import os
import os.path
import sys
import subprocess
import ipaddress
# Prompt the user to input a network address
network = input("Enter a network address in CIDR format(ex.192.168.1.0/24): ")
# Create the network
ip_net = ipaddress.ip_network(network)
# Get all hosts on that network
all_hosts = list(ip_net.hosts())
# Create output file in preset directory
os.chdir("C:\\Python364\\Output")
onlineHosts = "Online_Hosts.txt"
offlineHosts = "Offline_Hosts.txt"
on = open(onlineHosts, 'a') # File object 'on' is created with append mode
off = open(offlineHosts, 'a') # File object 'off' is created with append mode
# Configure subprocess to hide the console window
info = subprocess.STARTUPINFO()
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
info.wShowWindow = subprocess.SW_HIDE
# For each IP address in the subnet,
# run the ping command with subprocess.popen interface
for i in range(len(all_hosts)):
output = subprocess.Popen(['ping', '-n', '1', '-w', '500', str(all_hosts[i])], stdout=subprocess.PIPE, startupinfo=info).communicate()[0]
if "Destination host unreachable" in output.decode('utf-8'):
print(str(all_hosts[i]), "is Offline")
result = str(all_hosts[i])
off.write(result)
elif "Request timed out" in output.decode('utf-8'):
print(str(all_hosts[i]), "is Offline")
result = str(all_hosts[i])
off.write(result)
else:
print(str(all_hosts[i]), "is Online")
result = str(all_hosts[i])
on.write(result
Make sure to close the files when finished with them. The writing may stay in the buffer until you do.
on.close()
off.close()
To write immediately without closing, you can flush the buffers:
on.flush()
off.flush()
If one only want to use the shell, I found the following to be helpful for this problem: https://ss64.com/nt/type.html
To write the ping results to the output file, type:
ping -t "SomeIPAddress" > newfile.txt
To append ping results to the existing output file, type:
ping -t "some IP address" >> existingfile.txt
If you also want to add a timestamp on the ping results, then you can type the following in the Powershell:
ping -t "SomeIPAddress"|Foreach{"{0} - {1}" -f (Get-Date),$_} > > newfile.txt
Source: https://support.solarwinds.com/SuccessCenter/s/article/Ping-Test-and-save-to-text-file?language=en_US

Python silent print PDF to specific printer

I have a PDF document and I want to print it with my python app.
I have tried the solution in here (Print PDF document with python's win32print module?) but when I install Ghostscript 9.15 that is the actual version, it has no gsprint.exe
The way I am using that works is with the command os.startfile('PDFfile.pdf', "print") but it opens default viewer (mine is Adobe Reader) and after printing it stills open, trying to kill the process with os.system("TASKKILL /F /IM AcroRD32.exe") kills other opened windows and I dont want it.
With the next command, it also prints, but it let the Adobe Reader opened too
currentprinter = win32print.GetDefaultPrinter()
win32api.ShellExecute(0, "print", 'PDFfile.pdf', '/d:"%s"' % currentprinter, ".", 0)
I have seen this answer too but they recommend using gsprint.exe again
Anybody has the gsprint.exe file or any other solution?.
NOTE: When I used another default program to open PDF files like Chrome or Windows Reader, I always get an Exception in the execution of the commands above '(31, 'ShellExecute', 'A device attached to the system is not functioning.')' or [Error 1155] No application is associated with the specified file for this operation: 'PDFfile.pdf' with the startfile command
Finally after hours and hours of searching for the right files, i have found the answer to my problem.
You can download the GSPRINT in HERE
You can download the Ghostscript GPL in HERE
With this extracted files in your PC (Windows) you can print your PDF with this command
GHOSTSCRIPT_PATH = "C:\\path\\to\\GHOSTSCRIPT\\bin\\gswin32.exe"
GSPRINT_PATH = "C:\\path\\to\\GSPRINT\\gsprint.exe"
# YOU CAN PUT HERE THE NAME OF YOUR SPECIFIC PRINTER INSTEAD OF DEFAULT
currentprinter = win32print.GetDefaultPrinter()
win32api.ShellExecute(0, 'open', GSPRINT_PATH, '-ghostscript "'+GHOSTSCRIPT_PATH+'" -printer "'+currentprinter+'" "PDFFile.pdf"', '.', 0)
The GhostScript can also be found in the Official page HERE
I found the gsprint.exe for 64bits HERE
I hope this helps.
I know this is an old question, but in case someone is looking for it here is how I fixed it.
I am using python 3.8 and gs9.52 on windows 10 64-bit and python3-ghostscript library which you can install using pip install python3-ghostscript I am also using pypiwin32 to get the default printer name, you can install it with pip pip install pypiwin32
This is the working script
import tempfile
import win32print
import locale
import ghostscript
import render_to_pdf
pdf = render_to_pdf('print/slip.html', context)
temp1 = tempfile.mktemp('.pdf')
f1 = open(temp1, 'ab')
f1.write(pdf)
f1.close()
args = [
"-dPrinted", "-dBATCH", "-dNOSAFER", "-dNOPAUSE", "-dNOPROMPT"
"-q",
"-dNumCopies#1",
"-sDEVICE#mswinpr2",
f'-sOutputFile#"%printer%{win32print.GetDefaultPrinter()}"',
f'"{temp1}"'
]
encoding = locale.getpreferredencoding()
args = [a.encode(encoding) for a in args]
ghostscript.Ghostscript(*args)
Few things to note here I am using '#' instead of '=' because for some reason it was not working with '='.
If this is not working for you try changing -sDEVICE switch to your printer type for example when I was using HP LaserJet it was giving me prompt so I changed my -sDEVICE to laserjet and it worked, you can get the list of device by running gs -h in terminal
Here's a way to silently print a pdf in the same directory as your python script without gsprint and without win32api. It allows for more GhostScript customization like choosing width/height, etc.
import os
import subprocess
import sys
if sys.platform == 'win32':
args = '"C:\\\\Program Files\\\\gs\\\\gs9.23\\\\bin\\\\gswin64c" ' \
'-sDEVICE=mswinpr2 ' \
'-dBATCH ' \
'-dNOPAUSE ' \
'-dFitPage ' \
'-sOutputFile="%printer%myPrinterName" '
ghostscript = args + os.path.join(os.getcwd(), 'myFile.pdf').replace('\\', '\\\\')
subprocess.call(ghostscript, shell=True)
If you're using the 32 bit version of GhostScript then you would use gswin32c
If you want to print specific pages and some other parameters, you should specify them in the parameters of gsprint as follows:
import win32print
import win32api
GHOSTSCRIPT_PATH = "C:\\path\\to\\GHOSTSCRIPT\\bin\\gswin32.exe"
GSPRINT_PATH = "C:\\path\\to\\GSPRINT\\gsprint.exe"
params = '-ghostscript "'+ GHOSTSCRIPT_PATH +'" -printer "'+currentprinter+'" -from 1 -to 3 -landscape -copies 1 "1.pdf "'
print(params)
win32api.ShellExecute(0, 'open', GSPRINT_PATH, params, '.',0)
The following code will block the current task
for i in range(10):
currentprinter = win32print.GetDefaultPrinter()
win32api.ShellExecute(0, "print", 'PDFfile.pdf', '/d:"%s"' % currentprinter, ".", 0)
and killing the reader after printing help won't block the current task
os.system("TASKKILL /F /IM AcroRD32.exe")
but it will close other pdf files too.
If you can't use gsprint, use the acrobat command
import win32print
import subprocess
import time
pdf_file = 'D:\d1\d1.pdf'
acrobat = 'C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe'
name = win32print.GetDefaultPrinter()
cmd = '"{}" /n /o /t "{}" "{}"'.format(acrobat, pdf_file, name)
for i in range(10)):
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
It won't block the current task and close the other pdf files.
Based on previous answers and other posts, i develop the following script to print .pdf and .ps from a Laravel website.
I used python 3.9 and Ghostscript 9.54 (for 64bits). pywin32 and python3-ghostscript libs are requiered too.
import os
import sys
import win32print
import win32api
import ghostscript
import locale
USELESS_PRINTER = ['OneNote for Windows 10', 'OneNote (Desktop)', 'Microsoft XPS Document Writer',
'Microsoft Print to PDF', 'Fax']
HELP = """pyPrinter - Author: Arthur SICARD - Date: 19/05/2021
\n-help
\tDisplay this message.
\n-list [-virtual]
\tReturn list of available printer (excepted: """ + ", ".join(USELESS_PRINTER) + """)
\n-file filepath [-printer printer_name] [-virtual]
\tPrint specified file on default system printer. Use -printer to specify printer to use. Printer name must be available un -list response.
\n-batch filepath [-printer printer_name] [-virtual]
\tPrint each document specified un batch file on default system printer. Batch file must be a .txt. Each file to print must be write on its own line.
\tUse -printer to specify printer to use. Printer name must be available un -list response.
\n-virtual
\tUse this option after all other arguments to enable printing on virtual printer 'Microsoft Print to PDF'
"""
# Safe accessor to argv. Return None if index is not set
def getArgv(index):
try:
return (sys.argv[1:])[index]
except:
return None
# Return list of local printer available without "virtual printer" define in USELESS_PRINTER list.
def getAvailablePrinters():
printers = win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL)
printer_list = []
for x in range(len(printers)):
if printers[x][2] not in USELESS_PRINTER:
printer_list.append(printers[x][2])
return printer_list
# Return printer name to use. If -printer is set it will return this value only if value match with available
# printers list. Return a error if -printer not in list. If no printer specified, retrieve default printer and return
# its name. Sometime default printer is on USELESS_PRINTER list so first printer return by getAvailablePrinters() is
# return. If no printer is return display an error.
def getPrinter():
default_printer = win32print.GetDefaultPrinter()
if default_printer in USELESS_PRINTER:
if len(getAvailablePrinters()) == 0:
print("No printer available, unable to print. Use -virtual if you want enable virtual printer.")
sys.exit(1801)
default_printer = getAvailablePrinters()[0]
if getArgv(2) is not None:
if getArgv(2) == "-printer":
printer = getArgv(3)
if printer in getAvailablePrinters():
return printer
else:
if printer is not None:
print("Given printer not found. Defaut printer configured: ", default_printer)
return default_printer
# Use GhostScript API to silent print .pdf and .ps. Use win32api to print .txt. Return a error if printing failed or
# file ext doesn't match.
def printFile(filepath):
try:
if os.path.splitext(filepath)[1] in [".pdf", ".ps"]:
args = [
"-dPrinted", "-dBATCH", "-dNOSAFER", "-dNOPAUSE", "-dNOPROMPT"
"-q",
"-dNumCopies#1",
"-sDEVICE#mswinpr2",
f'-sOutputFile#"%printer%{getPrinter()}"',
f'"{filepath}"'
]
encoding = locale.getpreferredencoding()
args = [a.encode(encoding) for a in args]
ghostscript.Ghostscript(*args)
elif os.path.splitext(filepath)[1] in [".txt"]:
# '"%s"' % enable to encapsulate string with quote
win32api.ShellExecute(0, "printto", '"%s"' % filepath, '"%s"' % getPrinter(), ".", 0)
return True
except:
print("Printing error for file: ", '"%s"' % filepath, "| Printer: ", '"%s"' % getPrinter())
return False
def main(argv):
if len(argv) in [1, 2, 4, 5]:
cmd1 = getArgv(0)
filepath = getArgv(1)
if argv[-1] == "-virtual":
USELESS_PRINTER.remove('Microsoft Print to PDF')
# Batch printing mode
if cmd1 == "-batch" and len(argv) in [2, 4, 5]:
if not os.path.isfile(filepath) and not os.path.exists(filepath):
print("Path provide for batch file is not a valid file path or doesn't exist.")
sys.exit(2)
if os.path.splitext(filepath)[1] in [".txt"]:
with open(filepath) as fp:
line = fp.readline().strip('\n')
while line:
if not os.path.isfile(line) and not os.path.exists(line):
print("Path provide is not a valid file path or doesn't exist: ", line)
else:
printFile(line)
line = fp.readline().strip('\n')
fp.close()
else:
print("Not supported file format for batch printing.")
sys.exit(50)
# Single file printing mode
elif cmd1 == "-file" and len(argv) in [2, 4, 5]:
if not os.path.isfile(filepath) and not os.path.exists(filepath):
print("Path provide is not a file path.")
sys.exit(2)
if not printFile(filepath):
sys.exit(1)
# Get printers list
elif cmd1 == "-list" and len(argv) in [1, 2]:
for printer in getAvailablePrinters():
print(printer)
# Display help
elif cmd1 == "-help" and len(argv) in [1]:
print(HELP)
sys.exit(0)
else:
print("Unknow option. Use -help to obtain more informations about supported options.")
sys.exit(50)
else:
print("Wrong arguments number. Use -help to obtain more informations about supported options.")
sys.exit(50)
exit(0)
if __name__ == '__main__':
main(sys.argv[1:])
Following command explain how to use it:
python main.py -help
pyPrinter - Author: Arthur - Date: 19/05/2021
-help
Display this message.
-list [-virtual]
Return list of available printer (excepted: OneNote for Windows 10, OneNote (Desktop), Microsoft XPS Document Writer, Microsoft Print to PDF, Fax)
-file filepath [-printer printer_name] [-virtual]
Print specified file on default system printer. Use -printer to specify printer to use. Printer name must be available un -list response.
-batch filepath [-printer printer_name] [-virtual]
Print each document specified un batch file on default system printer. Batch file must be a .txt. Each file to print must be write on its own line.
Use -printer to specify printer to use. Printer name must be available un -list response.
-virtual
Use this option after all other arguments to enable printing on virtual printer 'Microsoft Print to PDF'
To print one file to printer HP1FF6CC (HP OfficeJet Pro 6970)
python main.py -file "D:\my\system\path\to\file\pattern.ps" -printer "HP1FF6CC (HP OfficeJet Pro 6970)"
To print one file to virtual printer Microsoft Print to PDF (generally for text purpose, paper is quickly expensive)
python main.py -file "D:\my\system\path\to\file\pattern.ps" -printer "Microsoft Print to PDF" -virtual
There is another method to send the file to printer without adobe reader also, by SumatraPDF
install SumatraPDF application and add the SumatraPDF.exe location to the path
# import subprocess and os
import subprocess
import os
# file path
file_name = "Document.pdf"
if file_name:
print("exist")
# send data to the printer
try:
subprocess.call(['SumatraPDF.exe', '-print-to', "Barcode",
'-print-settings', "1x", file_name])
except BaseException as msg:
print(msg)
there is no need to have any adobe reader, and for every time it wont open the adobe reader to read data,
but issue is that should try on page orientation and page size,
but if those are same always for pdf seems we can change in the printer properties directly,
only to add exe path to the file path in system
thats it
So this isn't exactly silently, but it will automatically dismiss the dialog box and print anyway, also has a weird dependency on selenium that you wouldn't expect per se, but this actually worked for me since I was in a world where I wasn't allowed to download ghostscript nor could I download adobe's pdf reader. I thought it might help someone else out there, somewhere, some place, some time...
from selenium import webdriver
import win32com.client
import win32print
import time
def printpdf(pdf,printer):
current_printer = win32print.GetDefaultPrinter()
win32print.SetDefaultPrinter(printer)
driver = webdriver.Chrome()
driver.get(pdf)
time.sleep(1) #Adjust as necessary
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys('^p')
time.sleep(1) #Adjust as necessary
shell.SendKeys('{ENTER}') #dismiss the print dialog box
driver.close()
win32print.SetDefaultPrinter(current_printer)
If you have Adobe try this:
import win32api
import winreg
import subprocess
import time
def get_adobe_executable():
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as conn:
with winreg.OpenKey(conn, r'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe', 0, winreg.KEY_READ) as hkey:
value = winreg.QueryValue(hkey, None)
if value:
value = '"{}"'.format(value)
return value.strip()
return None
def print_pdf_file(file, printer_name=None, secs=5):
cmd = get_adobe_executable()
if cmd is None:
return False
if printer_name:
cmd = '{} /h /t "{}" "{}"'.format(cmd, file, printer_name)
else:
cmd = '{} /p /h "{}"'.format(cmd, file)
proc = subprocess.Popen(cmd)
time.sleep(secs)
proc.kill()
return True
if __name__ == "__main__":
print_pdf_file("doc.pdf") # print with default printer
print_pdf_file("doc.pdf", "HP LaserJet Pro M102") # setting the printer name
get_adobe_executable
Get the Adobe from the registry(you can also get the print command like the one that you right click the pdf file and select Print from the menu but I wanted to just get the path then configure it according to the printer configuration)
print_pdf_file
If you don't set the printer_name variable, Adobe will print with the default printer
After executing the print command it will wait 5 seconds and then close Adobe program, Adobe it does not have command line option (as today of writing) to exit after printing the file, here you can see the command line options

running command before other finished in python

I asked already and few people gave good advises but there were to many unknowns for me as I am beginner. Therefore I decided to ask for help again without giving bad code.
I need a script which will execute copy files to directory while the other is still running.
Basically I run first command, it generates files (until user press enter) and then those files are gone (automatically removed).
What I would like to have is to copying those files (without have to press "Enter" as well).
I made in bash however I would like to achieve this on python. Please see below:
while kill -0 $! 2>/dev/null;do
cp -v /tmp/directory/* /tmp/
done
If first script is purely command line : it should be fully manageable with a python script.
General architecture :
python scripts starts first one with subprocess module
reads output from first script until it gets the message asking for pressing enter
copies all files from source directory to destination directory
sends \r into first script input
waits first script terminates
exits
General requirements :
first script must be purely CLI one
first script must write to standart output/error and read from standard input - if it reads/writes to physical terminal (/dev/tty on Unix/Linux or con: on Dos/Windows), it won't work
the end of processing must be identifiable in standard output/error
if the two above requirement were no met, the only way would be to wait a define amount of time
Optional operation :
if there are other interactions in first script (read and/or write), it will be necessary to add the redirections in the script, it is certainly feasible, but will be a little harder
Configuration :
the command to be run
the string (from command output) that indicates first program has finished processing
the source directory
the destination directory
a pattern for file name to be copied
if time defined and no identifiable string in output : the delay to wait before copying
A script like that should be simple to write and test and able to manage the first script as you want.
Edit : here is an example of such a script, still without timeout management.
import subprocess
import os
import shutil
import re
# default values for command execution - to be configured at installation
defCommand = "test.bat"
defEnd = "Appuyez"
defSource = "."
defDest = ".."
# BEWARE : pattern is in regex format !
defPattern="x.*\.txt"
class Launcher(object):
'''
Helper to launch a command, wait for a defined string from stderr or stdout
of the command, copy files from a source folder to a destination folder,
and write a newline to the stdin of the command.
Limits : use blocking IO without timeout'''
def __init__(self, command=defCommand, end=defEnd, source=defSource,
dest=defDest, pattern = defPattern):
self.command = command
self.end = end
self.source = source
self.dest = dest
self.pattern = pattern
def start(self):
'Actualy starts the command and copies the files'
found = False
pipes = os.pipe() # use explicit pipes to mix stdout and stderr
rx = re.compile(self.pattern)
cmd = subprocess.Popen(self.command, shell=True, stdin=subprocess.PIPE,
stdout=pipes[1], stderr=pipes[1])
os.close(pipes[1])
while True:
txt = os.read(pipes[0], 1024)
#print(txt) # for debug
if str(txt).find(self.end) != -1:
found = True
break
# only try to copy files if end string found
if found:
for file in os.listdir(self.source):
if rx.match(file):
shutil.copy(os.path.join(self.source, file), self.dest)
print("Copied : %s" % (file,))
# copy done : write the newline to command input
cmd.stdin.write(b"\n")
cmd.stdin.close()
try:
cmd.wait()
print("Command terminated with %d status" % (cmd.returncode,))
except:
print("Calling terminate ...")
cmd.terminate()
os.close(pipes[0])
# allows to use the file either as an imported module or directly as a script
if __name__ == '__main__':
# parse optional parameters
import argparse
parser = argparse.ArgumentParser(description='Launch a command and copy files')
parser.add_argument('--command', '-c', nargs = 1, default = defCommand,
help="full text of the command to launch")
parser.add_argument('--endString', '-e', nargs = 1, default = defEnd,
dest="end",
help="string that denotes that command has finished processing")
parser.add_argument('--source', '-s', nargs = 1, default = defSource,
help="source folder")
parser.add_argument('--dest', '-d', nargs = 1, default = defDest,
help = "destination folder")
parser.add_argument('--pattern', '-p', nargs = 1, default = defPattern,
help = "pattern (regex format) for files to be copied")
args = parser.parse_args()
# create and start a Launcher ...
launcher = Launcher(args.command, args.end, args.source, args.dest,
args.pattern)
launcher.start()

Categories

Resources