Зацикливание заголовков div и извлечение тегов li для каждого тега заголовка - PullRequest
0 голосов
/ 22 сентября 2018

Я пытаюсь почистить веб-страницу, в которой используются объекты JS.

Я использую Selenium в среде Python;Я использую селен, чтобы загрузить то, что я хочу, то есть текст «ПРОСМОТРЕТЬ ВЫБОР ТВ ПАКЕТА», который запускает модальный контейнер.

enter image description here

В этом контейнере, есть заголовки пакетов, с каналами под ними.Я пытаюсь перебрать каждый заголовок и захватить названия каналов в каждом.

Это веб-страница

Вот мой код, который поможет вам перейти к контейнеру, который я пытаюсь очистить:

from selenium import webdriver
import pandas as pd


url = "https://www.rogers.com/consumer/tv#/packages"

#create a new Chrome session
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get(url)

#change the province to Ontario
province_button = driver.find_element_by_class_name("dropdown-toggle")
province_button.click() #clicks dropdown
province_button = driver.find_element_by_link_text("Ontario")
province_button.click() #clicks dropdown

#visit TV portal page, re-init url again
driver.get(url)


#####BEGIN SCRAPING PACKAGE INFO#####

#open Select Package window 
package_button = driver.find_element_by_class_name("Package-details")
package_button.click() #clicks dropdown

package_data = driver.find_elements_by_class_name("Package-channels")

package_data var возвращает все мои заголовки и названия каналов;но не указание того, какие строки были заголовками, а какие - каналами.Я знаю, что мог бы написать какое-то сложное регулярное выражение, чтобы добиться цели, но я надеюсь на динамический подход.Любой совет приветствуется.Спасибо!

****** РЕДАКТИРОВАНИЕ *******

В комментариях ниже приведен код, который переводит WebElements в переменную вместо вывода в консоль:

select_package_data = [] 

headingsCount = len(driver.find_elements_by_xpath("//div[@class='modal- 
content']//*[contains(@class,'Package-channels--heading ng-binding')]"))

for index in range(headingsCount):
    head = driver.find_element_by_xpath("//div[@class='modal-content']//* 
    [contains(@class,'Package-channels--heading ng-binding')] 
    [index]".replace('index',str(index+1)))

    select_package_data.append(head.text)

    channelsPerheading = driver.find_elements_by_xpath("(//div[@class='modal- 
    content']//ul[@ng-if='vm.channels'])[index]/li[not 
    (contains(@class,'Package-channels--heading ng- 
    binding'))]".replace('index',str(index+1)))

    temp_list=[]

for channel in channelsPerheading:
    temp_list.append(channel.text.encode('utf-8'))
select_package_data.insert((index+1), temp_list[:])`

********* РЕДАКТИРОВАНИЕ V2 ЗА КОММЕНТАРИИ: *********

Окончательный код требует добавления скобок в методе xpath;Я полагаю, что это связано с [index], добавленным в конец фактического xpath при назначении его переменной:

#get the count of headings in the modal contaier
headingsCount = len(driver.find_elements_by_xpath("//div[@class='modal- 
content']//*[contains(@class,'Package-channels--heading ng-binding')]"))

#use this count as an iterator
for index in range(headingsCount):

#get the first heading - we use replace method bc xpath is not zero-indexed
head = driver.find_element_by_xpath("(//div[@class='modal-content']//* 
[contains(@class,'Package-channels--heading ng-binding')]) 
[index]".replace('index',str(index+1)))

header_placeholder = head.text 
##takes heading element as text to use for dataframe row index label 

#goes to //ul tag in accordance with current index, finds all BUT the 
#headings
channelsPerheading = driver.find_elements_by_xpath("(//div[@class='modal- 
content']//ul[@ng-if='vm.channels'])[index]/li[not 
(contains(@class,'Package-channels--heading ng- 
binding'))]".replace('index',str(index+1)))

temp_list=[]

for channel in channelsPerheading: #append the channels as text to a temp 
list
    temp_list.append(channel.text.encode('utf-8'))

1 Ответ

0 голосов
/ 22 сентября 2018

Самый простой способ получить все заголовки и каналы в модальном окне - использовать приведенные ниже xpaths.Кроме того, ниже xpaths являются динамическими и не жестко закодированы.Даже если новые каналы или заголовки будут добавлены в будущем, эти xpath-ы все равно будут работать.

headings = driver.find_elements_by_xpath("//div[@class='modal-content']//*[contains(@class,'Package-channels--heading ng-binding')]")
print('all headings: '+str(len(headings)))

channels= driver.find_elements_by_xpath("//div[@class='modal-content']//a[contains(@class,'PackageChannelImage')]")
print('all channels: '+str(len(channels)))

Вывод:

all headings: 17
all channels: 243

Вы можете использовать приведенный ниже подход для извлечения каналов по заголовку ираспечатайте их.

headingsCount = len(driver.find_elements_by_xpath("//div[@class='modal-content']//*[contains(@class,'Package-channels--heading ng-binding')]"))

for index in range(headingsCount):
    print('For heading: '+ driver.find_element_by_xpath("(//div[@class='modal-content']//*[contains(@class,'Package-channels--heading ng-binding')])[index]".replace('index',str(index+1))).text+', Channels are:')
    channelsPerheading = driver.find_elements_by_xpath("(//div[@class='modal-content']//ul[@ng-if='vm.channels'])[index]/li[not (contains(@class,'Package-channels--heading ng-binding'))]".replace('index',str(index+1)))
    for channel in channelsPerheading:
        print(channel.text.encode('utf-8').strip())

Я вставил вывод здесь

...