【问题标题】:Using Selenium to scrape a table across multiple pages when the url doesn't change当 url 不变时,使用 Selenium 跨多个页面抓取表格
【发布时间】:2017-03-06 20:33:12
【问题描述】:

我一直在尝试编写一个程序来从 www.whoscored.com 抓取统计数据并创建一个 pandas 数据框。

我在 crookedleaf 的帮助下更新了代码,这是工作代码:

import time
import pandas as pd
from pandas.io.html import read_html
from pandas import DataFrame
from selenium import webdriver

driver = webdriver.Firefox()
driver.get('https://www.whoscored.com/Regions/252/Tournaments/2/Seasons/6335/Stages/13796/PlayerStatistics/England-Premier-League-2016-2017')

summary_stats = DataFrame()

while True:

    while driver.find_element_by_xpath('//*[@id="statistics-table-summary"]').get_attribute('class') == 'is-updating': # driver.find_element_by_xpath('//*[@id="statistics-table-summary-loading"]').get_attribute('style') == 'display; block;' or
        time.sleep(1)

    table = driver.find_element_by_xpath('//*[@id="statistics-table-summary"]')
    table_html = table.get_attribute('innerHTML')
    page_number = driver.find_element_by_xpath('//*[@id="currentPage"]').get_attribute('value')
    print('Page ' + page_number)
    df1 = read_html(table_html)[0]
    summary_stats = pd.concat([summary_stats, df1])
    next_link = driver.find_element_by_xpath('//*[@id="next"]')

    if 'disabled' in next_link.get_attribute('class'):
        break

    next_link.click()

print(summary_stats)

driver.close()

现在我正在尝试从其他选项卡收集统计信息。我真的很接近,但是当代码应该退出循环时,它并没有退出循环。下面是代码:

defensive_button = driver.find_element_by_xpath('//*[@id="stage-top-player-stats-options"]/li[2]/a')
defensive_button.click()

defensive_stats = DataFrame()

while True:

    while driver.find_element_by_xpath('//*[@id="statistics-table-defensive"]').get_attribute('class') == 'is-updating': # driver.find_element_by_xpath('//*[@id="statistics-table-summary-loading"]').get_attribute('style') == 'display; block;' or
        time.sleep(1)

    table = driver.find_element_by_xpath('//*[@id="statistics-table-defensive"]')
    table_html = table.get_attribute('innerHTML')
    page_number = driver.find_element_by_xpath('//*[@id="statistics-paging-defensive"]/div/input[1]').get_attribute('value')
    print('Page ' + page_number)
    df2 = read_html(table_html)[0]
    defensive_stats = pd.concat([defensive_stats, df2])
    next_link = driver.find_element_by_xpath('//*[@id="statistics-paging-defensive"]/div/dl[2]/dd[3]')

    if 'disabled' in next_link.get_attribute('class'):
        break

    next_link.click()

print(defensive_stats)

此代码循环遍历所有页面,然后继续循环遍历最后一页

【问题讨论】:

    标签: python selenium web webdriver screen-scraping


    【解决方案1】:

    您是在循环之外定义表格的代码。您正在导航到下一页,但没有重新定义您的 tabletable_html 元素。将它们移到while True之后的第一行

    编辑:对代码进行更改后,我的猜测是由于表格的动态加载内容,您无法处理更改或由于“加载”图形覆盖而无法获取内容。另一件事是可能并不总是 30 页。例如,今天有 29 个,因此它不断从第 29 页获取数据。我修改了您的代码以继续运行,直到不再启用“下一步”按钮,然后我等待检查表是否在继续之前正在加载:

    import time
    from pandas.io.html import read_html
    from pandas import DataFrame
    from selenium import webdriver
    
    driver = webdriver.Chrome(path-to-your-chromedriver)
    driver.get('https://www.whoscored.com/Regions/252/Tournaments/2/Seasons/6335/Stages/13796/PlayerStatistics/England-Premier-League-2016-2017')
    
    df = DataFrame()
    
    while True:
    
        while driver.find_element_by_xpath('//*[@id="statistics-table-summary"]').get_attribute('class') == 'is-updating': # driver.find_element_by_xpath('//*[@id="statistics-table-summary-loading"]').get_attribute('style') == 'display; block;' or
            time.sleep(1)
    
        table = driver.find_element_by_xpath('//*[@id="statistics-table-summary"]')
        table_html = table.get_attribute('innerHTML')
        page_number = driver.find_element_by_xpath('//*[@id="currentPage"]').get_attribute('value')
        print('Page ' + page_number)
        df1 = read_html(table_html)[0]
        df.append(df1)
        next_link = driver.find_element_by_xpath('//*[@id="next"]')
    
        if 'disabled' in next_link.get_attribute('class'):
            break
    
        next_link.click()
    
    
    print(df)
    
    driver.close()
    

    但是,在运行结束时我得到一个空的DataFrame。不幸的是,我对pandas 不够熟悉以识别问题,但它与df.append() 有关。我通过它在每个循环中打印df1 的值来运行它,它打印正确的数据,但是它没有将它添加到DataFrame。这可能是您足够熟悉的内容,可以实现完全运行所需的更改。

    编辑 2:我花了一段时间才弄清楚这一点。本质上,页面的内容是用 javascript 动态加载的。您声明的“下一个”元素仍然是您遇到的第一个“下一个”按钮。每次单击新选项卡时,“下一个”元素的数量都会增加。我添加了一个编辑,它成功地浏览了所有选项卡(“详细”选项卡除外……希望你不需要这个,哈哈)。但是,我仍然感到空虚DataFrame()'s

    import time
    import pandas as pd
    from pandas.io.html import read_html
    from pandas import DataFrame
    from selenium import webdriver
    
    driver = webdriver.Chrome('/home/mdrouin/Downloads/chromedriver')
    driver.get('https://www.whoscored.com/Regions/252/Tournaments/2/Seasons/6335/Stages/13796/PlayerStatistics/England-Premier-League-2016-2017')
    
    statistics = {  # this is a list of all the tabs on the page
        'summary': DataFrame(),
        'defensive': DataFrame(),
        'offensive': DataFrame(),
        'passing': DataFrame()
    }
    
    count = 0
    tabs = driver.find_element_by_xpath('//*[@id="stage-top-player-stats-options"]').find_elements_by_tag_name('li')  # this pulls all the tab elements
    for tab in tabs[:-1]:  # iterate over the different tab sections
        section = tab.text.lower()
        driver.find_element_by_xpath('//*[@id="stage-top-player-stats-options"]').find_element_by_link_text(section.title()).click()  # clicks the actual tab by using the dictionary's key (.proper() makes the first character in the string uppercase)
        time.sleep(3)
        while True:
            while driver.find_element_by_xpath('//*[@id="statistics-table-%s"]' % section).get_attribute('class') == 'is-updating':  # string formatting on the xpath to change for each section that is iterated over
                time.sleep(1)
    
            table = driver.find_element_by_xpath('//*[@id="statistics-table-%s"]' % section)  # string formatting on the xpath to change for each section that is iterated over
            table_html = table.get_attribute('innerHTML')
            df = read_html(table_html)[0]
            # print df
            pd.concat([statistics[section], df])
            next_link = driver.find_elements_by_xpath('//*[@id="next"]')[count]  # makes sure it's selecting the correct index of 'next' items 
            if 'disabled' in next_link.get_attribute('class'):
                break
            time.sleep(5)
            next_link.click()
        count += 1
    
    
    for df in statistics.values():  # iterates over the DataFrame() elemnts
        print df
    
    driver.quit()
    

    【讨论】:

    • 我已经更新了代码,但是还是有问题。如果您再看一眼,我将不胜感激
    • @jchadwick92 查看我对答案的更新,如果您有任何问题,请告诉我
    • 代码运行良好,非常感谢。我现在已经进入了防守部分,但是我在退出循环时遇到了问题,你能再看看吗?
    • @jchadwick92 尝试对next_link 使用相同的声明... next_link = driver.find_element_by_xpath('//*[@id="next"]')
    • 我试过了,它给了我这个错误:ElementNotVisibleException
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    相关资源
    最近更新 更多