super increase gpt power

This commit is contained in:
feder-cr 2024-08-09 17:26:07 +01:00
parent 6dab29af3a
commit e314cc6ebb
7 changed files with 476 additions and 34 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ data_folder*
.venv
generated_cv
resume.html
.vscode

4
gpt.py
View File

@ -171,13 +171,13 @@ class GPTAnswerer:
resume_markdown_chain = resume_markdown_prompt | self.llm_cheap | StrOutputParser()
fusion_job_description_resume_chain = fusion_job_description_resume_prompt | self.llm_cheap | StrOutputParser()
html_template = strings.html_template.format(email_address=self.resume.personal_information.email, phone_number=self.resume.personal_information.phonePrefix + self.resume.personal_information.phone , github_link=self.resume.personal_information.github, linkedin_link=self.resume.personal_information.linkedin,city=self.resume.personal_information.city,country=self.resume.personal_information.country)
#html_template = strings.html_template.format(email_address=self.resume.personal_information.email, phone_number=self.resume.personal_information.phonePrefix + self.resume.personal_information.phone , github_link=self.resume.personal_information.github, linkedin_link=self.resume.personal_information.linkedin,city=self.resume.personal_information.city,country=self.resume.personal_information.country)
composed_chain = (
resume_markdown_chain
| (lambda output: {"job_description": self.job.summarize_job_description, "formatted_resume": output})
| fusion_job_description_resume_chain
| (lambda formatted_resume: html_template + formatted_resume)
| (lambda formatted_resume: strings.html_template + formatted_resume)
)
try:

View File

@ -1,4 +1,4 @@
import io
import base64
import os
import random
import tempfile
@ -23,13 +23,11 @@ import io
import time
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from xhtml2pdf import pisa
import utils
class LinkedInEasyApplier:
def __init__(self, driver: Any, resume_dir: Optional[str], set_old_answers: List[Tuple[str, str, str]], gpt_answerer: Any):
if resume_dir is None or not os.path.exists(resume_dir):
@ -181,45 +179,28 @@ class LinkedInEasyApplier:
def _create_and_upload_resume(self, element):
max_retries = 3
retry_delay = 1 # seconds
retry_delay = 1
folder_path = 'generated_cv'
# Create the directory if it doesn't exist
if not os.path.exists(folder_path):
os.makedirs(folder_path)
for attempt in range(max_retries):
try:
html_string = self.gpt_answerer.get_resume_html()
file_name = 'resume.html'
with open(file_name, 'w', encoding='utf-8') as file:
file.write(html_string)
file_path = os.path.abspath(file_name)
self.driver.execute_script("window.open('');")
self.driver.switch_to.window(self.driver.window_handles[1])
self.driver.get(f"file:///{file_path}")
time.sleep(1)
page_source = self.driver.page_source
self.driver.close()
self.driver.switch_to.window(self.driver.window_handles[0])
with tempfile.NamedTemporaryFile(delete=False, suffix='.html', mode='w', encoding='utf-8') as temp_html_file:
temp_html_file.write(html_string)
file_name_HTML = temp_html_file.name
file_name_pdf = f"resume_{uuid.uuid4().hex}.pdf"
file_path_pdf = os.path.join(folder_path, file_name_pdf)
# Convert HTML to PDF and save it to the specified folder
with open(file_path_pdf, 'wb') as pdf_file:
pisa_status = pisa.CreatePDF(page_source, dest=pdf_file)
with open(file_path_pdf, "wb") as f:
f.write(base64.b64decode(utils.HTML_to_PDF(file_name_HTML,True)))
file_path_pdf = os.path.abspath(file_path_pdf)
# Upload the file
element.send_keys(file_path_pdf)
if pisa_status.err:
raise Exception(f"PDF generation failed with error: {pisa_status.err}")
time.sleep(2) # Give some time for the upload process
os.remove(file_name_HTML)
return True
except Exception:
if attempt < max_retries - 1:
time.sleep(retry_delay)

View File

@ -0,0 +1,202 @@
/*****************************************************************************
* casual-markdown - a lightweight regexp-base markdown parser with TOC support
* 2022/07/31, v0.90, refine frontmatter (simple yaml)
* 2023/04/12, v0.92, addCopyButton for code-block
*
* Copyright (c) 2022-2023, Casualwriter (MIT Licensed)
* https://github.com/casualwriter/casual-markdown
*****************************************************************************/
;(function(){
// define md object, and extent function (which is a dummy function)
var md = { yaml:{}, before: function (str) {return str}, after: function (str) {return str} }
// function for REGEXP to convert html tag. ie. <TAG> => &lt;TAG*gt;
md.formatTag = function (html) { return html.replace(/</g,'&lt;').replace(/\>/g,'&gt;'); }
// frontmatter for simple YAML (support multi-level, but string value only)
md.formatYAML = function (front, matter) {
var level = {}, latest = md.yaml;
matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) {
level[sp] = level[sp] || latest
latest = level[sp][key.trim()] = val.trim() || {}
for (e in level) if(e>sp) level[e]=null;
} );
return ''
}
//===== format code-block, highlight remarks/keywords for code/sql
md.formatCode = function (match, title, block) {
// convert tag <> to &lt; &gt; tab to 3 space, support marker using ^^^
block = block.replace(/</g,'&lt;').replace(/\>/g,'&gt;')
block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '<mark>$1</mark>')
// highlight comment and keyword based on title := none | sql | code
if (title.toLowerCase(title) == 'sql') {
block = block.replace(/^\-\-(.*)/gm,'<rem>--$1</rem>').replace(/\s\-\-(.*)/gm,' <rem>--$1</rem>')
block = block.replace(/(\s?)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1<b>$2</b>$3')
block = block.replace(/(\s?)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1<b>$2</b>$3')
} else if ((title||'none')!=='none') {
block = block.replace(/^\/\/(.*)/gm,'<rem>//$1</rem>').replace(/\s\/\/(.*)/gm,' <rem>//$1</rem>')
block = block.replace(/(\s?)(function|procedure|return|exit|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1<b>$2</b>$3')
block = block.replace(/(\s?)(var|let|const|=>|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1<b>$2</b>$3')
}
return '<pre title="' + title + '"><button onclick="md.clipboard(this)">copy</button><code>' + block + '</code></pre>'
}
// copy to clipboard for code-block
md.clipboard = function (e) {
navigator.clipboard.writeText( e.parentNode.innerText.replace('copy\n','') )
e.innerText = 'copied'
}
//===== parse markdown string into HTML string (exclude code-block)
md.parser = function( mdstr ) {
// apply yaml variables
for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
// table syntax
mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\s?\|\s?\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'<th>')
var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
tbody = tbody.replace(/(.+)/gm,'<tr><td>$1</td></tr>').replace(/\|/g,'<td>')
return '\n<table>\n<thead>\n<th>' + thead + '\n</thead>\n<tbody>' + tbody + '\n</tbody></table>\n\n'
} )
// horizontal rule => <hr>
mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '<hr>').replace(/\n\n<hr\>/g, '\n<br><hr>')
// header => <h1>..<h5>
mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '<h5>$1</h5>')
.replace(/^#### (.*?)\s*#*$/gm, '<h4>$1</h4>')
.replace(/^### (.*?)\s*#*$/gm, '<h3>$1</h3>')
.replace(/^## (.*?)\s*#*$/gm, '<h2>$1</h2>')
.replace(/^# (.*?)\s*#*$/gm, '<h1>$1</h1>')
.replace(/^<h(\d)\>(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '<h$1 id="$3">$2</h$1>')
// inline code-block: `code-block` => <code>code-block</code>
mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '<code>' + md.formatTag(p).replace(/`/g,'&#96;') + '</code>'} )
mdstr = mdstr.replace(/`(.*?)`/gm, '<code>$1</code>' )
// blockquote, max 2 levels => <blockquote>{text}</blockquote>
mdstr = mdstr.replace(/^\>\> (.*$)/gm, '<blockquote><blockquote>$1</blockquote></blockquote>')
mdstr = mdstr.replace(/^\> (.*$)/gm, '<blockquote>$1</blockquote>')
mdstr = mdstr.replace(/<\/blockquote\>\n<blockquote\>/g, '\n<br>' )
mdstr = mdstr.replace(/<\/blockquote\>\n<br\><blockquote\>/g, '\n<br>' )
// image syntax: ![title](url) => <img alt="title" src="url" />
mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '<img alt="$1" src="$2" $3 />')
mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '<img alt="$1" src="$2" width="90%" />')
// links syntax: [title "title"](url) => <a href="url" title="title">text</a>
mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '<a href="$2" target=_new>$1</a>')
mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '<a href="$2" title="$3">$1</a>')
mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1<a href="$2">$2</a>$3')
mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '<a href="$1">$1</a>')
mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '<a href="$2">$1</a>')
// unordered/ordered list, max 2 levels => <ul><li>..</li></ul>, <ol><li>..</li></ol>
mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '<ul><li>$1</li></ul>' )
mdstr = mdstr.replace(/^\d\d?[ .](.*)/gm, '<ol><li>$1</li></ol>' )
mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '<ul><ul><li>$1</li></ul></ul>' )
mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '<ul><ol><li>$1</li></ol></ul>' )
mdstr = mdstr.replace(/<\/[ou]l\>\n\n?<[ou]l\>/g, '\n' )
mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
// text decoration: bold, italic, underline, strikethrough, highlight
mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '<b><em>$1</em></b>')
mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '<b>$1</b>')
mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '<em>$1</em>')
mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '<b><em>$1</em></b>')
mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '<u>$1</u>')
// mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '<u>$1</u>') // NOT support!!
mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '<mark>$1</mark>')
mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '<ins>$1</ins>')
mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '<del>$1</del>')
// line break and paragraph => <br/> <p>
mdstr = mdstr.replace(/ \n/g, '\n<br/>').replace(/\n\s*\n/g, '\n<p>\n')
// indent as code-block
mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '<pre><code>' + md.formatTag(p) + '</code></pre>'} )
mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '<pre><code>' + md.formatTag(p) + '</code></pre>'} )
mdstr = mdstr.replace(/<\/code\><\/pre\>\n<pre\><code\>/g, '\n' )
// Escaping Characters
return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
}
//===== parse markdown string into HTML content (cater code-block)
md.html = function (mdText) {
// replace \r\n to \n, and handle front matter for simple YAML
mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
// handle code-block.
mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
// split by "<code>", skip for code-block and process normal text
var pos1=0, pos2=0, mdHTML = ''
while ( (pos1 = mdText.indexOf('<code>')) >= 0 ) {
pos2 = mdText.indexOf('</code>', pos1 )
mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
mdText = mdText.substr( pos2 + 7 )
}
return '<div class="markdown">' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '</div>'
}
//===== TOC support
md.toc = function (srcDiv, tocDiv, options ) {
// select elements, set title
var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
var tocTitle = (options&&options.title) || 'Table of Contents'
var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
var html = '<div class="toc"><ul>' + (tocTitle=='none'? '' : '<h3>' + tocTitle + '</h3>');
// loop for each element,add <li> element with class in TAG name.
for (var i=0; i<toc.length; i++ ) {
if (toc[i].id.substr(0,6)=='no-toc') continue;
if (!toc[i].id) toc[i].id = "toc-item-" + i;
html += '<li class="' + toc[i].nodeName + '" title="#' + toc[i].id + '" onclick="location=this.title">'
html += toc[i].textContent + '</a></li>';
}
document.getElementById(tocDiv).innerHTML = html + "</ul>";
//===== scrollspy support (ps: add to document.body if element(scrollspy) not found)
if ( options && options.scrollspy ) {
(document.getElementById(options.scrollspy)||document).onscroll = function () {
// get TOC elements, and viewport position
var list = document.getElementById(tocDiv).querySelectorAll('li')
var divScroll = document.getElementById(options.scrollspy) || document.documentElement
var divHeight = divScroll.clientHeight || divScroll.offsetHeight
// loop for each TOC element, add/remove scrollspy class
for (var i=0; i<list.length; i++) {
var div = document.getElementById( list[i].title.substr(1) )
var pos = (div? div.offsetTop - divScroll.scrollTop + 10: 0 )
if ( pos>0 && pos<divHeight ) {
list[i].className = list[i].className.replace('active','') + ' active' // classList.add( 'active' );
} else {
list[i].className = list[i].className.replace('active','') // classList.remove( 'active' );
}
}
}
}
//===== end of scrollspy
}
if (typeof exports==='object') {
module.exports=md;
} else if (typeof define==='function') {
define(function(){return md;});
} else {
this.md=md;
}
}).call( function(){ return this||(typeof window!=='undefined'?window:global)}() );

View File

@ -0,0 +1,43 @@
// reorganizeHeader.js
function reorganizeHeader() {
const h1 = document.querySelector('h1');
if (!h1) return;
let currentNode = h1;
const headerInfoElements = [];
const contactInfoElements = [];
let firstAnchorFound = false;
while (currentNode && currentNode.tagName !== 'H2') {
if (currentNode.tagName === 'A') {
if (!firstAnchorFound) {
headerInfoElements.push(currentNode);
firstAnchorFound = true;
} else {
contactInfoElements.push(currentNode);
}
} else {
headerInfoElements.push(currentNode);
}
currentNode = currentNode.nextElementSibling;
}
const newHeader = document.createElement('header');
const headerInfoDiv = document.createElement('div');
headerInfoDiv.className = 'header-info';
headerInfoElements.forEach(el => {
headerInfoDiv.appendChild(el);
});
const contactInfoDiv = document.createElement('div');
contactInfoDiv.className = 'contact-info';
contactInfoElements.forEach(el => {
contactInfoDiv.appendChild(el);
});
newHeader.appendChild(headerInfoDiv);
newHeader.appendChild(contactInfoDiv);
const h2 = document.querySelector('h2');
if (h2) {
h2.parentNode.insertBefore(newHeader, h2);
}
}
setTimeout(function() {
reorganizeHeader();
}, 100);

156
resume_template/resume.css Normal file
View File

@ -0,0 +1,156 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@700&family=Roboto:wght@400&display=swap');
/* Reset generale per uniformità */
body, h2, h3, h4, p, ul, ol {
margin: 0;
padding: 0;
font-family: 'Roboto', sans-serif;
}
body {
line-height: 1.6;
margin: auto;
padding: 20px;
max-width: 1024px;
color: #333;
background-color: #f8f9fa;
}
/* Header Style */
header {
background-color: #e9ecef; /* Sfondo leggermente più scuro */
padding: 15px 20px 0 20px; /* Padding: 15px sopra, 20px a destra e a sinistra, 0px sotto */
border-bottom: 2px solid #d1d1d1; /* Bordo sottile per separare il header dal resto del contenuto */
font-family: 'Roboto', sans-serif; /* Font per il testo generico */
display: flex;
justify-content: space-between;
align-items: center;
}
.header-info {
flex: 1;
}
.header-info h1 {
margin: 0;
font-size: 30px; /* Dimensione del font aumentata per il nome */
color: #000; /* Colore nero per il testo del nome */
font-family: 'Montserrat', sans-serif; /* Font più accattivante per il nome */
}
.header-info a {
color: #0056b3; /* Colore blu intenso per i link */
text-decoration: none;
font-weight: bold;
}
.header-info a:hover {
text-decoration: underline;
}
.contact-info {
flex: 0;
text-align: center; /* Centratura del testo */
}
.contact-info a {
display: block;
color: #0056b3; /* Colore blu intenso per i link */
text-decoration: none;
margin-bottom: 5px; /* Spaziatura tra i contatti */
font-size: 14px; /* Dimensione del font per i dettagli di contatto */
font-family: 'Roboto', sans-serif; /* Font moderno per i dettagli di contatto */
font-weight: bold;
}
.contact-info a:hover {
color: #ff5722; /* Colore arancione per i link al passaggio del mouse */
}
.contact-info a:visited {
color: #666; /* Colore grigio scuro per i link visitati */
}
/* Stile per i titoli delle sezioni */
h2 {
font-size: 24px;
color: #0056b3;
border-bottom: 1px solid #d1d1d1;
margin-bottom: 10px;
padding-bottom: 5px;
font-family: 'Montserrat', sans-serif;
}
/* Stile per le esperienze professionali */
h3 {
font-size: 20px;
color: #212529;
margin-top: 15px;
margin-bottom: 5px;
}
em {
color: #555;
}
ol, ul {
margin-left: 20px;
margin-bottom: 15px;
}
li {
margin-bottom: 8px;
line-height: 1.5;
}
/* Stile per le sezioni secondarie */
p {
margin-bottom: 15px;
}
b {
color: #212529;
}
/* Stile per i link */
a {
color: #0056b3;
}
a:hover {
color: #ff5722;
text-decoration: underline;
}
/* Responsività per schermi più piccoli */
@media (max-width: 768px) {
header {
flex-direction: column;
text-align: center;
}
.contact-info {
text-align: center;
margin-top: 10px;
}
}
.markdown code { background:#f0f0f0; color:navy; border-radius:6px; padding:2px; }
.markdown pre { background:#f0f0f0; margin:12px; border:1px solid #ddd; padding:20px 12px; border-radius:6px; }
.markdown pre:hover button { display:block; }
.markdown pre button { display:none; position:relative; float:right; top:-16px }
.markdown blockquote { background:#f0f0f0; border-left:6px solid grey; padding:8px }
.markdown table { margin:12px; border-collapse: collapse; }
.markdown th { border:1px solid grey; background:lightgrey; padding:6px; }
.markdown td { border:1px solid grey; padding:6px; }
.markdown tr:nth-child(even) { background:#f0f0f0; }
.markdown ins { color:#890604 }
.markdown rem { color:#198964 }
.toc ul { padding: 0 12px; }
.toc h3 { color:#0057b7; border-bottom:1px dotted grey }
.toc .H1 { list-style-type:none; font-weight:600; margin:4px; background:#eee }
.toc .H2 { list-style-type:none; font-weight:600; margin:4px; }
.toc .H3 { margin-left:2em }
.toc .H4 { margin-left:4em }
.toc .active { color:#0057b7 }
.toc li:hover { background:#f0f0f0 }

View File

@ -1,6 +1,13 @@
import json
import os
import random
import time
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium import webdriver
import time
import glob
from webdriver_manager.chrome import ChromeDriverManager
headless = False
chromeProfilePath = r"/home/.config/google-chrome/linkedin_profile"
@ -43,6 +50,58 @@ def scroll_slow(driver, scrollable_element, start=0, end=3600, step=100, reverse
except Exception as e:
print(f"Exception occurred: {e}")
def HTML_to_PDF(FilePath, Hide_Window=True):
# Validate and prepare file paths
if not os.path.isfile(FilePath):
raise FileNotFoundError(f"The specified file does not exist: {FilePath}")
FilePath = f"file:///{os.path.abspath(FilePath).replace(os.sep, '/')}"
# Set up Chrome options
chrome_options = webdriver.ChromeOptions()
if Hide_Window:
chrome_options.add_argument("--headless") # Run Chrome in headless mode
# Initialize Chrome driver
service = ChromeService(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=chrome_options)
try:
# Load the HTML file
driver.get(FilePath)
start_time = time.time()
pdf_base64 = driver.execute_cdp_cmd("Page.printToPDF", {
"printBackground": True, # Incluir los fondos en el PDF
"landscape": False, # Orientación vertical
"paperWidth": 10, # Ancho en pulgadas (Carta: 8.5)
"paperHeight": 11, # Alto en pulgadas (Carta: 11)
"marginTop": 0, # Márgenes en pulgadas
"marginBottom": 0,
"marginLeft": 0,
"marginRight": 0,
"displayHeaderFooter": False, # No mostrar encabezado y pie de página
"preferCSSPageSize": True, # Preferir el tamaño de página definido por CSS
"generateDocumentOutline": False, # No generar un índice en el PDF
"generateTaggedPDF": False, # No generar PDF accesible
"transferMode": "ReturnAsBase64" # Retornar el PDF como base64
})
# Check if PDF generation was successful
if time.time() - start_time > 120:
raise TimeoutError("PDF generation exceeded the specified timeout limit.")
# Return the base64-encoded PDF
return pdf_base64['data']
except WebDriverException as e:
raise RuntimeError(f"WebDriver exception occurred: {e}")
finally:
# Ensure the driver is closed
driver.quit()
def chromeBrowserOptions():
options = webdriver.ChromeOptions()
options.add_argument('--no-sandbox')