python - 使用 Selenium 抓取嵌套的点击迷宫
问题描述
我一直在尝试使用 Selenium 抓取 cookie 设置横幅。我想创建一个适用于多个网站的刮板,而无需为每个网站单独调整它。
让我们以https://faz.net的 cookie-settings 横幅为例。我想从这个横幅中提取所有 cookie 的名称。问题是您必须通过单击几个“按钮”和“div”元素来浏览横幅才能加载 HTML。然而,简单地递归地点击所有“button”或“div”元素是行不通的,因为点击会加载或卸载其他“button”和“div”元素。
你对如何解决这个问题有什么建议吗?
这是导航到https://faz.net的 cookie-settings 横幅的 python 代码:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("https://faz.net")
wait = WebDriverWait(driver, 10)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[contains(@title,'SP')]")))
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "[title='EINSTELLUNGEN']"))).click()
解决方案
cookie 横幅似乎具有三个主要标题(在本例中:Zwecke
、Funktionen
和Partner
),每个标题可能包含两个直接子切换,然后是下拉菜单。下拉列表可以有以表格格式或在子切换下列出的 cookie。此解决方案单击每个标题,触发子按钮(如果存在),并切换每个下拉菜单:
from selenium import webdriver
import time
from bs4 import BeautifulSoup as soup
d = webdriver.Chrome('path/to/chromedriver')
d.get('https://www.faz.net/aktuell/')
d.switch_to.frame(d.execute_script('return document.querySelector("#sp_message_iframe_510204")'))
d.execute_script('''document.querySelector('button[title="EINSTELLUNGEN"]').click()''')
time.sleep(2)
d.switch_to.default_content()
d.switch_to.frame(d.execute_script('return document.querySelector("#sp_message_iframe_192912")'))
results = []
for label in d.execute_script("""
function* get_labels(){
for (var i of document.querySelectorAll('div.pm-tab.focusable')){
yield i.getAttribute('aria-label').toString()
}
}
return [...get_labels()]
"""):
d.execute_script(f'''document.querySelector('div[role="tab"][aria-label="{label}"]').click()''')
time.sleep(1)
for i in range(1, d.execute_script('''
return Array.from(document.querySelectorAll('div.pm-type-toggle > div')).length
''')+1):
d.execute_script(f'''document.querySelector('div.pm-type-toggle > div:nth-of-type({i})').click()''')
time.sleep(1)
d.execute_script('''
for (var j of document.querySelectorAll('.accordion')){
j.click();
}
for (var x of document.querySelectorAll('.toggle-vendor')){
if (x.querySelector('table') != null){
x.click();
}
}''')
for tbl in soup(d.page_source, 'html.parser').select('table.tvtbl'):
h, *vals = tbl.select('tr')
hvals = [t.get_text(strip=True) for t in h]
results.extend([dict(zip(hvals, [y.get_text(strip=True) for y in td])) for td in vals])
输出(来自 的前十个 cookie results
):
print(results[:10])
输出:
[{'Cookie': 'b', 'Domain': '.blismedia.com', 'Dauer': '1 Jahr(e)'}, {'Cookie': 'id', 'Domain': '', 'Dauer': ''}, {'Cookie': 'fc', 'Domain': '.turn.com', 'Dauer': '180 Tag(e)'}, {'Cookie': 'optOut', 'Domain': '.turn.com', 'Dauer': '24855 Tag(e)'}, {'Cookie': 'clk', 'Domain': '.turn.com', 'Dauer': '180 Tag(e)'}, {'Cookie': 'bito', 'Domain': '.bidr.io', 'Dauer': '21 Stunde(n)'}, {'Cookie': 'bitoIsSecure', 'Domain': '.bidr.io', 'Dauer': '21 Stunde(n)'}, {'Cookie': 'b', 'Domain': '.blismedia.com', 'Dauer': '1 Jahr(e)'}, {'Cookie': 'id', 'Domain': '', 'Dauer': ''}, {'Cookie': 'b', 'Domain': '.blismedia.com', 'Dauer': '1 Jahr(e)'}]
将结果加载到pandas
:
import pandas as pd
df = pd.DataFrame(results)
print(df)
Cookie Domain Dauer Category
0 b .blismedia.com 1 Jahr(e) NaN
1 id NaN
2 fc .turn.com 180 Tag(e) NaN
3 optOut .turn.com 24855 Tag(e) NaN
4 clk .turn.com 180 Tag(e) NaN
.. ... ... ... ...
580 _sp_v1_lt .faz.net 30 Tag(e) Notwendige Technologien
581 _sp_v1_opt .faz.net 30 Tag(e) Notwendige Technologien
582 _sp_v1_ss .faz.net 30 Tag(e) Notwendige Technologien
583 _sp_v1_uid consent.faz.net 30 Tag(e) Notwendige Technologien
584 consentUUID .faz.net 365 Tag(e) Notwendige Technologien
[585 rows x 4 columns]
推荐阅读
- javascript - Date 的构造函数在修剪和未修剪的字符串上的行为不同
- php - 需要帮助将表单从 HTML 传递到 PHP
- powershell - 变量赋值中括号前的逗号
- r - 基于多行日期的子集数据
- javascript - Material UI 为 React js 项目提供的选项卡中的导航问题
- python - 如何创建 x 值为日期时间对象的 BSpline 或 polyfit 图?
- python - 尝试从 youtube api 获取数据的 Python 错误
- python-3.x - (Python) 按日期查询,在 mongoDB 集合中存储为字符串
- redis - Redis ha helm chart 错误 - NOREPLICAS 没有足够好的副本来编写
- amazon-web-services - 在 Amazon Redshift 上从 `pg_table_def` 中选择 count(*) 需要几分钟