Selenium очищает те же заголовки, субтитры и ссылки с веб-страницы The Sun Football

Я столкнулся с проблемой при очистке заголовков новостей, субтитров и ссылок с веб-сайта The Sun Football с помощью Selenium. Несмотря на, казалось бы, правильную реализацию XPath для выбора нужных элементов (div[@class = "teaser__copy-container"] для контейнеров, span[@class = "teaser__headline teaser__kicker t-p-color"] для заголовков и h3[@class = "teaser__subdeck"] для субтитров), я последовательно извлекаю одни и те же данные для всех новостей.

Фрагмент кода

from selenium import webdriver
from selenium.webdriver.firefox.service import Service # Using Firefox service

import pandas as pd

# Website URL for news scraping
website = "https://www.thesun.co.uk/sport/football/"

# Path to the GeckoDriver executable
path = "/Users/dada/AutomationProjects/drivers/geckodriver.exe"

# Configure Firefox service with GeckoDriver path
service = Service(executable_path=path)

# Initialise Firefox WebDriver using the service
driver = webdriver.Firefox(service=service)

# Open the desired website
driver.get(website)

containers = driver.find_elements(by = "xpath", value='//div[@class = "teaser__copy-container"]')

titles = []
subtitles = []
links = []

for container in containers:
    title = container.find_element(by = "xpath", value='//div[@class = "teaser__copy-container"]/a/span[@class = "teaser__headline teaser__kicker t-p-color"]').get_attribute("data-original-text")
    subtitle = container.find_element(by = "xpath", value='//div[@class = "teaser__copy-container"]/a/h3[@class = "teaser__subdeck"]').get_attribute("data-original-text")
    link = container.find_element(by = "xpath", value='//div[@class = "teaser__copy-container"]/a').get_attribute("href")
    titles.append(title)
    subtitles.append(subtitle)
    links.append(link)

dict = {'Titles' : titles, 'Subtitles' : subtitles, 'Links' : links}

headlines_df = pd.DataFrame(dict)
print(headlines_df)

Проверенные XPath: я дважды проверил XPath с помощью инструментов разработчика браузера, чтобы убедиться, что они точно нацелены на нужные элементы. Проблема сохраняется. Я по-прежнему извлекаю те же заголовки, субтитры и ссылки, несмотря на этап устранения неполадок.

Версия селена: 4.19.0 | Версия Python: 3.9.19 | Окружающая среда: блокнот Jupyter.

Я буду признателен за любую информацию или предложения, которые помогут мне определить основную причину этой проблемы и успешно скопировать отдельные заголовки, субтитры и ссылки с веб-сайта The Sun Football.

🤔 А знаете ли вы, что...
Python подходит для начинающих программистов благодаря своей простоте и читаемости кода.


63
1

Ответ:

Решено

Да... есть одна "странная" вещь, которую приходится делать с XPath при поиске по существующему элементу. Вместо

link = container.find_element(By.XPATH, '//div[@class = "teaser__copy-container"]/a')

вам нужно добавить '.' к началу XPath, например.

link = container.find_element(By.XPATH, './/div[@class = "teaser__copy-container"]/a')
                                         ^ period added here

Это применимо только к XPath и только тогда, когда вы используете .find_element() из элемента. Например, driver.find_element() работает нормально, но element.find_element() требует '.'. Это должно решить ваши проблемы.


Оказывается, ваши локаторы названия и т. д. были неправильными. Я обновил и упростил их. Полный рабочий код приведен ниже.

from selenium import webdriver
from selenium.webdriver.common.by import By

import pandas as pd

# Website URL for news scraping
website = "https://www.thesun.co.uk/sport/football/"

# Initialise Firefox WebDriver using the service
driver = webdriver.Firefox()
driver.maximize_window()

# Open the desired website
driver.get(website)

containers = driver.find_elements(By.XPATH, '//div[@class = "teaser__copy-container"][./a]')

titles = []
subtitles = []
links = []
for container in containers:
    title = container.find_element(By.CSS_SELECTOR, 'a > span').get_attribute("data-original-text")
    subtitle = container.find_element(By.CSS_SELECTOR, 'a > h3').get_attribute("data-original-text")
    link = container.find_element(By.CSS_SELECTOR, 'a').get_attribute("href")
    titles.append(title)
    subtitles.append(subtitle)
    links.append(link)

dict = {'Titles' : titles, 'Subtitles' : subtitles, 'Links' : links}

headlines_df = pd.DataFrame(dict)
print(headlines_df)

Это выводит

           Titles                                          Subtitles                                              Links
0      OF HIS ILK   Gundogan's glam wife enters row with Barca st...  https://www.thesun.co.uk/sport/27404398/ilkay-...
1       NICE TUCH   Bayern president hails Tuchel for 'tactical m...  https://www.thesun.co.uk/sport/27402309/bayern...
...

Дополнительный отзыв

  1. Начиная с Selenium 4.6 вам больше не нужно загружать, настраивать и поддерживать собственные драйверы. Был добавлен Selenium Manager, который автоматически загрузит и установит для вас драйверы, соответствующие установленному вами браузеру. Итак, ваш первоначальный код можно упростить до

    from selenium import webdriver
    
    website = "https://www.thesun.co.uk/sport/football/"
    driver = webdriver.Firefox()
    driver.get(website)
    
  2. Предпочтительный способ написать .find_element() звонок:

    from selenium.webdriver.common.by import By
    
    driver.find_element(By.XPATH, '//div[@class = "teaser__copy-container"]/a')
    

    Ваш способ будет работать, но он подвержен опечаткам, и ваша IDE не узнает об опечатках, пока вы не запустите сценарий и он не завершится неудачно. Использование By.XPATH и т. д. позволяет избежать опечаток в типе локатора, а ваша IDE поможет вам автоматически заполнить его. Если есть опечатки, IDE пометит их как ошибки перед запуском, что сэкономит ваше время.


Поскольку вы запросили XPath, элементы containers уже найдены с помощью XPath. Приведенный ниже код должен позаботиться обо всем остальном.

title = container.find_element(By.XPATH, './a/span').get_attribute("data-original-text")
subtitle = container.find_element(By.XPATH, './a/h3').get_attribute("data-original-text")
link = container.find_element(By.XPATH, './a').get_attribute("href")