外观往往和事物的本身完全不符,世人都容易为表面的装饰所欺骗。—— 莎士比亚 《威尼斯商人》
一. 概述
上一篇文章 【爬虫】python+selenium+firefox使用与部署详解 介绍了 selenium
传统方式部署与使用,需要安装浏览器、安装浏览器对应的驱动等,对于我来说配置还是比较繁琐,有没有没有简单的配置方式呢?有,那就是使用 docker
来部署,接下来将介绍如何使用 docker
部署 python + selenium + firefox-headless
。
二. docker 安装 selenium/standalone-firefox
selenium docker hub 地址:https://hub.docker.com/u/sele...
访问上面的地址,选择一个对应浏览器镜像,这里选择 selenium/standalone-firefox
,如下图所示:
快速开始
更多配置与使用可以查看 github:https://github.com/SeleniumHQ...
使用下面的命令启动一个
Firefox
的docker
容器:$ docker run --name firefox -d -p 4444:4444 -p 7900:7900 --shm-size="2g" selenium/standalone-firefox:3.141
- 访问 http://localhost:4444 测试
webDriver
,如下图所示:
- 访问 http://localhost:4444/wd/hub/... 跳转到 selenium 控制台,如下图所示:
注意:
- 当为包含浏览器的镜像执行docker运行时,请使用标志
--shm-size 2g
来使用主机的共享内存- 始终使用带有完整标签的 Docker 镜像来固定特定的浏览器和网格版本。
为什么需要设置 --shm-size 2g
:
这是一个已知的解决方案,以避免在docker容器内浏览器崩溃,2gb的shm大小是任意的,但已知可以很好地工作,您的特定用例可能需要不同的值,建议根据您的需要调整这个值。
可以使用下面的命令进入到 firefox 容器中:
docker exec -it firefox bash
使用下面命令,可以看到容器中已经安装好了 firefox
和 geckodriver
:
seluser@67be1f8cd61f:/opt$ ls -al /opt
total 8228
drwxr-xr-x 1 root root 4096 Jul 29 08:49 .
drwxr-xr-x 1 root root 4096 Aug 15 08:02 ..
drwxr-xr-x 1 root root 4096 Jul 29 08:52 bin
drwxr-xr-x 7 root root 4096 Jul 29 08:49 firefox-latest
-rwxr-xr-x 1 1000 1000 8401832 Apr 8 22:01 geckodriver-0.29.1
drwxrwxrwx 1 root root 4096 Jul 29 08:44 selenium
三. 使用 webdriver.Remote() 配置远程浏览器
selenium
提供了 webdriver.Remote()
通过发送命令到远程服务器来控制浏览器,可以使执行测试的机器和发送测试命令的机器独立开来。
关于 webdriver.Remote()
的配置使用非常简单,不需要像前面文章提到的指定各种配置,其参数默认如下:
selenium.webdriver.remote.webdriver.WebDriver
def __init__(self,
command_executor: str = 'http://127.0.0.1:4444/wd/hub',
desired_capabilities: Any = None,
browser_profile: Any = None,
proxy: Any = None,
keep_alive: bool = False,
file_detector: Any = None,
options: Any = None) -> Any
使用示例如下:
from selenium import webdriver
from selenium.webdriver import DesiredCapabilities
if __name__ == '__main__':
driver = webdriver.Remote(
# 指定远程浏览器的地址
command_executor='http://localhost:4444/wd/hub',
# 指定期望的浏览器类型,这里安装的是 firefox 所以指定firefox
desired_capabilities=DesiredCapabilities.FIREFOX,
)
# 发送请求
driver.get("https://www.baidu.com")
# 获取网页源码
html = driver.page_source
print(html)
# 获取网页title
title = driver.title
print(title) # 百度一下,你就知道
# 获取当前网页的 url
current_url = driver.current_url
print(current_url) # https://www.baidu.com/
# 退出驱动,关闭所有关联的窗口
driver.quit()
当使用 driver.close()
关闭当前窗口的时候,可以看到 selenium 控制台会产生一个会话,并且没有自动关闭会话,如下图所示:
这里运行了三次产生了三个会话,如果使用 driver.quit()
会自动关闭关联的所有会话,不会保留会话 id 在控制台。
driver = webdriver.Remote() 常用方法与属性:
driver.get(url)
在当前浏览器会话中访问传入的url地址。
用法:driver.get('https://www.baidu.com')
driver.close()
关闭浏览器当前窗口。
driver.quit()
退出webdriver并关闭所有窗口。
driver.refresh()
刷新当前页面。
driver.title
获取当前页的标题。
driver.page_source
获取当前页渲染后的源代码。
driver.current_url
获取当前页面的url。
driver.window_handles
获取当前会话中所有窗口的句柄,返回的是一个列表。
四. python + selenium 配置远程浏览器获取今日头条数据
上一篇文章中获取今日头条数据的代码配置远程浏览器修改如下:
from lxml import etree
from selenium import webdriver
from selenium.webdriver import DesiredCapabilities
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC # 和下面WebDriverWait一起用的
from selenium.webdriver.support.wait import WebDriverWait
def html_selenium_firefox(url):
"""
根据 url 使用 selenium 获取网页源码
:param url: url
:return: 网页源码
"""
driver = webdriver.Remote(
# 指定远程浏览器的地址
command_executor='http://localhost:4444/wd/hub',
# 指定期望的浏览器类型,这里安装的是 firefox 所以指定firefox
desired_capabilities=DesiredCapabilities.FIREFOX,
)
# 发送请求
driver.get(url)
# 显式等待:显式地等待某个元素被加载
wait = WebDriverWait(driver, 20)
wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'article-content')))
wait.until(EC.presence_of_element_located((By.TAG_NAME, 'span')))
# 获取网页源码
html = driver.page_source
# 关闭浏览器释放资源
driver.quit()
return html
def get_news_content(url):
html = html_selenium_firefox(url)
tree = etree.HTML(html)
title = tree.xpath('//div[@class="article-content"]/h1/text()')[0]
# xpath 查找没有 class 的元素:span[not(@class)]
pubtime = tree.xpath('//div[@class="article-meta mt-4"]/span[not(@class)]/text()')[0]
# xpath 查找 class="name" 的元素:span[@class="name"]
source = tree.xpath('//div[@class="article-meta mt-4"]/span[@class="name"]/a/text()')[0]
# xpath 某个标签中的所有元素://div
content = tree.xpath('//article')[0]
# 处理 content 乱码问题
content = str(etree.tostring(content, encoding='utf-8', method='html'), 'utf-8')
# 提取 content 中所有图片的地址
images = etree.HTML(content).xpath('//img/@src')
result = {
"title": title,
"pubtime": pubtime,
"source": source,
"content": content,
"images": images,
}
return result
if __name__ == '__main__':
url = "https://www.toutiao.com/a6969138023774667264/"
result = get_news_content(url)
print(result)
参考文档:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。