【问题标题】:Loop div headings and retrieve li tags for every heading tag循环 div 标题并检索每个标题标签的 li 标签
【发布时间】:2025-11-29 14:25:01
【问题描述】:

我正在尝试抓取使用 JS 对象的网页。

我在 Python 环境中使用 Selenium;我使用 selenium 加载我想要的内容,即启动模式容器的“查看选择电视包详细信息”文本。

在这个容器中,有包标题,下面有通道。我正在尝试遍历每个标题,并在每个标题中获取频道名称。

这是webpage

这是我的代码,它将帮助您导航到我试图抓取的容器:

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 返回我所有的标题和频道名称;但没有指明哪些字符串是标题,哪些是频道。我知道我可以编写一些复杂的正则表达式来解决问题,但我希望采用动态方法。任何建议表示赞赏。谢谢!

******已编辑*******

下面的每个 cmets,下面是将 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'))

【问题讨论】:

    标签: python html selenium web-scraping selenium-chromedriver


    【解决方案1】:

    在模态窗口中获取所有标题和频道的最简单方法是使用以下 xpath。此外,下面的 xpath 是动态的,不是硬编码的。即使将来添加了新的频道或标题,这些 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())
    

    我已经粘贴了输出here

    【讨论】:

    • 感谢@Kireeti 澄清用于拉取headingschannels 的xpath 语法。我正在尝试组织数据以表示哪个channels 属于每个heading。例如在上面的屏幕截图中:Family 标题包含 5 个频道;那些是 2 树屋和 3 YTV。是否有解决此问题的迭代方法,即对于每个标题,返回其下方的频道标签?
    • 感谢@KireetiAnnamaraj,xpath 语法和 add'l 方法成功地将其打印到控制台。我已经调整了您的代码以将文本输出到列表数据结构,但是 find_element_by_xpath 用于标题,对于任何高于 1 的索引返回 NoSuchElementException。打印时不是的情况安慰
    • 我已经用我正在使用的代码编辑了上面的 OP - 感谢任何反馈,谢谢!
    • 嗨@MarkSamuel,你需要这样使用xpath:(//div[@class='modal-content']//*[contains(@class,'Package-channels--heading ng-binding')]) [index]。为标题。可以试试吗?
    • 是的,将 xpath 包含在 () 中,然后我们可以使用 [index] 遍历使用该 xpath 找到的所有元素,其中索引从 '1' 开始,不像我们的编程数组以'0' 开始