零基础-一起学爬虫

【零基础学爬虫】Selenium库详解

2019-03-24  本文已影响6人  大菜鸟_

什么是Selenium

主要用于自动化测试工具,支持多浏览器:chrome,Firefox,Android浏览器等,主要用于驱动浏览器,给浏览器发一些指令,让浏览器执行各种动作:输入、跳转、点击、下拉等操作。它在爬虫中主要解决javaScript渲染问题,完全模拟网页的加载。

在做爬虫的时候如果遇到Request、urllib无法正常获取网页内容,那么这可能是JavaScript渲染致使的问题,这时使用Selenium可以完成渲染,即模拟浏览器完整的操作,之后获取到的源代码就是网页渲染后的源代码,可以完全解决javaScript渲染问题。

安装

基本使用

下面是一个简单实例代码:

from selenium import webdriver#浏览器驱动对象
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

browser = webdriver.Chrome()#chrom浏览器驱动对象
try:
    browser.get('https://www.baidu.com')#传入url,此时会跳出浏览器,访问百度网址
    input = browser.find_element_by_id('kw') #找出id为kw元素
    input.send_keys('Python')#kw中发送python
    input.send_keys(Keys.ENTER)#回车
    wait = WebDriverWait(browser, 10)#等待加载完成
    wait.until(EC.presence_of_element_located((By.ID, 'content_left')))#等待content_left加载完成
    print(browser.current_url)
    #print(browser.get_cookies())
    #print(browser.page_source)
finally:
    browser.close()

输出的当前网页url其实就是我们搜索关键词时浏览器地址栏的地址:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=Python&rsv_pq=e7742729000658f1&rsv_t=cc28oZ5U7GMkpj%2FJdBtJXIrYy8IMIXVo35002Hb4hIvJpqwhNFLtlB9KzUw&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug2=0&inputT=75&rsv_sug4=76

pageSource太长了就没打印
(1)声明浏览器对象

from selenium import webdriver

browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()

(2) 访问页面

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
print(browser.page_source)
browser.close()

(3)查找单个元素
获取到网页源码后,可能需要进行一些交互的操作:输入框、按钮点击之类的。

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element_by_id('q')
input_second = browser.find_element_by_css_selector('#q')
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first, input_second, input_third)#三个结果一样
browser.close()

输出的三个结果其实是一样的,也就是可以使用不同的方法找元素

<selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")> 
<selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")> 
<selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")>

常用的查找单个元素方法:

from selenium import webdriver
from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element(By.ID, 'q')
print(input_first)
browser.close()

(4)查找多个元素

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
lis = browser.find_elements_by_css_selector('.service-bd li')
print(lis)
browser.close()

下面与上面方式一样:

from selenium import webdriver
from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
lis = browser.find_elements(By.CSS_SELECTOR, '.service-bd li')#列表
print(lis)
browser.close()

常用的查找多个元素方法:

from selenium import webdriver
import time

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input = browser.find_element_by_id('q')
input.send_keys('iPhone')
time.sleep(1)#等待1秒
input.clear()
input.send_keys('iPad')搜索IPad
button = browser.find_element_by_class_name('btn-search')
button.click()

上面程序含义是:在淘宝中搜索“iPad”,那么为什么是find_element_by_id('q')呢?q又是从何而来的呢?我们打开淘宝首页,邮件,审查元素,鼠标点击淘宝的搜索框,如下图所示:



这就是id为‘q’的由来。当我们在淘宝搜索iPhone时,再次点击邮件->检查,结果如下图所示:



这就是‘q’的由来。
另外,btn-search是怎么来的呢?

另外,实际测试中发现填写:tb-bg也是可以的

更多操作: http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement

(6)交互动作
和上面的元素交互动作是不同的:

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
target = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()

上面的draggable和droppable都来自上图,执行后就将小方框拖动到大方框中了

更多操作: http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains

执行JavaScript

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')

(7)获取元素属性、文本值

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo.text)#文本值
print(logo.get_attribute('class'))

输出:

知乎
zu-top-link-logo

获取ID、位置、标签名、大小

from selenium import webdriver

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)

输出:

0.6822924344980397-1
{'y': 7, 'x': 774}
button
{'height': 32, 'width': 66}

Frame

Frame在网页中可能出现比较频繁,但是如果出现了Frame,在做元素筛选的时候会导致一些不太方便的问题:有些Frame相对于一个独立的网页,在父级的Frame中,想查找子元素的Frame,实际上必须切换到Frame中才能进行查找,否则是不能完成元素的查找。

比如之前拖拽案例中的源代码:


整个拖拽是在一个iframe中,但是如果我们在这个iframe中想要获取外面的那些元素,获取时可能汇报错误,比如在拖拽那个iframe中尝试获取logo class,此时汇报找不到该元素的错误:

import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')#切换到拖拽那个iframe中
source = browser.find_element_by_css_selector('#draggable')
print(source.text)#
try:
    logo = browser.find_element_by_class_name('logo')#尝试找外面的元素
except NoSuchElementException:
    print('NO LOGO')#没找到
browser.switch_to.parent_frame()#切换到父iframe查找
logo = browser.find_element_by_class_name('logo')
print(type(logo))
print(logo.text)

输出:
请拖拽我!

NO LOGO
<class 'selenium.webdriver.remote.webelement.WebElement'>
RUNOOB.COM

不能在子frame查找父frame中的元素

等待

我们在爬取数据的时候可能会有一些Ajax请求,这些Ajax请求不会管Selenium是否完成了网页的加载,也就是说:Selenium只是把基本的框架给加载出来了,如果有一些后续的Ajax请求等其他的操作,可能会出现有部分元素没有加载完全,在没加载完时进行操作会导致一些问题的出现。所以,我们需要加一些等待,确保元素都完成加载后在进行一些操作,这样可以减少异常。

等待分为两种:显式等待和隐式等待。
(1)隐式等待
当使用了隐式等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常, 换句话说:当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0

from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(10)#隐式等待时间10秒
browser.get('https://www.zhihu.com/explore')
#当网速比较慢时会出现下面的元素没加载出来
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)

(2)显示等待

title_is 标题是某内容
title_contains 标题包含某内容
presence_of_element_located 元素加载出,传入定位元组,如(By.ID, 'p')
visibility_of_element_located 元素可见,传入定位元组
visibility_of 可见,传入元素对象
presence_of_all_elements_located 所有元素加载出
text_to_be_present_in_element 某个元素文本包含某文字
text_to_be_present_in_element_value 某个元素值包含某文字
frame_to_be_available_and_switch_to_it frame加载并切换
invisibility_of_element_located 元素不可见
element_to_be_clickable 元素可点击
staleness_of 判断一个元素是否仍在DOM,可判断页面是否已经刷新
element_to_be_selected 元素可选择,传元素对象
element_located_to_be_selected 元素可选择,传入定位元组
element_selection_state_to_be 传入元素对象以及状态,相等返回True,否则返回False
element_located_selection_state_to_be 传入定位元组以及状态,相等返回True,否则返回False
alert_is_present 是否出现Alert

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

browser = webdriver.Chrome()
browser.get('https://www.taobao.com/')
wait = WebDriverWait(browser, 10)#最长等待时间
#等待条件
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
#等待条件
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
print(input, button)

详细等待条件介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

浏览器的前进和后退

import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.python.org/')
browser.back()
browser.back()
time.sleep(1)
browser.forward()
browser.close()

cookies
尤其在登陆后的爬取,设置登录的状态。

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())

浏览器选项卡的操作
新增浏览器选项卡:最简单的就是通过js打开新的选项卡;另外就是通过模拟键盘按键(浏览器可以通过快捷键打开选项卡),不太通用,不同浏览器快捷方式不一样:

import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com')#第一个选项卡打开百度
browser.execute_script('window.open()')
print(browser.window_handles)#返回的所有窗口的引用
browser.switch_to_window(browser.window_handles[1])#切换到第二个选项卡
browser.get('https://www.taobao.com')#第二个选项卡切换到淘宝
time.sleep(1)
browser.switch_to_window(browser.window_handles[0])#切换第一个选项卡
browser.get('https://python.org')#第一个选项卡切换到python

异常处理
例如:某个元素无法点击异常、加载超时异常、没有找到元素的异常,各类异常最好查看官方文档:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException

browser = webdriver.Chrome()
try:
    browser.get('https://www.baidu.com')
except TimeoutException:#超时异常
    print('Time Out')
try:
    browser.find_element_by_id('hello')
except NoSuchElementException:#好不到元素的异常
    print('No Element')
finally:
    browser.close()

exception的详细介绍文档:
http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions


扫描下方二维码,及时获取更多互联网求职面经javapython爬虫大数据等技术,和海量资料分享
公众号菜鸟名企梦后台发送“csdn”即可免费领取【csdn】和【百度文库】下载服务;
公众号菜鸟名企梦后台发送“资料”:即可领取5T精品学习资料java面试考点java面经总结,以及几十个java、大数据项目资料很全,你想找的几乎都有

扫码关注,及时获取更多精彩内容。(博主今日头条大数据工程师)
上一篇 下一篇

猜你喜欢

热点阅读