首页 > 解决方案 > 使用 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()

标签: pythonhtmlseleniumdomweb-scraping

解决方案


cookie 横幅似乎具有三个主要标题(在本例中:ZweckeFunktionenPartner),每个标题可能包含两个直接子切换,然后是下拉菜单。下拉列表可以有以表格格式或在子切换下列出的 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]

推荐阅读