kmisc 2.1.120__tar.gz → 2.1.122__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kmisc-2.1.120 → kmisc-2.1.122}/PKG-INFO +1 -1
- {kmisc-2.1.120 → kmisc-2.1.122}/kmisc/__init__.py +209 -14
- {kmisc-2.1.120 → kmisc-2.1.122}/kmisc.egg-info/PKG-INFO +1 -1
- {kmisc-2.1.120 → kmisc-2.1.122}/LICENSE +0 -0
- {kmisc-2.1.120 → kmisc-2.1.122}/README.md +0 -0
- {kmisc-2.1.120 → kmisc-2.1.122}/kmisc.egg-info/SOURCES.txt +0 -0
- {kmisc-2.1.120 → kmisc-2.1.122}/kmisc.egg-info/dependency_links.txt +0 -0
- {kmisc-2.1.120 → kmisc-2.1.122}/kmisc.egg-info/top_level.txt +0 -0
- {kmisc-2.1.120 → kmisc-2.1.122}/pyproject.toml +0 -0
- {kmisc-2.1.120 → kmisc-2.1.122}/setup.cfg +0 -0
- {kmisc-2.1.120 → kmisc-2.1.122}/setup.py +0 -0
@@ -23,12 +23,13 @@ import fnmatch
|
|
23
23
|
import smtplib
|
24
24
|
import zipfile
|
25
25
|
import tarfile
|
26
|
+
import warnings
|
26
27
|
import email.utils
|
27
28
|
from sys import modules
|
28
29
|
from pprint import pprint
|
29
30
|
import fcntl,socket,struct
|
30
31
|
from email import encoders
|
31
|
-
from threading import Thread
|
32
|
+
from threading import Thread, Lock
|
32
33
|
from datetime import datetime
|
33
34
|
from http.cookies import Morsel # This module for requests when you use build by pyinstaller command
|
34
35
|
import xml.etree.ElementTree as ET
|
@@ -39,6 +40,10 @@ Process=multiprocessing.Process
|
|
39
40
|
Queue=multiprocessing.Queue
|
40
41
|
#from multiprocessing import Process, Queue
|
41
42
|
from email.mime.multipart import MIMEMultipart
|
43
|
+
|
44
|
+
warning_message='ignore'
|
45
|
+
warnings.filterwarnings(warning_message)
|
46
|
+
|
42
47
|
try:
|
43
48
|
from kmport import *
|
44
49
|
import kmport
|
@@ -3448,12 +3453,25 @@ def Upper(src,default='org'):
|
|
3448
3453
|
if default in ['org',{'org'}]: return src
|
3449
3454
|
return default
|
3450
3455
|
|
3451
|
-
def web_capture(url,output_file,image_size='1920,1080',wait_time=3):
|
3456
|
+
def web_capture(url,output_file,image_size='1920,1080',wait_time=3,ignore_certificate_error=False,username=None,password=None,auth_fields={'auth':{'type':'name','name':('username','password')},'submit':{'type':'submit','name':None}},next_do={},gpu=False,live_capture=0,capture_method='file',find_string=None,found_space='\n',log=None,ocr_enhance=False,daemon=False,backup=False):
|
3457
|
+
#auth_fields.submit.type : name : login button with name
|
3458
|
+
# : id : login button with id
|
3459
|
+
# : submit : submit button without name or id
|
3460
|
+
#auth_fields.submit.name : <string>: name or id's submit name string
|
3461
|
+
#auth_fields.auth.type : name : username/password with name field
|
3462
|
+
# : id : username/password with name id
|
3463
|
+
#auth_fields.auth.name : (usernane,password) : username/password field string for name or id
|
3464
|
+
#next_do : put data and click submit
|
3465
|
+
|
3452
3466
|
if isinstance(image_size,str):
|
3453
3467
|
if 'x' in image_size:
|
3454
3468
|
image_size=image_size.split('x')
|
3455
3469
|
elif ',' in image_size:
|
3456
3470
|
image_size=image_size.split(',')
|
3471
|
+
elif '*' in image_size:
|
3472
|
+
image_size=image_size.split('*')
|
3473
|
+
elif ':' in image_size:
|
3474
|
+
image_size=image_size.split(':')
|
3457
3475
|
if isinstance(image_size,(list,tuple)) and len(image_size) == 2:
|
3458
3476
|
image_size=','.join([str(i) for i in image_size])
|
3459
3477
|
else:
|
@@ -3463,34 +3481,211 @@ def web_capture(url,output_file,image_size='1920,1080',wait_time=3):
|
|
3463
3481
|
if Import('import selenium'):
|
3464
3482
|
return False,'Can not install selenium package'
|
3465
3483
|
else:
|
3484
|
+
if backup:
|
3485
|
+
Import('filecmp')
|
3486
|
+
Import('shutil')
|
3487
|
+
|
3488
|
+
ocr=None
|
3489
|
+
if capture_method != 'file':
|
3490
|
+
ocr=OCR(enhance=ocr_enhance)
|
3466
3491
|
# Configure Chrome options for headless mode
|
3467
3492
|
from selenium.webdriver.chrome.options import Options
|
3493
|
+
from selenium.webdriver.common.by import By
|
3494
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
3495
|
+
from selenium.webdriver.support import expected_conditions as EC
|
3468
3496
|
chrome_options = Options()
|
3469
3497
|
chrome_options.add_argument('--headless') # Run in headless mode
|
3470
3498
|
chrome_options.add_argument('--no-sandbox')
|
3471
3499
|
chrome_options.add_argument('--disable-dev-shm-usage')
|
3472
3500
|
chrome_options.add_argument(f"--window-size={image_size}") # Set window size
|
3501
|
+
if not gpu:
|
3502
|
+
chrome_options.add_argument("--disable-gpu")
|
3503
|
+
if ignore_certificate_error:
|
3504
|
+
chrome_options.add_argument('--ignore-certificate-errors') # gnore-certificate-errors
|
3505
|
+
chrome_options.add_argument('--allow-insecure-localhost') # gnore-certificate-errors
|
3473
3506
|
# Initialize the Chrome driver
|
3474
3507
|
driver = selenium.webdriver.Chrome(options=chrome_options)
|
3475
3508
|
rc=False,output_file
|
3476
3509
|
try:
|
3477
3510
|
# Navigate to the URL
|
3478
3511
|
driver.get(url)
|
3479
|
-
|
3480
|
-
#
|
3481
|
-
|
3482
|
-
|
3483
|
-
|
3484
|
-
|
3485
|
-
|
3486
|
-
|
3512
|
+
|
3513
|
+
#Login to web page
|
3514
|
+
if username and password:
|
3515
|
+
wait = WebDriverWait(driver, 10) # Wait up to 10 seconds
|
3516
|
+
#Search field name for username,password
|
3517
|
+
if auth_fields.get('auth').get('type') == 'id':
|
3518
|
+
by_type=By.ID
|
3519
|
+
else:
|
3520
|
+
by_type=By.NAME
|
3521
|
+
username_field = wait.until(EC.presence_of_element_located((by_type, auth_fields.get('auth').get('name')[0])))
|
3522
|
+
password_field = driver.find_element(by_type, auth_fields.get('auth').get('name')[1])
|
3523
|
+
#login submit
|
3524
|
+
if auth_fields.get('submit',{}).get('type') in ['id','name']:
|
3525
|
+
if auth_fields.get('submit',{}).get('type') == 'id':
|
3526
|
+
by_type=By.ID
|
3527
|
+
else:
|
3528
|
+
by_type=By.NAME
|
3529
|
+
login_button = driver.find_element(by_type, auth_fields.get('submit').get('name'))
|
3530
|
+
else: #button submit type
|
3531
|
+
login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
|
3532
|
+
#put username/password into field
|
3533
|
+
username_field.send_keys(username)
|
3534
|
+
password_field.send_keys(password)
|
3535
|
+
#Login
|
3536
|
+
login_button.click()
|
3537
|
+
|
3538
|
+
if next_do and isinstance(next_do.get('datas'),(list,tuple)):
|
3539
|
+
wait = WebDriverWait(driver, 10) # Wait up to 10 seconds
|
3540
|
+
for do_i in next_do.get('datas'):
|
3541
|
+
if not isinstance(do_i,dict): continue
|
3542
|
+
if do_i.get('type') == 'id':
|
3543
|
+
do_type=By.ID
|
3544
|
+
else:
|
3545
|
+
do_type=By.NAME
|
3546
|
+
user_do_field = wait.until(EC.presence_of_element_located((do_type, do_i.get('name'))))
|
3547
|
+
if do_i.get('click'):
|
3548
|
+
user_do_field.click()
|
3549
|
+
else:
|
3550
|
+
user_do_field.send_keys(do_i.get('data'))
|
3551
|
+
#Submit data
|
3552
|
+
if next_do.get('type') in ['id','name']:
|
3553
|
+
if next_do.get('type') == 'id':
|
3554
|
+
by_type=By.ID
|
3555
|
+
else:
|
3556
|
+
by_type=By.NAME
|
3557
|
+
next_do_button = driver.find_element(by_type, next_do.get('name'))
|
3558
|
+
else: #button submit type
|
3559
|
+
next_do_button = driver.find_element(By.XPATH, "//button[@type='submit']")
|
3560
|
+
next_do_button.click()
|
3561
|
+
|
3562
|
+
def _capture_(live_capture,driver,output_file,wait_time,capture_method,backup,ocr,log,find_string,daemon):
|
3563
|
+
def wait_body(driver,timeout=10):
|
3564
|
+
#wait until get screen data
|
3565
|
+
try:
|
3566
|
+
selenium.webdriver.support.ui.WebDriverWait(driver,timeout).until(
|
3567
|
+
EC.presence_of_element_located((By.TAG_NAME,"body"))
|
3568
|
+
)
|
3569
|
+
return
|
3570
|
+
except:
|
3571
|
+
try:
|
3572
|
+
selenium.webdriver.support.ui.WebDriverWait(driver,timeout).until(
|
3573
|
+
lambda d: d.execute_script("return document.readyState") == "complete"
|
3574
|
+
)
|
3575
|
+
return
|
3576
|
+
except:
|
3577
|
+
pass
|
3578
|
+
time.sleep(timeout)
|
3579
|
+
|
3580
|
+
live_capture=Int(live_capture)
|
3581
|
+
wait_time=Int(wait_time,10)
|
3582
|
+
backup_idx=0
|
3583
|
+
if backup:
|
3584
|
+
backup=Int(backup,2)
|
3585
|
+
if isinstance(live_capture,int) and live_capture > wait_time*2:
|
3586
|
+
Time=TIME()
|
3587
|
+
while True:
|
3588
|
+
if Time.Out(live_capture):
|
3589
|
+
driver.quit()
|
3590
|
+
return False
|
3591
|
+
# Capture screenshot
|
3592
|
+
if log:
|
3593
|
+
if log in ['screen','log','print',print]:
|
3594
|
+
printf(Dot(),direct=True)
|
3595
|
+
else:
|
3596
|
+
printf(Dot(),log=log,direct=True)
|
3597
|
+
if backup:
|
3598
|
+
save_file='{}.{}'.format(output_file,backup_idx%backup)
|
3599
|
+
else:
|
3600
|
+
save_file=output_file
|
3601
|
+
#wait
|
3602
|
+
wait_body(driver,timeout=wait_time)
|
3603
|
+
#capture
|
3604
|
+
driver.save_screenshot(save_file)
|
3605
|
+
if backup:
|
3606
|
+
if backup == 2:
|
3607
|
+
comp_a=f'{output_file}.0'
|
3608
|
+
comp_b=f'{output_file}.1'
|
3609
|
+
if os.path.isfile(comp_a) and os.path.isfile(comp_b):
|
3610
|
+
if filecmp.cmp(comp_a,comp_b):
|
3611
|
+
if log:
|
3612
|
+
if log in ['screen','log','print',print]:
|
3613
|
+
printf(Dot(),direct=True)
|
3614
|
+
else:
|
3615
|
+
printf(Dot(),log=log,direct=True)
|
3616
|
+
time.sleep(wait_time)
|
3617
|
+
backup_idx+=1
|
3618
|
+
continue
|
3619
|
+
shutil.copy2(save_file,output_file)
|
3620
|
+
if IsIn(capture_method,['log','screen','text']):
|
3621
|
+
found_words=ocr.Text(image_file=save_file)
|
3622
|
+
found_strings=found_space.join(found_words)
|
3623
|
+
printf(found_strings,log=log,mode='d' if log else 's')
|
3624
|
+
if find_string:
|
3625
|
+
if find_string in found_strings:
|
3626
|
+
driver.quit()
|
3627
|
+
return True
|
3628
|
+
time.sleep(wait_time)
|
3629
|
+
backup_idx+=1
|
3630
|
+
else:
|
3631
|
+
#wait
|
3632
|
+
wait_body(driver,timeout=wait_time)
|
3633
|
+
#capture
|
3634
|
+
driver.save_screenshot(output_file)
|
3635
|
+
driver.quit()
|
3636
|
+
if daemon:
|
3637
|
+
t=kThread(target=_capture_, args=(live_capture,driver,output_file,wait_time,capture_method,backup,ocr,log,find_string,daemon))
|
3638
|
+
return t
|
3639
|
+
else:
|
3640
|
+
_capture_(live_capture,driver,output_file,wait_time,capture_method,backup,ocr,log,find_string,daemon)
|
3641
|
+
return True,output_file
|
3642
|
+
|
3487
3643
|
except Exception as e:
|
3488
3644
|
#print(f"Error capturing screenshot: {str(e)}")
|
3489
|
-
rc=False,str(e)
|
3490
|
-
finally:
|
3491
|
-
# Close the browser
|
3492
3645
|
driver.quit()
|
3493
|
-
|
3646
|
+
return False,str(e)
|
3647
|
+
# finally:
|
3648
|
+
# # Close the browser
|
3649
|
+
# driver.quit()
|
3650
|
+
# return rc
|
3651
|
+
|
3652
|
+
class OCR:
|
3653
|
+
def __init__(self,image_file=None,enhance=False,language=['en'],gpu=False,model_storage_directory=None,**opts):
|
3654
|
+
self.enhance=enhance
|
3655
|
+
self.image_file=image_file
|
3656
|
+
Import('easyocr')
|
3657
|
+
if self.enhance:
|
3658
|
+
Import('PIL',install_name='Pillow')
|
3659
|
+
Import('numpy')
|
3660
|
+
self.reader = easyocr.Reader(language,gpu=gpu,model_storage_directory=model_storage_directory)
|
3661
|
+
# Suppress Torch pin_memory warning
|
3662
|
+
warnings.filterwarnings("ignore", category=UserWarning, module="torch.utils.data.dataloader")
|
3663
|
+
|
3664
|
+
# Suppress EasyOCR CPU warning
|
3665
|
+
#warnings.filterwarnings("ignore", message="WARNING:easyocr.easyocr:Using CPU. Note: This module is much faster with a GPU.")
|
3666
|
+
|
3667
|
+
# Suppress NetworkX backend warning
|
3668
|
+
warnings.filterwarnings("ignore", category=RuntimeWarning, module="networkx.utils.backends")
|
3669
|
+
|
3670
|
+
def Text(self,detail=0,low_text=None,contrast_ths=None,image_file=None):
|
3671
|
+
if not image_file: image_file=self.image_file
|
3672
|
+
if not image_file: return False
|
3673
|
+
opts={}
|
3674
|
+
opts['detail']=detail
|
3675
|
+
if isinstance(low_text,float): opts['low_text']=low_test
|
3676
|
+
if isinstance(contrast_ths,float): opts['contrast_ths']=contrast_ths
|
3677
|
+
if self.enhance:
|
3678
|
+
image = PIL.Image.open(image_file)
|
3679
|
+
image = image.convert('L') #Grayscale
|
3680
|
+
image = PIL.ImageEnhance.Contrast(image).enhance(3.0) #high contrast
|
3681
|
+
image = PIL.ImageEnhance.Sharpness(image).enhance(2.0)#Sharpen
|
3682
|
+
image = image.convert('RGB').point(lambda p: 255 if p > 140 else 0) # Adjust threshold if needed
|
3683
|
+
# image = image.resize((800, int(800 * image.height / image.width)), PIL.Image.Resampling.LANCZOS)
|
3684
|
+
image.save(image_file)
|
3685
|
+
# image_np = numpy.array(image)
|
3686
|
+
# return self.reader.readtext(image_np,**opts)
|
3687
|
+
# else:
|
3688
|
+
return self.reader.readtext(image_file,**opts)
|
3494
3689
|
|
3495
3690
|
############################################
|
3496
3691
|
#Temporary function map for replacement
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|