ide:pycharm铝噩;
language:python衡蚂;
selenium:3.141.0
啟動(dòng)pycharm,并創(chuàng)建名為seleniumHQ的工程骏庸,創(chuàng)建一個(gè)py文件毛甲,輸入如下代碼:
if __name__ == '__main__':
from selenium.webdriver.chrome.webdriver import WebDriver
path="/Users/apple/Seleniumdriver/chromedriver"
driver = WebDriver(executable_path=path)
driver.get("https://www.baidu.com")
driver.close()
driver.quit()
進(jìn)入WebDriver類源碼
class WebDriver(RemoteWebDriver):
"""
Controls the ChromeDriver and allows you to drive the browser.
You will need to download the ChromeDriver executable from
http://chromedriver.storage.googleapis.com/index.html
"""
def __init__(self, executable_path="chromedriver", port=0,
options=None, service_args=None,
desired_capabilities=None, service_log_path=None,
chrome_options=None, keep_alive=True):
"""
Creates a new instance of the chrome driver.
Starts the service and then creates new instance of chrome driver.
:Args:
- executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
- port - port you would like the service to run, if left as 0, a free port will be found.
- options - this takes an instance of ChromeOptions
- service_args - List of args to pass to the driver service
- desired_capabilities - Dictionary object with non-browser specific
capabilities only, such as "proxy" or "loggingPref".
- service_log_path - Where to log information from the driver.
- chrome_options - Deprecated argument for options
- keep_alive - Whether to configure ChromeRemoteConnection to use HTTP keep-alive.
"""
if chrome_options:
warnings.warn('use options instead of chrome_options',
DeprecationWarning, stacklevel=2)
options = chrome_options
if options is None:
# desired_capabilities stays as passed in
if desired_capabilities is None:
desired_capabilities = self.create_options().to_capabilities()
else:
if desired_capabilities is None:
desired_capabilities = options.to_capabilities()
else:
desired_capabilities.update(options.to_capabilities())
self.service = Service(
executable_path,
port=port,
service_args=service_args,
log_path=service_log_path)
self.service.start()
try:
RemoteWebDriver.__init__(
self,
command_executor=ChromeRemoteConnection(
remote_server_addr=self.service.service_url,
keep_alive=keep_alive),
desired_capabilities=desired_capabilities)
except Exception:
self.quit()
raise
self._is_remote = False
其構(gòu)造函數(shù)入?yún)xecutable_path默認(rèn)為“chromedriver”,在其init方法中具被,創(chuàng)建了一個(gè)Service類實(shí)例service玻募,executable_path作為了Service類init方法的入?yún)ⅰxecutable_path在WebDriver源碼中僅僅出現(xiàn)在該處一姿,說(shuō)明WebDriver在處理executable_path的過(guò)程中七咧,僅僅只起到傳遞值的作用。實(shí)際處理executable_path并不在WebDriver叮叹。
進(jìn)入Service類源碼艾栋,
class Service(service.Service):
"""
Object that manages the starting and stopping of the ChromeDriver
"""
def __init__(self, executable_path, port=0, service_args=None,
log_path=None, env=None):
"""
Creates a new instance of the Service
:Args:
- executable_path : Path to the ChromeDriver
- port : Port the service is running on
- service_args : List of args to pass to the chromedriver service
- log_path : Path for the chromedriver service to log to"""
self.service_args = service_args or []
if log_path:
self.service_args.append('--log-path=%s' % log_path)
service.Service.__init__(self, executable_path, port=port, env=env,
start_error_message="Please see https://sites.google.com/a/chromium.org/chromedriver/home")
其init方法中將executable_path傳遞給了其父類的init方法,整個(gè)Service類init方法中僅將executable_path傳遞給了父類的init方法蛉顽,未做其他處理蝗砾。
進(jìn)入Service的父類Service源碼,
class Service(object):
def __init__(self, executable, port=0, log_file=DEVNULL, env=None, start_error_message=""):
self.path = executable
self.port = port
if self.port == 0:
self.port = utils.free_port()
if not _HAS_NATIVE_DEVNULL and log_file == DEVNULL:
log_file = open(os.devnull, 'wb')
self.start_error_message = start_error_message
self.log_file = log_file
self.env = env or os.environ
其init方法僅僅只是將executable存儲(chǔ)下來(lái)携冤,存在了self.path中悼粮,到此,executable_path的傳遞過(guò)程就結(jié)束了曾棕,但是我們?nèi)晕粗浪挥迷谑裁吹胤健?/p>
既然executable_path被存儲(chǔ)在了self.path中矮锈,path是Service的一個(gè)實(shí)例屬性,那么它只可能被Service類的方法所使用睁蕾,回顧先前的代碼,WebDriver類創(chuàng)建了Service類的實(shí)例service债朵,緊接著就調(diào)用了service.start()子眶,進(jìn)入start方法,
def start(self):
"""
Starts the Service.
:Exceptions:
- WebDriverException : Raised either when it can't start the service
or when it can't connect to the service
"""
try:
cmd = [self.path]
cmd.extend(self.command_line_args())
self.process = subprocess.Popen(cmd, env=self.env,
close_fds=platform.system() != 'Windows',
stdout=self.log_file,
stderr=self.log_file,
stdin=PIPE)
except TypeError:
raise
except OSError as err:
if err.errno == errno.ENOENT:
raise WebDriverException(
"'%s' executable needs to be in PATH. %s" % (
os.path.basename(self.path), self.start_error_message)
)
elif err.errno == errno.EACCES:
raise WebDriverException(
"'%s' executable may have wrong permissions. %s" % (
os.path.basename(self.path), self.start_error_message)
)
else:
raise
except Exception as e:
raise WebDriverException(
"The executable %s needs to be available in the path. %s\n%s" %
(os.path.basename(self.path), self.start_error_message, str(e)))
count = 0
while True:
self.assert_process_still_running()
if self.is_connectable():
break
count += 1
time.sleep(1)
if count == 30:
raise WebDriverException("Can not connect to the Service %s" % self.path)
在start方法中序芦,主要都是try...except的實(shí)現(xiàn)臭杰。
其中將self.path放在了list類實(shí)例cmd中,并將cmd作為了參數(shù)傳給subprocess.Popen函數(shù)谚中。而subprocess.Popen函數(shù)即相當(dāng)于在命令行執(zhí)行了cmd命令渴杆。
所以為selenium的WebDriver init方法配置executable_path可以有兩種方法:
一:將chromedriver的路徑加入到環(huán)境變量Path中寥枝,而不用給WebDriver的構(gòu)造方法傳遞任何參數(shù),因?yàn)橐呀?jīng)有了默認(rèn)參數(shù)“chromedriver”磁奖;
二:不必配置環(huán)境變量囊拜,直接給WebDriver的init方法傳遞chromedriver的絕對(duì)地址,即WebDriver(executable_path=path)比搭;