【问题标题】:How to get internet speed results from Fast.com如何从 Fast.com 获取互联网速度结果
【发布时间】:2019-11-29 13:37:40
【问题描述】:

我想定期检查我的互联网速度并在路由器下降到某个阈值时重置我的路由器,这似乎修复了我的 ISP“提供”的糟糕连接。

虽然可能有更简单的方法来解决这个问题,但我认为我应该从 Fast.com 获取结果,它可以为我提供所需的结果,例如下载速度、上传速度和到靠近服务器的 ping 时间我。

寻找任何指针。

【问题讨论】:

    标签: python selenium google-chrome web-scraping beautifulsoup


    【解决方案1】:

    EDIT 2020-11-03:我已经修复了代码,感谢Carlos,它又可以工作了。


    该页面是 JS 驱动的,没有简单的方法可以通过简单地从页面上抓取 HTML 来获得结果,因此单独使用 requestsbs4 对您没有帮助。
    您需要运行一个完整的现代浏览器来让测试运行,并等待它需要的时间然后得到结果。

    设置

    好吧,我们就用Selenium这个,它可以控制Chrome、Firefox、Safari,基本上任何浏览器都可以。

    通过运行安装包:

    pip install selenium
    

    我们还需要安装一个驱动来控制我们的浏览器,你可以找到它here(事实上完全阅读了关于安装的页面,它拥有运行它所需的一切)。然后我们需要将该可执行文件放在我们的PATH 中。最简单的方法是将其放在 Windows 上的 c:\Windows 或 Linux 上的 /usr/bin 下。但是关于 SO 和 Internet 上有大量文档,因此请学习正确执行此操作的正确方法,您将需要它。

    除此之外,我们还需要Beautiful Soup,它是事实上的 HTML 解析器(注意,我们可以继续使用 selenium 和浏览器,但我习惯于使用 bs4 来完成这项工作)。使用安装它

    pip install bs4
    

    运行测试

    现在要获取结果,我们需要运行浏览器,转到https://fast.com,让测试完成,然后获取结果的 HTML,然后提取我们需要的信息。

    我们如何知道测试何时结束?

    好吧,我们可以等 30 秒,直到一切都完成。但是如果提前结束呢?还是根本没有完成?那么我们就会无缘无故地等待。有更好的方法。

    测试完成后,微调器变为绿色。如果我们从开发者控制台观察 DOM,我们会看到它有一个 succeeded 类。

    但是如果我们展开结果,我们会看到上传结果还没有,当这种情况发生时,页面会再次更新,我们会到达这个状态:

    等待

    Selenium 具有explicit wait 功能,可让您等到页面上发生某些事情。我们将使用它来检查并等待页面上出现带有.succeeded 类的元素。如果您只需要下载速度,只需等待 spinner 获取.succeeded 类,如果您还需要上传结果,则需要等待。对于这项工作,我们可以使用这个辅助函数:

    from selenium.common.exceptions import TimeoutException
    from selenium.webdriver import Chrome
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import WebDriverWait
    
    
    def wait_until_present(driver: Chrome, selector: str, timeout: int = 5):
        condition = EC.presence_of_element_located((By.CSS_SELECTOR, selector))
        try:
            WebDriverWait(driver, timeout).until(condition)
        except TimeoutException as e:
            raise LookupError(f'{selector} is not present after {timeout}s') from e
    
    

    提取结果

    输入结果后,我们将获取包含上传和下载结果的父元素的 HTML。

    # this is the parent element that contains both download and upload results
    results_selector = '.speed-controls-container'
    results_el = driver.find_element_by_css_selector(results_selector)
    results_html = results_el.get_attribute('outerHTML')
    

    然后我们将 HTML 提供给 BeautifulSoup 并提取值。

    代码

    这是完整的代码:

    from selenium.webdriver import Chrome, ChromeOptions
    from selenium.webdriver.common.by import By
    from selenium.common.exceptions import TimeoutException
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from bs4 import BeautifulSoup
    from contextlib import contextmanager
    
    
    @contextmanager
    def get_chrome() -> Chrome:
        # https://docs.python.org/3.7/library/contextlib.html#contextlib.contextmanager
        opts = ChromeOptions()
        # opts.headless = True
        driver = Chrome(options=opts)
        yield driver
        driver.close()
    
    
    def wait_until_present(driver: Chrome, selector: str, timeout: int = 5):
        condition = EC.presence_of_element_located((By.CSS_SELECTOR, selector))
        try:
            WebDriverWait(driver, timeout).until(condition)
        except TimeoutException as e:
            raise LookupError(f'{selector} is not present after {timeout}s') from e
    
    
    def extract_speed_info(soup: BeautifulSoup) -> dict:
        dl_speed = soup.select_one('#speed-value').text
        dl_unit = soup.select_one('#speed-units').text
        upload_speed = soup.select_one('#upload-value').text
        upload_unit = soup.select_one('#upload-units').text
    
        return {
            'upload': f'{upload_speed} {upload_unit}',
            'download': f'{dl_speed} {dl_unit}'
        }
    
    
    def run_speed_test() -> dict:
        with get_chrome() as driver:
            driver.get('https://fast.com')
    
            # wait at most 60s until upload results come in
            download_done_selector = '#speed-value.succeeded'
            upload_done_selector = '#upload-value.succeeded'
            wait_until_present(driver, upload_done_selector, timeout=60)
    
            # this is the parent element that contains both download and upload results
            results_selector = '.speed-container'
            results_el = driver.find_element_by_css_selector(results_selector)
            results_html = results_el.get_attribute('outerHTML')
    
        # we're finished with chrome, let it close (by exiting with block)
    
        soup = BeautifulSoup(results_html, 'html.parser')
        info = extract_speed_info(soup)
        return info
    
    
    if __name__ == '__main__':
        try:
            results = run_speed_test()
            print('Speed results:', results)
        except LookupError as e:
            print('Cannot get speed results')
            print(e)
            exit(1)
    

    输出:

    {'upload': '320 Kbps', 'download': '3.4 Mbps'}
    

    【讨论】:

      【解决方案2】:

      有一个用golang写的fast.com的命令行客户端:https://github.com/ddo/fast/releases

      【讨论】:

        【解决方案3】:

        abdusco 提供的答案非常有帮助。无论如何,现在在 2020 年它不起作用。要加载上传结果,需要在下载测试完成后点击“显示更多信息”按钮。 要解决这个问题,只需在加载页面后添加另一个 wait_visble 并单击按钮。

        这是必须从 abdusco 的答案修改的代码:

            upload_done_selector = '#upload-value.succeeded'
            more_info_selector = "show-more-details-link"
            wait_visible(driver, "#"+more_info_selector, timeout=60)
            driver.find_element_by_id(more_info_selector).click()
            wait_visible(driver, upload_done_selector, timeout=60)
        

        【讨论】:

        • 感谢您的提醒。你真的不需要点击任何东西。我已将等待条件从对用户可见更改为在页面中显示,并且无需任何重大更改即可工作
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-09
        • 2011-07-28
        • 1970-01-01
        • 1970-01-01
        • 2013-11-08
        • 2022-11-19
        相关资源
        最近更新 更多