9.4 Selenium
上一节我们讲解了PhantomJS的用法,它只是一个没有界面的浏览器,运行的还是JavaScript脚本,这和Python爬虫开发有什么联系呢?本节介绍的Selenium能将Python和PhantomJS紧密地联系起来,从而实现爬虫的开发。
Selenium是一个自动化测试工具,支持各种浏览器,包括Chrome、Safari、Firefox等主流界面式浏览器,也包括PhantomJS等无界面浏览器,通俗来说Selenium支持浏览器驱动,可以对浏览器进行控制。而且Selenium支持多种语言开发,比如Java、C、Ruby,还有Python,因此Python+Selenium+PhantomJS的组合就诞生了。PhantomJS负责渲染解析JavaScript,Selenium负责驱动浏览器和与Python对接,Python负责做后期处理,三者构成了一个完整的爬虫结构。
9.4.1 安装Selenium
Selenium现在最新的版本为3.0.1,本书也是以此为标准进行讲解。Selenium官方地址为:http://www.seleniumhq.org/ ,其安装主要有两种方式:
·pip install Selenium==3.0.1
·从https://pypi.python.org/pypi/selenium 下载源代码解压后,运行python setup.py install。
·Selenium3.x和Selenium2.x版本有以下区别:
·Selenium2.x调用高版本浏览器会出现不兼容问题,调用低版本浏览器正常。
·Selenium3.x调用浏览器必须下载一个类似补丁的文件,比如Firefox的为geckodriver,Chrome的为chromedriver。
各种版本浏览器的补丁下载地址为:http://www.seleniumhq.org/download/ ,如图9-11所示。
图9-11 补丁下载地址
根据自己的操作系统,下载指定的geckodriver文件。下面以Firefox为例,对geckodriver进行配置。在ubuntu下,将文件下载下来之后解压到指定目录下,我把它解压到firefoxDriver目录下,如图9-12所示。
图9-12 补丁解压位置
接着配置环境变量,在shell中执行:export PATH=$PATH:/home/ubuntu/firefoxDr-iver,将geckodriver所在的目录配置到环境变量中,其他操作系统配置方式类似。
9.4.2 快速入门
安装和配置完成后,现在开始使用Selenium写一个小例子,功能是打开百度主页,在搜索框中输入网络爬虫,进行搜索。代码如下:
from selenium import webdriver from selenium.webdriver.common.keys import Keys import time driver = webdriver.Firefox() driver.get("http://www.baidu.com") assert u"百度" in driver.title elem = driver.find_element_by_name("wd") elem.clear() elem.send_keys(u"网络爬虫") elem.send_keys(Keys.RETURN) time.sleep(3) assert u"网络爬虫." not in driver.page_source driver.close()
效果如图9-13所示。
图9-13 搜索网络爬虫
代码分析:首先使用webdriver.Firefox()获取Firefox浏览器的驱动,调用get方法,打开百度首页,判断标题中是否包含百度字样,接着通过元素名称wd获取输入框,通过send_keys方法将网络爬虫填写其中,然后回车。延时3秒后,判断搜索页面是否有网络爬虫字样,最后关闭driver。
我相信即使是同样的代码,大家也会遇到各种各样的问题。下面将大家可能遇到的问题进行一下总结:
1)错误信息为:Exception AttributeError:“’Service‘object has no attribute’process‘”in...,可能是geckodriver环境变量有问题,重新将geckodriver所在目录配置到环境变量中。或者直接在代码中指定路径:
webdriver.Firefox(executable_path=’/home/ubuntu/firefoxDriver/geckodriver‘)
2)错误信息为:selenium.common.exceptions.WebDriverException:Message:Unsupported Marionette protocol version 2,required 3,可能是Firefox版本太低,使用Selenium3.x要求Firefox>=v47。
3)错误信息为:selenium.common.exceptions.WebDriverException:Message:Failed to start browser,可能是没找到Firefox浏览器,可以在代码中指定Firefox的位置:
binary = FirefoxBinary(r'E:\Mozilla Firefox\firefox.exe') driver = webdriver.Firefox(firefox_binary=binary)
9.4.3 元素选取
要想对页面进行操作,首先要做的是选中页面元素。元素选取方法如表9-5所示。
表9-5 定位方法
除了上面具有确定功能的方法,还有两个通用方法find_element和find_elements,可以通过传入参数来指定功能。示例如下:
from selenium.webdriver.common.by import By driver.find_element(By.XPATH, '// button[text()="Some text"]')
这一个例子是通过xpath表达式来查找,方法中第一个参数是指定选取元素的方式,第二个参数是选取元素需要传入的值或表达式。第一个参数还可以传入By类中的以下值:
·By.ID
·By.XPATH
·By.LINK_TEXT
·By.PARTIAL_LINK_TEXT
·By.NAME
·By.TAG_NAME
·By.CLASS_NAME
·By.CSS_SELECTOR
下面通过一个HTML文档来讲解一下如何使用以上方法提取内容,HTML文档如下:
<html> <body> <h1>Welcome</h1> <p class="content">用户登录</p> <form id="loginForm"> <input name="username" type="text" /> <input name="password" type="password" /> <input name="continue" type="submit" value="Login" /> <input name="continue" type="button" value="Clear" /> </form> <a href="register.html">Register</a> </body> <html>
定位方法的使用如表9-6所示。
表9-6 定位方法示例
9.4.4 页面操作
以如下HTML文档为例介绍页面操作,login.html代码如下:
<html> <head> <meta http-equiv="content-type" content="text/html;charset=gbk"> </head> <body> <h1>Welcome</h1> <p class="content">用户登录</p> <form id="loginForm"> <select name="loginways"> <option value="email">邮箱</option> <option value="mobile">手机号</option> <option value="name">用户名</option> </select> <br/> <input name="username" type="text" /> <br/> 密码 <br/> <input name="password" type="password" /> <br/><br/> <input name="continue" type="submit" value="Login" /> <input name="continue" type="button" value="Clear" /> </form> <a href="register.html">Register</a> </body> </html>
效果如图9-14所示。
图9-14 登录页面
1.页面交互与填充表单
第一步: 初始化Firefox驱动,打开html文件,由于是本地文件,可以使用下面方式打开。
driver = webdriver.Firefox() driver.get("file:// /e:/login.html")
第二步: 获取用户名和密码的输入框,和登录按钮。
username = driver.find_element_by_name('username') password = driver.find_element_by_xpath(".// *[@id='loginForm']/input[2]") login_button = driver.find_element_by_xpath("// input[@type='submit']")
第三步: 使用send_keys方法输入用户名和密码,使用click方法模拟点击登录。
username.send_keys("qiye") password.send_keys("qiye_pass") login_button.click()
如果想清除username和password输入框的内容,可以使用clear方法。
username.clear() password.clear()
上面还有一个问题没解决,如何操作下拉选项卡选择登录方式呢?第一种方法代码如下:
select = driver.find_element_by_xpath("// form/select") all_options = select.find_elements_by_tag_name("option") for option in all_options: print("Value is: %s" % option.get_attribute("value")) option.click()
在代码中首先获取select元素,也就是下拉选项卡。然后轮流设置了select选项卡中的每一个option选项。这并不是一个非常好的办法。官方提供了更好的实现方式,在WebDriver中提供了一个叫Select方法,也就是第二种操作方式。代码如下:
from selenium.webdriver.support.ui import Select select = Select(driver.find_element_by_xpath('// form/select ')) select.select_by_index(index) select.select_by_visible_text("text") select.select_by_value(value)
它可以根据索引、文字、value值来选择选项卡中的某一项。
如果select标记中multiple=“multiple”,也就是说这个select标记支持多选,Select对象提供了支持此功能的方法和属性。示例如下:
·取消所有的选项:select.deselect_all()
·获取所有的选项:select.options
·获取已选中的选项:select.all_selected_options
2.元素拖拽
元素的拖拽即将一个元素拖到另一个元素的位置,类似于拼图。首先要找到源元素和目的元素,然后使用ActionChains类可以实现。代码如下:
element = driver.find_element_by_name("source") target = driver.find_element_by_name("target") from selenium.webdriver import ActionChains action_chains = ActionChains(driver) action_chains.drag_and_drop(element, target).perform()
3.窗口和页面frame的切换
一个浏览器一般都会开多个窗口,我们可以switch_to_window方法实现指定窗口的切换。示例如下:
driver.switch_to_window("windowName")
也可以通过window handle来获取每个窗口的操作对象。示例如下:
for handle in driver.window_handles: driver.switch_to_window(handle)
如需切换页面frame,可以使用switch_to_frame方法,示例如下:
driver.switch_to_frame("frameName") driver.switch_to_frame("frameName.0.child")
4.弹窗处理
如果你在处理页面的过程中,触发了某个事件,跳出弹框。可以使用switch_to_alert获取弹框对象,从而进行关闭弹框、获取弹框信息等操作。示例如下:
alert = driver.switch_to_alert() alert.dismiss()
5.历史记录
操作页面的前进和后退功能,示例如下:
driver.forward() driver.back()
6.Cookie处理
可以使用get_cookies方法获取cookie,也可以使用add_cookie方法添加cookie信息。示例如下:
driver.get("http://www.baidu.com") cookie = {'name': 'foo', 'value' : 'bar'} driver.add_cookie(cookie) driver.get_cookies()
7.设置phantomJS请求头中User-Agent
这个功能在爬虫中非常有用,一般针对phantomJS的反爬虫措施都会检测这个字段,默认的User-Agent中含有phantomJS内容,可以通过代码进行修改。代码如下:
dcap = dict(DesiredCapabilities.PHANTOMJS) dcap["phantomjs.page.settings.userAgent"] = ( "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36" ) driver = webdriver.PhantomJS()# desired_capabilities=dcap) driver.get("http://www.google.com") driver.quit()
9.4.5 等待
由于现在很多网站采用Ajax技术,不确定网页元素什么时候能被完全加载,所以网页元素的选取会比较困难,这时候就需要等待。Selenium有两种等待方式,一种是显式等待,一种是隐式等待。
1.显式等待
显式等待是一种条件触发式的等待方式,指定某一条件直到这个条件成立时才会继续执行,可以设置超时时间,如果超过这个时间元素依然没被加载,就会抛出异常。示例如下:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Firefox() driver.get("http://somedomain/url_that_delays_loading") try: element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")) ) finally: driver.quit()
以上代码加载http://somedomain/url_that_delays_loading 页面,并定位id为myDynamic Element的元素,设置超时时间为10s。WebDriverWait默认会500ms检测一下元素是否存在。
Selenium提供了一些内置的用于显式等待的方法,位于expected_conditions类中,方法名称如表9-7所示:
表9-7 内置方法
2.隐式等待
隐式等待是在尝试发现某个元素的时候,如果没能立刻发现,就等待固定长度的时间,类似于socket超时,默认设置是0秒。一旦设置了隐式等待时间,它的作用范围是Webdriver对象实例的整个生命周期,也就是说Webdriver执行每条命令的超时时间都是如此。如果大家感觉设置的时间过长,可以进行不断地修改。使用方法示例如下:
from selenium import webdriver driver = webdriver.Firefox() driver.implicitly_wait(10) # seconds driver.get("http://somedomain/url_that_delays_loading") myDynamicElement = driver.find_element_by_id("myDynamicElement")
3.线程休眠
time.sleep(time),这是使用线程休眠延时的办法,也是比较常用的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论