如何从 Fast.com 获取网速结果

问题描述 投票:0回答:4

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

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

寻找任何指示。

python selenium google-chrome web-scraping beautifulsoup
4个回答
5
投票

编辑2020-11-03:我已经修复了代码,并且由于Carlos它再次工作了。


该页面是 JS 驱动的,并且没有简单的方法可以通过简单地从页面上删除 HTML 来获取结果,因此仅使用

requests
bs4
无法帮助您。
您需要运行完整的现代浏览器才能运行测试,并等待所需的时间,然后获取结果。

设置

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

通过运行安装软件包:

pip install selenium

我们还需要安装一个驱动程序来控制我们的浏览器,你可以在这里找到它(事实上,请完整阅读有关安装的页面,它拥有运行它所需的一切)。然后我们需要将该可执行文件放入我们的PATH

中。最简单的方法是将其放在 Windows 上的 
c:\Windows
 或 Linux 上的 
/usr/bin
 下。但是在 SO 和互联网上有大量的文档,所以学习正确的方法来正确地做到这一点,你会需要它。

除此之外,我们还需要

Beautiful Soup,它是事实上的 HTML 解析器(在这一点上,我们可以继续使用 selenium 和浏览器,但我习惯使用 bs4 来完成这项工作)。使用安装它

pip install bs4
运行测试

现在要获取结果,我们需要运行浏览器,访问

https://fast.com,让测试完成,然后获取结果的 HTML,然后提取我们需要的信息。

我们如何知道测试何时完成?

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

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

succeeded

 类。

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

等待

Selenium 有一个

显式等待 功能,可以让您等到页面上发生某些事情。我们将使用它来检查并等待页面上出现一些具有 .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'}
    

1
投票
fast.com 有一个用 golang 编写的命令行客户端:

https://github.com/ddo/fast/releases


0
投票
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)



0
投票

随着这一改变,该程序对我有用了。

© www.soinside.com 2019 - 2024. All rights reserved.