几乎实时地从网站上抓取动态内容



我正在尝试实现一个web scraper,它几乎实时地从网站上抓取动态更新的内容。

我们走吧https://www.timeanddate.com/worldclock/作为一个例子,并假设我想在我的家乡连续获得当前时间。我现在的解决方案如下:每秒获取渲染的页面内容,并使用bs4提取时间。工作代码:

import asyncio
import bs4
import pyppeteer
def get_current_time(content):
soup = bs4.BeautifulSoup(content, features="lxml")
clock = soup.find(class_="my-city__digitalClock")
hour_minutes = clock.contents[3].next_element
seconds = clock.contents[5].next_element
return hour_minutes + ":" + seconds
async def main():
browser = await pyppeteer.launch()
page = await browser.newPage()
await page.goto("https://www.timeanddate.com/worldclock/")
for _ in range(30):
content = await page.content()
print(get_current_time(content))
await asyncio.sleep(1)
await browser.close()
asyncio.run(main())

相反,我想做的是:只有当页面上的时间更新时才进行反应。原因:反应更快,计算密集度更低(尤其是在监视多个页面时,这些页面可能以小于或大于一秒的不规则间隔更新(。

我尝试了以下三种方法来解决这个问题,但我不知道如何继续。还有一种更简单/更优雅的方法:

1(使用pyppeteer拦截网络响应

这似乎不起作用,因为在最初加载页面后没有更多的网络活动(除了广告(,正如我在Chrome开发工具的"网络"选项卡中看到的那样。

2(对页面上的自定义事件作出反应

使用Chrome开发工具中"源代码"选项卡中的"事件侦听器断点",我可以停止JavaScript代码在各种事件上的执行(例如"Set innerHTML"事件(。

是否可以使用pyppeteer进行类似的操作,提供有关事件的一些上下文信息(例如,用哪个新文本更新了哪个元素(?

使用JavaScript和puppeteer似乎是可能的(请参阅https://github.com/puppeteer/puppeteer/blob/main/examples/custom-event.js),但我认为pyppeteer没有提供此功能(我在API参考中找不到它(。

3(覆盖页面JavaScript代码中的函数

覆盖相关函数并截取相关数据(作为参数提供给该函数(。

这个想法的灵感来自于这篇博客文章:https://antoinevastel.com/javascript/2019/06/10/monitor-js-execution.html

博客文章的完整代码:https://github.com/antoinevastel/blog-post-monitor-js/blob/master/monitorExecution.js

我试了一下,但我的JavaScript似乎太有限了,甚至不能覆盖页面使用的一个Java脚本中的一个函数。

使用Selenium可以实现这一点。我通过网络驱动程序管理器使用Chrome网络驱动程序,但您可以修改它以使用您喜欢的任何内容。

首先,我们所有的进口

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager

使用headless参数创建我们的driver对象,这样浏览器窗口就不会打开。

options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)

定义一个接受WebElement以提取时钟时间的函数。

def getTimeString(myClock: WebElement) -> str:
hourMinute = myClock.find_element(By.XPATH, "span[position()=2]").text
seconds = myClock.find_element(By.CLASS_NAME, "my-city__seconds").text
return f"{hourMinute}:{seconds}"

获取页面并提取时钟WebElement

driver.get("https://www.timeanddate.com/worldclock/")
myClock = driver.find_element(By.CLASS_NAME, "my-city__digitalClock")

最后,实现我们的环路

last = None
while True:
now = getTimeString(myClock)
if now == last:
continue
print(now)
last = now

在逻辑结束之前,请确保运行driver.quit()进行清理。

输出

05:27:56
05:27:57
05:27:58

最新更新