动态渲染网页爬取-selenium

Selenium 简介

  Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的操作例如点击、下拉等操作。同事它还能够获取浏览器当前呈现的页面的源代码,即可以做到可见可爬。这对于一些JavaScript渲染的页面我就就可以使用它进行爬取,而不用去分析后台接口参数。#应用:(以google浏览器为例))安装selenium并且将google驱动chromedirver.exe程序与python代码文件的放置在同一个目录中,即可使用selenium驱动google浏览器.以下为一个简单示例:

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
#声明浏览器对象(也可以是其他浏览器:火狐、IE等)
browser = webdriver.Chrome()
try:
#访问页面
    browser.get('https://www.baidu.com')
    input = browser.find_element_by_id('kw')
    input.send_keys('python')
    input.send_keys(Keys.ENTER)
    wait = WebDriverWait(browser,10)
    wait.until(EC.presence_of_element_located((By.ID,'content_left')))
    print(browser.current_url)
    print(browser.get_cookies())
    print(browser.page_source)
finally:
    browser.close()

结果(输出当前url,源代码,cookies)
.............................................................................................省略
<script>
if(bds.comm.supportis){
    window.__restart_confirm_timeout=true;
    window.__confirm_timeout=8000;
    window.__disable_is_guide=true;
    window.__disable_swap_to_empty=true;
}
initPreload({
    'isui':true,
    'index_form':"#form",
    'index_kw':"#kw",
    'result_form':"#form",
    'result_kw':"#kw"
});
</script>

<script>
if(navigator.cookieEnabled){
    document.cookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT";
}
</script>
</body></html>
View Code

Selenium声明浏览器对象

from selenium import webdriver
#声明谷歌浏览器对象
browser = webdriver.Chrome()
#声明火狐浏览器对象
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser =webdriver.Safari()
View Code

Selenium访问页面

from selenium import webdriver

browser = webdriver.Chrome()
#访问淘宝网页面获取网页原代码
browser.get('https://www.taobao.com')
#获取网页原代码
print(browser.page_source)
#关闭浏览器
browser.close()
View Code

Selenium查找节点

1.单节点查找

单个节点查找find_element()方法

常见方法有:

  • find_element_by_id()
  • find_element_by_name()
  • find_element_by_xpath()
  • find_element_by_link_text()
  • find_element_by_partial_link_text()
  • find_element_by_tag_name()
  • find_element_by_css_selector()

  或

  find_element()传入两个参数查找方式By和值,例如:

  find_element(By.ID,id)

*取以淘宝搜索框网页为例
<input id="q" name="q" aria-label="请输入搜索文字" accesskey="s" autofocus="autofocus" autocomplete="off" class="search-combobox-input" aria-haspopup="true" aria-combobox="list" role="combobox" x-webkit-grammar="builtin:translate" tabindex="0">

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
#根据id获取淘宝搜索框
input_first = browser.find_element_by_id('q')
#根据css选择器获取
input_second = browser.find_element_by_css_selector('#q')
#根据xpath获取
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first,input_second,input_third)
browser.close()

结果(三个结果一致)
<selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")> <selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")> <selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")>
View Code

2.多节点查找

多个节点查找find_elements()方法

  • find_elements_by_id()
  • find_elements_by_name()
  • find_elements_by_xpath()
  • find_elements_by_link_text()
  • find_elements_by_partial_link_text()
  • find_elements_by_tag_name()
  • find_elements_by_css_selector()

   或

  find_elements()传入两个参数查找方式By和值,例如:

  find_element(By.ID,id)

*以淘宝导航栏为例
from selenium import webdriver

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


或者以下方法
Liss = browser.find_elements(By.CSS_SELECTOR,’.server-bd li’)#结果一致
print(lis)
browser.close()

结果
[<selenium.webdriver.remote.webelement.WebElement (session="89a7ea4bb337fc1f8976d6593615d13d", element="0.7879413394489616-1")>...<selenium.webdriver.remote.webelement.WebElement (session="89a7ea4bb337fc1f8976d6593615d13d", element="0.7879413394489616-16")>]
View Code

节点交互,常用的有以下几个:

  • 输入文字用send_keys()方法
  • 清空文字用clear()方法
  • 点击按钮用click()方法
from selenium import webdriver
import time

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
#获取输入框
input = browser.find_element_by_id('q')
#搜索框输入iphone,但是未点击搜索按钮所以不进行搜索
input.send_keys('iphone')
time.sleep(1)
#清空输入框
input.clear()
input.send_keys('ipad')
#获取搜索按钮
button = browser.find_element_by_class_name('btn-search')
#点击按钮完成搜索任务
button.click()
#关闭浏览器
browser.close()
View Code

动作链:例如鼠拖曳和键盘按键等操作就称之为动作链,它们没有特定的执行对象

*举例:实现一个节点的拖曳操作
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')
#声明ActionChains对象
actions = ActionChains(browser)
#action调用以下两个方法完成拖曳操作
actions.drag_and_drop(source,target)
actions.perform()
browser.close()
View Code

执行JavaScript:例如下拉进度条可以直接模拟运行JavaScript,执行execute_script()方法即可实现

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
#将下拉条拉倒最底部
browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
#弹出alert提示框
browser.execute_script('alert("To Bottom")')
browser.close()
View Code

获取节点信息(包括属性,文本以及id位置标签名和大小)

*获取属性
from selenium import webdriver

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
#获取提问按钮
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo)
#打印属性
print(logo.get_attribute('class'))
browser.close()

结果
<selenium.webdriver.remote.webelement.WebElement (session="52975bfa983727a2a7f26b9972c414a2", element="0.9714708708818114-1")>
zu-top-link-logo

*获取文本值
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.text)
browser.close()

结果
提问
View Code

获取id、位置、标签名、和大小

*通过id,location、tag_name、size属性获取对应的值
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')
#获取id值
print(input.id)
#获取位置
print(input.location)
#获取标签名
print(input.tag_name)
#获取大小
print(input.size)
browser.close()

结果
0.8772617338808859-1
{'x': 760, 'y': 7}
button
{'height': 32, 'width': 66}
View Code

切换Frame:网页中有一种节点叫做iframe,也就是子Frame,相当于页面的子页面,结构和外部网页完全一致。Selenium默认打开后是在父级Frame里面操作,而此时如果页面中还有子Frame,则是不能够获取子Frame里面的节点的。则需要使用switch_to_.frame()方法来切换Frame,代码示例如下

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)
#通过switch_to.frame()切换到子页面Frame里面
browser.switch_to.frame('iframeResult')
try:
    #获取子Frame里面的logo节点
    logo = browser.find_element_by_class_name('logo')
    #若不存在打印No Logo
except NoSuchElementException:
    print('No Logo')
#通过switch_to_.parent_frame切回父级Frame
browser.switch_to.parent_frame()
#重新获取logo节点
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)

结果
No Logo
<selenium.webdriver.remote.webelement.WebElement (session="342ed5d025ac85c06d872fdf337edc82", element="0.12105089091907728-2")>
RUNOOB.COM
View Code

延时等待:

  seleniumget()方法会在网页加载结束后结束执行,此时如果要获取page_source,可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中不一定能成功获取,所以需要等待一定的时间从而确保页面加载出来而等待又分为隐式等待和和显式等待。

  • 隐式等待::当时用隐式等待执行测试的时候,若Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则会抛出找不到的节点的异常,即当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间在查找DOM,默认时间为0
  • 显式等待:指定要查找的节点,然后指定一个最长的等待时间。若在规定的时间内加载出来这个节点,就返回查找的节点,若到了规定时间没有加载出来这个节点则会抛出超时异常。

隐式等待

from selenium import webdriver

browser = webdriver.Chrome()
#调用implicitly_wait()方法实现隐式等待
browser.implicitly_wait(10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)

结果
<selenium.webdriver.remote.webelement.WebElement (session="9bc5b8f1ae5203fd98654d854b8b70e6", element="0.6674161481100129-1")>
View Code

显式等待条件

        等待条件                                  含义
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       加载并切换
invisibility_of_element_located              节点不可见
element_to_be_clickable                      节点可点击
staleness_of                            判断一个节点是否仍然在DOM,可判断页面是否已经刷新
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')
#创建WebDriverWait对象,指定最长等待时间 10秒
wait = WebDriverWait(browser,10)
#调用until()方法传入等待条件(条件为id为q的节点出现10秒内是否出现)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
#查找CSS选择器为.btn-serch的按钮,若在10秒内是可点击的,则成功加载出来
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.btn-search')))
print(input,button)
browser.close()

结果
<selenium.webdriver.remote.webelement.WebElement (session="c8d488bc04ef5ad442cab51e8547dc34", element="0.8244517500943758-1")> <selenium.webdriver.remote.webelement.WebElement (session="c8d488bc04ef5ad442cab51e8547dc34", element="0.8244517500943758-2")>
View Code

 前进和后退selenium

*back()方法后退,forward方法前进
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()
time.sleep(1)
browser.forward()
browser.close()
View Code

Cookies

*使用selenium可以方便的对cookies进行获取、添加、删除等操作
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
#获取所有cookies
print(browser.get_cookies())
#添加cookies
browser.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'})
print(browser.get_cookies())
#删除所有cookies
browser.delete_all_cookies()
#重新获取结果为空
print(browser.get_cookies())
browser.close()
View Code

选项卡管理

*当我们在访问网页的时候会开启一个选项卡,可以使用selenuim对选项卡进行操作

import time
from selenium import webdriver

browser = webdriver.Chrome()
#访问百度网页
browser.get('https://www.baidu.com')
#开启一个新的选项卡
browser.execute_script('window.open()')
#调用window_handles属性获取当前开启的所有选项卡
print(browser.window_handles)
#调用switch_to_window()方法切换到第二个选项卡
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(1)
#调用switch_to_window()方法切换到第一个选项卡
browser.switch_to_window(browser.window_handles[0])
browser.get('https://python.org')

结果
['CDwindow-E4ECA535D3501ED974B9B9E0AD36995B', 'CDwindow-C362F44E7078475E2676DD6C5DF455DF']
View Code

异常处理

*在使用selenium的过程中难免会遇到一些错误,一旦出现错误程序便不会在运行了,而我们可以使用try excep语句来捕获各种异常

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()

结果
No Element
View Code

 

 

 

 

 

 

 

 

 

 

posted @ 2018-12-26 21:55  Coolc  阅读(1586)  评论(0编辑  收藏  举报