ฉันจะถือความเห็นที่ไม่เป็นที่นิยมในแท็ก SO ซีลีเนียมว่าXPath นั้นดีกว่า CSS ในระยะยาว
โพสต์แบบยาวนี้มีสองส่วนก่อนอื่นฉันจะใส่หลักฐานด้านหลังของผ้าเช็ดปากความแตกต่างของประสิทธิภาพระหว่างทั้งสองคือ0.1-0.3 มิลลิวินาที (ใช่นั่นคือ 100 ไมโครวินาที)แล้วฉันจะแบ่งปันความคิดเห็นของฉันว่าทำไม XPath มีประสิทธิภาพมากขึ้น
ความแตกต่างของประสิทธิภาพ
ก่อนอื่นเรามาจัดการกับ "ช้างในห้อง" - xpath นั้นช้ากว่า css
ด้วยพลังซีพียูปัจจุบัน(อ่าน: x86 ทุกอย่างที่ผลิตตั้งแต่ปี 2013)แม้กระทั่งบน browserstack / saucelabs / aws VMs และการพัฒนาเบราว์เซอร์(อ่าน: สิ่งที่เป็นที่นิยมทั้งหมดในช่วง 5 ปีที่ผ่านมา)ซึ่งแทบจะไม่เป็นเช่นนั้น เครื่องมือเบราว์เซอร์ได้มีการพัฒนา, การสนับสนุนของ XPath เป็นชุด, IE เป็นออกจากภาพ(หวังว่าสำหรับส่วนมากของเรา) การเปรียบเทียบนี้ในคำตอบอื่น ๆ กำลังถูกอ้างถึงทั่วทุกที่ แต่มันเป็นไปตามบริบท - มีกี่คนที่กำลังทำงานหรือสนใจ - ระบบอัตโนมัติกับ IE8?
หากมีความแตกต่างก็คือในส่วนของมิลลิวินาที
อย่างไรก็ตามเฟรมเวิร์กระดับสูงกว่าส่วนใหญ่จะเพิ่มค่าโสหุ้ยอย่างน้อย 1ms เหนือการเรียกซีลีเนียมดิบอย่างไรก็ตาม (wrapper, handlers, state storage etc) อาวุธประจำตัวที่ฉันเลือก - RobotFramework - เพิ่มอย่างน้อย 2ms ซึ่งฉันมีความสุขมากกว่าที่จะเสียสละเพื่อสิ่งที่ให้มา บินบนเครือข่ายจาก AWS เราตะวันออก-1 กับฮับ BrowserStack มักจะเป็น11 มิลลิวินาที
ดังนั้นด้วยเบราว์เซอร์ระยะไกลหากมีความแตกต่างระหว่าง xpath และ css มันจะถูกบดบังด้วยสิ่งอื่นใดตามลำดับขนาด
การวัด
มีการเปรียบเทียบสาธารณะไม่มากนัก(ฉันเคยเห็นเพียงตัวเดียวที่อ้างถึงเท่านั้น)ดังนั้นนี่คือกรณีตัวอย่างคร่าวๆแบบจำลองและแบบง่ายๆ
มันจะค้นหาองค์ประกอบตามสองกลยุทธ์ X ครั้งและเปรียบเทียบเวลาเฉลี่ยสำหรับสิ่งนั้น
เป้าหมาย - หน้า Landing Page ของ BrowserStack และปุ่ม "สมัคร" ภาพหน้าจอของ html ขณะเขียนโพสต์นี้:
นี่คือรหัสทดสอบ (python):
from selenium import webdriver
import timeit
if __name__ == '__main__':
xpath_locator = '//div[@class="button-section col-xs-12 row"]'
css_locator = 'div.button-section.col-xs-12.row'
repetitions = 1000
driver = webdriver.Chrome()
driver.get('https://www.browserstack.com/')
css_time = timeit.timeit("driver.find_element_by_css_selector(css_locator)",
number=repetitions, globals=globals())
xpath_time = timeit.timeit('driver.find_element_by_xpath(xpath_locator)',
number=repetitions, globals=globals())
driver.quit()
print("css total time {} repeats: {:.2f}s, per find: {:.2f}ms".
format(repetitions, css_time, (css_time/repetitions)*1000))
print("xpath total time for {} repeats: {:.2f}s, per find: {:.2f}ms".
format(repetitions, xpath_time, (xpath_time/repetitions)*1000))
สำหรับผู้ที่ไม่คุ้นเคยกับ Python - จะเปิดหน้าและค้นหาองค์ประกอบ - อันดับแรกด้วย css locator จากนั้นใช้ xpath การดำเนินการค้นหาซ้ำ 1,000 ครั้ง ผลลัพธ์คือเวลารวมเป็นวินาทีสำหรับการทำซ้ำ 1,000 ครั้งและเวลาเฉลี่ยสำหรับหนึ่งครั้งที่พบในหน่วยมิลลิวินาที
ตัวระบุตำแหน่งคือ:
- สำหรับ xpath - "องค์ประกอบ div ที่มีค่าคลาสที่แน่นอนนี้อยู่ที่ไหนสักแห่งใน DOM";
- css นั้นคล้ายกัน - "องค์ประกอบ div กับคลาสนี้อยู่ที่ไหนสักแห่งใน DOM"
เลือกโดยเจตนาที่จะไม่ปรับแต่งมากเกินไป นอกจากนี้ตัวเลือกคลาสยังถูกอ้างถึงสำหรับ css ว่า "เร็วที่สุดเป็นอันดับสองรองจาก id"
สภาพแวดล้อม - Chrome v66.0.3359.139, chromedriver v2.38, CPU: ULV หลัก M-5Y10 มักจะทำงานที่ 1.5GHz (ใช่ "การประมวลผลคำ" หนึ่งไม่ได้ i7 สัตว์ปกติ)
นี่คือผลลัพธ์:
css total time 1000 repeats: 8.84s, per find: 8.84ms
xpath total time for 1000 repeats: 8.52s, per find: 8.52ms
แน่นอนว่าการกำหนดเวลาต่อการค้นพบนั้นค่อนข้างใกล้เคียงกัน แตกต่างกันคือ0.32 มิลลิวินาที อย่ากระโดด "xpath เร็วกว่า" - บางครั้งก็เป็นบางครั้งก็เป็น css
ลองใช้ตัวระบุตำแหน่งอีกชุดหนึ่งซึ่งซับซ้อนกว่าเล็กน้อย - แอตทริบิวต์ที่มีสตริงย่อย(อย่างน้อยวิธีการทั่วไปสำหรับฉันจะตามหลังคลาสขององค์ประกอบเมื่อส่วนหนึ่งของมันมีความหมายเชิงการทำงาน) :
xpath_locator = '//div[contains(@class, "button-section")]'
css_locator = 'div[class~=button-section]'
ตัวระบุตำแหน่งทั้งสองมีความหมายเหมือนกันอีกครั้ง - "ค้นหาองค์ประกอบ div ที่มีในคลาสแอตทริบิวต์สตริงย่อยนี้"
นี่คือผลลัพธ์:
css total time 1000 repeats: 8.60s, per find: 8.60ms
xpath total time for 1000 repeats: 8.75s, per find: 8.75ms
Diff ของ0.15ms
ในฐานะที่เป็นแบบฝึกหัด - การทดสอบเดียวกันกับที่ทำในบล็อกที่เชื่อมโยงในความคิดเห็น / คำตอบอื่น ๆ - หน้าทดสอบเป็นแบบสาธารณะและรหัสทดสอบก็เช่นกัน
พวกเขากำลังทำสองสิ่งในโค้ด - คลิกที่คอลัมน์เพื่อจัดเรียงจากนั้นรับค่าและตรวจสอบการจัดเรียง UI ว่าถูกต้อง
ฉันจะตัดมัน - แค่หาตัวระบุตำแหน่ง - นี่คือการทดสอบรูทใช่ไหม
รหัสเดียวกับด้านบนโดยมีการเปลี่ยนแปลงเหล่านี้ใน:
css_locator = '#table2 tbody .dues'
xpath_locator = "//table[@id='table2']//tr/td[contains(@class,'dues')]"
และนี่คือผลลัพธ์:
css total time 1000 repeats: 8.24s, per find: 8.24ms
xpath total time for 1000 repeats: 8.45s, per find: 8.45ms
ความแตกต่าง0.2มิลลิวินาที
"การค้นหาองค์ประกอบโดยการข้ามผ่าน":
css_locator = '#table1 tbody tr td:nth-of-type(4)'
xpath_locator = "//table[@id='table1']//tr/td[4]"
ผลลัพธ์:
css total time 1000 repeats: 9.29s, per find: 9.29ms
xpath total time for 1000 repeats: 8.79s, per find: 8.79ms
คราวนี้เป็น0.5มิลลิวินาที (ในทางกลับกัน xpath กลายเป็น "เร็วกว่า" ที่นี่)
5 ปีต่อมา (เอ็นจิ้นเบราว์เซอร์ที่ดีกว่า) และมุ่งเน้นไปที่ประสิทธิภาพของตัวระบุตำแหน่งเท่านั้น (ไม่มีการดำเนินการเช่นการเรียงลำดับใน UI ฯลฯ ) การทดสอบแบบเดียวกันไม่มีความแตกต่างระหว่าง CSS และ XPath ในทางปฏิบัติ
ดังนั้นจาก xpath และ css จะเลือกประสิทธิภาพแบบไหน คำตอบนั้นง่าย - เลือกตำแหน่งของคุณ id
เรื่องสั้นขนาดยาวหาก id ขององค์ประกอบไม่ซ้ำกัน (ตามที่ควรจะเป็นตามข้อกำหนด) ค่าของมันจะมีบทบาทสำคัญในการแสดง DOM ภายในของเบราว์เซอร์และโดยปกติจะเร็วที่สุด
อย่างไรก็ตามรหัสที่ไม่ซ้ำกันและคงที่(เช่นไม่ได้สร้างขึ้นโดยอัตโนมัติ)จะไม่สามารถใช้ได้เสมอไปซึ่งจะนำเราไปสู่ "ทำไมต้องใช้ XPath ถ้ามี CSS"
ข้อได้เปรียบ XPath
ด้วยประสิทธิภาพที่ออกมาจากภาพทำไมฉันคิดว่า xpath ดีกว่า? ง่าย - เก่งกาจและทรงพลัง
Xpath เป็นภาษาที่พัฒนาขึ้นสำหรับการทำงานกับเอกสาร XML ดังนั้นจึงช่วยให้สามารถสร้างโครงสร้างที่มีประสิทธิภาพมากกว่า css
ตัวอย่างเช่นการนำทางในทุกทิศทางในต้นไม้ - ค้นหาองค์ประกอบจากนั้นไปที่ปู่ย่าตายายและค้นหาลูกของมันที่มีคุณสมบัติบางอย่าง
อนุญาตให้ฝังเงื่อนไขบูลีน - cond1 and not(cond2 or not(cond3 and cond4))
; ตัวเลือกที่ฝังไว้ - "ค้นหา div ที่มีลูกเหล่านี้พร้อมคุณสมบัติเหล่านี้จากนั้นนำทางไปตามนั้น"
XPath ช่วยให้การค้นหาตามค่าของโหนด (ข้อความ) - อย่างไรก็ตามการปฏิบัติตามนี้มีประโยชน์ แต่ก็มีประโยชน์โดยเฉพาะอย่างยิ่งในเอกสารที่มีโครงสร้างไม่ดี(ไม่มีแอตทริบิวต์ที่แน่นอนที่ต้องดำเนินการเช่นรหัสและคลาสแบบไดนามิก - ค้นหาองค์ประกอบด้วยข้อความ เนื้อหา) .
การก้าวใน css นั้นง่ายกว่าอย่างแน่นอน - เราสามารถเริ่มเขียนตัวเลือกได้ในเวลาไม่กี่นาที แต่หลังจากใช้งานไปสองสามวันพลังและความเป็นไปได้ของ xpath ก็เอาชนะ css ได้อย่างรวดเร็ว
และเป็นอัตนัยล้วนๆ - css ที่ซับซ้อนอ่านยากกว่านิพจน์ xpath ที่ซับซ้อนมาก
เอาท์โร;)
สุดท้ายเป็นเรื่องส่วนตัวมากอีกครั้ง - จะเลือกอันไหนดี?
IMO ไม่มีทางเลือกที่ถูกหรือผิด - เป็นวิธีแก้ปัญหาที่แตกต่างกันสำหรับปัญหาเดียวกันและควรเลือกอะไรที่เหมาะสมกับงาน
การเป็น "แฟน" ของ XPath ฉันไม่อายที่จะใช้ทั้งสองอย่างในโปรเจ็กต์ของฉัน แต่บางครั้งการโยน CSS ก็เร็วกว่ามากถ้าฉันรู้ว่ามันจะทำงานได้ดี