在 Python 中使用 Selenium 解析 HTML5 数据-* 属性值
Parsing HTML5 data-* attribute values with Selenium in Python
我正在像这样解析 JS 生成的网页:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get('https://www.consumerbarometer.com/en/graph-builder/?question=M1&filter=country:singapore,canada,mexico,brazil,argentina,united_states,bulgaria,austria,belgium,croatia,czech_republic,denmark,estonia,finland,france,germany,greece,hungary,italy,ireland,latvia,lithuania,norway,netherlands,poland,portugal,russia,romania,serbia,slovakia,spain,slovenia,sweden,switzerland,ukraine,united_kingdom,australia,china,israel,hong_kong_sar,japan,korea,new_zealand,malaysia,taiwan,turkey,vietnam')
// wait for svg to appear
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'svg')))
for text in driver.find_elements_by_class_name('bar-text-label'):
print(text.text)
driver.close()
除了从 class bar-text-label
获取 text
之外,我还想从 HTML5 数据属性获取值。例如,<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="76" class="bar"></rect>
,我希望能够从中解析出 76
。
这可以在 Selenium 中实现吗?
我尝试了以下两种方法,但都没有成功:
for text in driver.find_elements_by_class_name('bar'):
print(data_value.text)
for data in driver.find_elements_by_xpath('//*[contains(@data-value)]/@data-value'):
print(data.text)
如果您有如下元素:
<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="75" class="bar">bar1</rect>
<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="76" class="bar">bar2</rect>
获取文本值和属性值如下:
elements = driver.find_elements_by_class_name('bar')
for element in elements:
print element.text
print element.get_attribute('data-value')
打印出来:
bar1
75
bar2
76
你提到你尝试过:
for text in driver.find_elements_by_class_name('bar'):
print(data_value.text)
鉴于 data_value
未在任何地方定义,它不会起作用。如果你做了 print(text.text)
,你应该得到每个有 bar
class 的元素的文本。 (这基本上就是您在第一个片段中所做的。)
你也提到这个:
for data in driver.find_elements_by_xpath('//*[contains(@data-value)]/@data-value'):
print(data.text)
这行不通,因为 Selenium 的 find_element(s)...
函数不能 return 除了元素或元素列表 以外的任何东西。您正试图将其设置为 return 一个属性,但这是行不通的。 XPath 通常允许它,但是当您通过 Selenium 使用 XPath 时,您只能获得元素。
您可以做 或:
results = driver.execute_script("""
var els = document.getElementsByClassName("bar");
var ret = [];
for (var i =0, el; (el = els[i]); ++i) {
ret.push([el.textContent, el.attributes["data-value"].value]);
}
return ret;
""")
for r in results:
print(r[0], r[1])
这将在您的脚本和浏览器之间进行一次往返。循环和使用 .text
和 .get_attribute()
每次迭代涉及 2 次往返。 JavasScript 构建了一个结果对列表。每对在第一个位置包含元素的文本,在第二个位置包含 data-value
的值。
我正在像这样解析 JS 生成的网页:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get('https://www.consumerbarometer.com/en/graph-builder/?question=M1&filter=country:singapore,canada,mexico,brazil,argentina,united_states,bulgaria,austria,belgium,croatia,czech_republic,denmark,estonia,finland,france,germany,greece,hungary,italy,ireland,latvia,lithuania,norway,netherlands,poland,portugal,russia,romania,serbia,slovakia,spain,slovenia,sweden,switzerland,ukraine,united_kingdom,australia,china,israel,hong_kong_sar,japan,korea,new_zealand,malaysia,taiwan,turkey,vietnam')
// wait for svg to appear
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'svg')))
for text in driver.find_elements_by_class_name('bar-text-label'):
print(text.text)
driver.close()
除了从 class bar-text-label
获取 text
之外,我还想从 HTML5 数据属性获取值。例如,<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="76" class="bar"></rect>
,我希望能够从中解析出 76
。
这可以在 Selenium 中实现吗?
我尝试了以下两种方法,但都没有成功:
for text in driver.find_elements_by_class_name('bar'):
print(data_value.text)
for data in driver.find_elements_by_xpath('//*[contains(@data-value)]/@data-value'):
print(data.text)
如果您有如下元素:
<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="75" class="bar">bar1</rect>
<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="76" class="bar">bar2</rect>
获取文本值和属性值如下:
elements = driver.find_elements_by_class_name('bar')
for element in elements:
print element.text
print element.get_attribute('data-value')
打印出来:
bar1
75
bar2
76
你提到你尝试过:
for text in driver.find_elements_by_class_name('bar'):
print(data_value.text)
鉴于 data_value
未在任何地方定义,它不会起作用。如果你做了 print(text.text)
,你应该得到每个有 bar
class 的元素的文本。 (这基本上就是您在第一个片段中所做的。)
你也提到这个:
for data in driver.find_elements_by_xpath('//*[contains(@data-value)]/@data-value'):
print(data.text)
这行不通,因为 Selenium 的 find_element(s)...
函数不能 return 除了元素或元素列表 以外的任何东西。您正试图将其设置为 return 一个属性,但这是行不通的。 XPath 通常允许它,但是当您通过 Selenium 使用 XPath 时,您只能获得元素。
您可以做
results = driver.execute_script("""
var els = document.getElementsByClassName("bar");
var ret = [];
for (var i =0, el; (el = els[i]); ++i) {
ret.push([el.textContent, el.attributes["data-value"].value]);
}
return ret;
""")
for r in results:
print(r[0], r[1])
这将在您的脚本和浏览器之间进行一次往返。循环和使用 .text
和 .get_attribute()
每次迭代涉及 2 次往返。 JavasScript 构建了一个结果对列表。每对在第一个位置包含元素的文本,在第二个位置包含 data-value
的值。