selenium + PhantomJS 使用 WebDriverWait 实现延迟加载网页动态内容并截图

最近有个项目功能需要实现一个后台模拟登录网站,然后进入到二级页面进行网页截图并返回的 API。

听起来很有意思,打算使用 Python 的 selenium 包配合无界面浏览器 PhantomJS 来实现。

要注意较新版本的 selenium 已经不再支持 PhantomJS,需安装较老版本的 selenium。

模拟登陆使用 requests 包的 Session 类,然后将 cookie 添加到 WebDriver 里。

session = requests.session()
res = session.post(url=LOGIN_URL, data=payload)
cookies = session.cookies.get_dict()

driver = webdriver.PhantomJS()
driver.implicitly_wait(10) # 设置连接超时时间为 10 秒。

for i in cookies:
    driver.add_cookie({
        "name": i,
        "value" : cookies[i],
        "path": "/",
        "domain": DOMAIN # domain 和 path 参数是必须的,否则会报错。
    })

需要截图的页面内有两个 iframe,而 iframe 内容是由页面上点击某个菜单链接时动态加载的。

所以我们在页面加载结束以后执行 JS 语句模拟点击菜单链接,网页引入了 JQuery,可以很方便的使用。

driver.get(CONTENT_URL)
driver.execute_script("$('a.menu').first().click()")

此时 iframe 开始加载,但是如果马上执行网页截图的话,iframe 可能还没有完成加载,所以我们等待想要截图的内容加载完成以后再执行截图。

这里可以方便的使用 selenium 提供的 WebDriverWait 类,用以阻塞式地循环判断条件是否成立,直到条件成立才会继续执行下面的代码。

# 在代码中引入 WebDriverWait 类
# from selenium.webdriver.support.wait import WebDriverWait

# WebDriverWait 对象的 until 方法参数需传入一个函数,并将会循环调用这个函数用于检测条件是否成立,直到函数返回 True 时才继续执行下面的代码。
# 这里为了方便,将一个 lambda 匿名函数作为 until 方法的参数传入。
condition = lambda x: driver.execute_script("return document.getElementsByTagName('iframe')[1].contentDocument.getElementsByTagName('table').length") > 0

# WebDriverWait 类构造函数第一个参数为 WebDriver 对象,第二个参数是超时时间(秒),如果超过该事件条件还未成立,将会抛出一个异常。
WebDriverWait(driver, 5).until(condition)

当条件成立时,执行网页截图,返回图片内容的字节数组。

screenshot = driver.get_screenshot_as_png()

最后,将图片内容写入到响应体中返回,完工。

发表评论

电子邮件地址不会被公开。