電影網(wǎng)站制作畢業(yè)論文摘要工具站seo
前言
使用Selenium 創(chuàng)建多個(gè)瀏覽器,這在自動(dòng)化操作中非常常見。
而在Python中,使用 Selenium + threading 或 Selenium + ThreadPoolExecutor 都是很好的實(shí)現(xiàn)方法。
應(yīng)用場(chǎng)景:
- 創(chuàng)建多個(gè)瀏覽器用于測(cè)試或者數(shù)據(jù)采集;
- 使用Selenium 控制本地安裝的 chrome瀏覽器 去做一些操作
- …
文章提供了 Selenium + threading 和 Selenium + ThreadPoolExecutor 結(jié)合的代碼模板,拿來(lái)即用。
知識(shí)點(diǎn)📖📖
上面兩個(gè)都是 Python 內(nèi)置模塊,無(wú)需手動(dòng)安裝~
導(dǎo)入模塊
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
多線程還是線程池?
在Selenium中,使用 多線程 或者是 線程池,差別并不大。主要都是網(wǎng)絡(luò)I/O的操作。
在使用 ThreadPoolExecutor 的情況下,任務(wù)將被分配到不同的線程中執(zhí)行,從而提高并發(fā)處理能力。與使用 threading 模塊相比,使用 ThreadPoolExecutor 有以下優(yōu)勢(shì):
- 更高的并發(fā)處理能力:線程池 可以動(dòng)態(tài)地調(diào)整線程數(shù)量,以適應(yīng)任務(wù)的數(shù)量和處理要求,從而提高并發(fā)處理能力。
- 更好的性能:線程池 可以根據(jù)任務(wù)的類型和大小動(dòng)態(tài)地調(diào)整線程數(shù)量,從而提高性能和效率。
- …
總之,使用 線程池 可以提高并發(fā)處理能力,更易于管理,并且可以提供更好的性能和效率。
但是選擇多線程,效果也不差。
所以使用哪個(gè)都不必糾結(jié),哪個(gè)代碼量更少就選哪個(gè)自然是最好的。
多個(gè)瀏覽器?
Selenium自動(dòng)化中需要多個(gè)瀏覽器,屬于是非常常見的操作了。
不管是用于自動(dòng)化測(cè)試、還是爬蟲數(shù)據(jù)采集,這都是個(gè)可行的方法。
這里示例的代碼中,線程池的運(yùn)行時(shí)候只有 多線程 的一半!!!
多線程與 多 瀏覽器🧨
這份代碼的應(yīng)用場(chǎng)景會(huì)廣一些,后續(xù)復(fù)用修改一下 browser_thread 函數(shù)的邏輯就可以了。
這里模擬相對(duì)復(fù)雜的操作,在創(chuàng)建的瀏覽器中新打開一個(gè)標(biāo)簽頁(yè),用于訪問(wèn)指定的網(wǎng)站。
然后切換到新打開的標(biāo)簽頁(yè),進(jìn)行截圖。
代碼釋義:
- 定義一個(gè)名為 start_browser 的函數(shù),用于創(chuàng)建 webdriver.Chrome 對(duì)象。
- 定義一個(gè)名為 browser_thread 的函數(shù),接受一個(gè) webdriver.Chrome 對(duì)象和一個(gè)整數(shù)作為參數(shù),用于打開指定網(wǎng)頁(yè)并截圖。 切換到最后一個(gè)窗口,然后截圖。
- main函數(shù)創(chuàng)建了5個(gè)瀏覽器,5個(gè)線程,執(zhí)行上面的操作,然后等待所有線程執(zhí)行完畢。
# -*- coding: utf-8 -*-
# Name: multi_thread.py
# Author: 小月
# Date: 2023/10/26 20:00
# Description:
import threading
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
def start_browser():
service = ChromeService(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
return driver
def browser_thread(driver: webdriver.Chrome, idx: int):
url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']
try:
driver.execute_script(f"window.open('{url_list[idx]}')")
driver.switch_to.window(driver.window_handles[-1])
driver.save_screenshot(f'{idx}.png')
return True
except Exception:
return False
def main():
for idx in range(5):
driver = start_browser()
threading.Thread(target=browser_thread, args=(driver, idx)).start()
# 等待所有線程執(zhí)行完畢
for thread in threading.enumerate():
if thread is not threading.current_thread():
thread.join()
if __name__ == "__main__":
main()
運(yùn)行結(jié)果
- 運(yùn)行時(shí)長(zhǎng)在9.28秒(速度與網(wǎng)絡(luò)環(huán)境有很大關(guān)系,木桶效應(yīng),取決于最后運(yùn)行完成的瀏覽器
- 看到程序運(yùn)行完成后,多出了5張截圖。
線程池與 多 瀏覽器🎍
這份代碼與 多線程與 多瀏覽器 的操作基本一致。速度上卻比多線程節(jié)省了一半。
# -*- coding: utf-8 -*-
# Name: demo2.py
# Author: 小月
# Date: 2023/10/26 20:00
# Description:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from concurrent.futures import ThreadPoolExecutor, as_completed
MAX_WORKERS = 5
service = ChromeService(ChromeDriverManager().install())
def start_browser():
driver = webdriver.Chrome(service=service)
return driver
def browser_task(driver: webdriver.Chrome, idx: int):
url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']
try:
driver.execute_script(f"window.open('{url_list[idx]}')")
driver.switch_to.window(driver.window_handles[-1])
driver.save_screenshot(f'{idx}.png')
return True
except Exception:
return False
def main():
executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
ths = list()
for idx in range(5):
driver = start_browser()
th = executor.submit(browser_task, driver, idx=idx)
ths.append(th)
# 獲取結(jié)果
for future in as_completed(ths):
print(future.result())
if __name__ == "__main__":
main()
運(yùn)行結(jié)果
- 運(yùn)行時(shí)長(zhǎng)在4.5秒(運(yùn)行效果圖不是很匹配,但確實(shí)是比多線程快很多。
- 看到程序運(yùn)行完成后,多出了5張截圖。
多個(gè)標(biāo)簽頁(yè)
這個(gè)的應(yīng)用場(chǎng)景有點(diǎn)意思。
這里的操作與上面的 多個(gè)瀏覽器其實(shí)是差不多的。
區(qū)別在于:上面打開多個(gè)瀏覽器,這里打開多個(gè)標(biāo)簽頁(yè)。
所以這個(gè)需要考量一個(gè)問(wèn)題:資源爭(zhēng)奪。與是這里用上了 threading.Lock 鎖,用以保護(hù)資源線程安全。
多線程與 多 標(biāo)簽頁(yè)🎃
代碼釋義:
與上面差不多,不解釋了。
# -*- coding: utf-8 -*-
# Name: demo2.py
# Author: 小月
# Date: 2023/10/26 20:00
# Description:
import threading
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
service = ChromeService(ChromeDriverManager().install())
lock = threading.Lock()
def start_browser():
driver = webdriver.Chrome(service=service)
return driver
def browser_thread(driver: webdriver.Chrome, idx: int):
url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']
try:
lock.acquire()
driver.execute_script(f"window.open('{url_list[idx]}')")
driver.switch_to.window(driver.window_handles[idx + 1])
driver.save_screenshot(f'{idx}.png')
return True
except Exception:
return False
finally:
lock.release()
def main():
driver = start_browser()
for idx in range(5):
threading.Thread(target=browser_thread, args=(driver, idx)).start()
# 等待所有線程執(zhí)行完畢
for thread in threading.enumerate():
if thread is not threading.current_thread():
thread.join()
if __name__ == "__main__":
main()
運(yùn)行結(jié)果
線程池與 多 標(biāo)簽頁(yè)👀
這里不展示運(yùn)行結(jié)果了,因?yàn)樾Чc 多線程與 多 標(biāo)簽頁(yè) 一致。
# -*- coding: utf-8 -*-
# Name: thread_pool.py
# Author: 小月
# Date: 2023/10/26 20:00
# Description:
import time
import threading
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from concurrent.futures import ThreadPoolExecutor, as_completed
MAX_WORKERS = 5
service = ChromeService(ChromeDriverManager().install())
lock = threading.Lock()
def start_browser():
driver = webdriver.Chrome(service=service)
return driver
def browser_task(driver: webdriver.Chrome, idx: int):
url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']
try:
lock.acquire()
driver.execute_script(f"window.open('{url_list[idx]}')")
driver.switch_to.window(driver.window_handles[idx + 1])
driver.save_screenshot(f'{idx}.png')
return True
except Exception:
return False
finally:
lock.release()
def main():
driver = start_browser()
executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
ths = list()
for idx in range(5):
th = executor.submit(browser_task, driver, idx=idx)
ths.append(th)
# 獲取結(jié)果
for future in as_completed(ths):
print(future.result())
if __name__ == "__main__":
st = time.time()
main()
et = time.time()
print(et - st)
總結(jié)??
本文章介紹了 Selenium + threading 和 Selenium + ThreadPoolExecutor 來(lái)創(chuàng)建多個(gè)瀏覽器或多個(gè)標(biāo)簽頁(yè)的操作。
文中示例的代碼比較簡(jiǎn)單,所以 線程池 比 多線程 運(yùn)行的更加快。
但在實(shí)際的使用過(guò)程中,可以根據(jù)自己的喜好去選擇 線程池 還是 多線程 。
后話
本次分享到此結(jié)束,
see you~🐱?🏍🐱?🏍