selenium

介绍

selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题。

selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器。

浏览器驱动

1
2
3
4
5
6
from selenium import webdriver
browser=webdriver.Chrome()
browser=webdriver.Firefox()
browser=webdriver.PhantomJS()
browser=webdriver.Safari()
browser=webdriver.Edge()

安装

selenium + chromedriver 有界面
安装:

  • pip3 install selenium
  • 下载chromdriver.exe放到python安装路径的scripts目录中即可

验证安装:

1
2
3
4
5
6
7
from selenium import webdriver

driver = webdriver.Chrome() # 弹出浏览器

driver.get('https://www.baidu.com')

print(driver.page_source) # 打印HTML内容

selenium+phantomjs 无界面
安装:

验证安装:

1
2
3
4
5
6
7
from selenium import webdriver

driver=webdriver.PhantomJS() #无界面浏览器

driver.get('https://www.baidu.com')

print(driver.page_source)

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from selenium import webdriver
from selenium.webdriver.common.by import By # 按照什么方式查找,By.ID,By.CSS_SELECTOR
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()
try:
browser.get('https://www.baidu.com')

input_tag = browser.find_element_by_id('kw')
input_tag.send_keys('python') # python2中输入中文错误,字符串前加个u
input_tag.send_keys(Keys.ENTER) # 输入回车

wait = WebDriverWait(browser, 10)
wait.until(EC.presence_of_element_located((By.ID, 'content_left'))) # 等到id为content_left的元素加载完毕,最多等10秒

print(browser.page_source) # HTML文本
print(browser.current_url) # 当前的URL
for cookie in browser.get_cookies(): # 获取所有cookie信息
print(cookie['name'], ':', cookie['value'])
finally:
# browser.close() # 关闭窗口
pass

三种选择器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from selenium import webdriver
from selenium.webdriver.common.by import By # 按照什么方式查找,By.ID,By.CSS_SELECTOR

browser = webdriver.Chrome()

browser.get('https://www.baidu.com')

# 以下三种方式达到的都是同一种效果:查找id为kw的标签
# 等同于:input_tag1=browser.find_element_by_id('kw')
input_tag1 = browser.find_element(By.ID, 'kw')


# 等同于:input_tag2=browser.find_element_by_css_selector('#kw')
input_tag2 = browser.find_element(By.CSS_SELECTOR, '#kw')

# 等同于:input_tag3=browser.find_element_by_xpath('//*[@id="kw"]')
input_tag3 = browser.find_element(By.XPATH,'//*[@id="kw"]')

# 注意:browser.find_elements系列与browser.find_element的区别就是,前者是查找多个,后者是只找第一个
div1 = browser.find_element(By.CSS_SELECTOR, 'div') # 找到第一个div标签
div2 = browser.find_elements(By.CSS_SELECTOR, 'div') # 找到所有的div标签,放到列表里
print(input_tag1)
# <selenium.webdriver.remote.webelement.WebElement (session="6710dd55ddc5c168db110da9124d4b08", element="0.711862648489562-1")>
print(input_tag2)
print(input_tag3)
print(div1)
print(div2) # [WebElement,WebElement,WebElement,]

browser.close()

获取标签属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from selenium import webdriver
from selenium.webdriver.common.by import By # 按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait # 等待页面加载某些元素

browser = webdriver.Chrome()

browser.get('https://www.amazon.cn/')

wait = WebDriverWait(browser, 10)
wait.until(EC.presence_of_element_located((By.ID, 'cc-lm-tcgShowImgContainer')))

tag = browser.find_element(By.CSS_SELECTOR, '#cc-lm-tcgShowImgContainer img')

# 获取标签属性,
print(tag.get_attribute('src'))

# 获取标签ID,位置,名称,大小(了解)
print(tag.id) # 0.7950153940221087-2
print(tag.location) # {'x': 0, 'y': 0}
print(tag.tag_name) # img
print(tag.size) # {'height': 0, 'width': 0}

browser.close()

等待元素被加载

  1. selenium只是模拟浏览器的行为,而浏览器解析页面是需要时间的(执行css,js),一些元素可能需要过一段时间才能加载出来,为了保证能查找到元素,必须等待
  2. 等待的方式分两种:
  • 隐式等待:在browser.get(’xxx’)前就设置,针对所有元素有效
  • 显式等待:在browser.get(’xxx’)之后设置,只针对某个元素有效

隐式等待

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from selenium import webdriver
from selenium.webdriver.common.keys import Keys # 键盘按键操作

browser = webdriver.Chrome()

# 隐式等待:在查找所有元素时,如果尚未被加载,则等10秒

browser.implicitly_wait(10)

browser.get('https://www.baidu.com')

input_tag = browser.find_element_by_id('kw')
input_tag.send_keys('美女')
input_tag.send_keys(Keys.ENTER)

contents = browser.find_element_by_id('content_left') # 没有等待环节而直接查找,找不到则会报错
print(contents)

browser.close()

显示等待

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from selenium import webdriver
from selenium.webdriver.common.by import By # 按照什么方式查找,By.ID,By.CSS_SELECTOR
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()
browser.get('https://www.baidu.com')

input_tag = browser.find_element_by_id('kw')
input_tag.send_keys('美女')
input_tag.send_keys(Keys.ENTER)

# 显式等待:显式地等待某个元素被加载

wait = WebDriverWait(browser, 10)
wait.until(EC.presence_of_element_located((By.ID, 'content_left')))

contents = browser.find_element(By.CSS_SELECTOR, '#content_left')
print(contents)

browser.close()

元素交互操作

点击.click() 清空.clear()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from selenium import webdriver
from selenium.webdriver.common.by import By # 按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait # 等待页面加载某些元素

browser = webdriver.Chrome()
browser.get('https://www.amazon.cn/')
wait = WebDriverWait(browser, 10)

input_tag = wait.until(EC.presence_of_element_located((By.ID, 'twotabsearchtextbox')))
input_tag.send_keys('iphone 8')
button = browser.find_element_by_css_selector('#nav-search > form > div.nav-right > div > input')
button.click() # 点击

import time

time.sleep(3)

input_tag = browser.find_element_by_id('twotabsearchtextbox')
input_tag.clear() # 清空输入框
input_tag.send_keys('iphone7plus')
button = browser.find_element_by_css_selector('#nav-search > form > div.nav-right > div > input')
button.click()

# browser.close()

动作链 Action Chains

官网解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()
browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
browser.switch_to.frame('iframeResult') # 切换到iframeResult

source = browser.find_element_by_id('draggable')
target = browser.find_element_by_id('droppable')

actions = ActionChains(browser) # 拿到动作链对象
# drag_and_drop 拖放
actions.drag_and_drop(source, target) # 把动作放到动作链中,准备串行执行
actions.perform() # 执行

# browser.close()

执行JS

在交互动作比较难实现的时候可以自己写JS(万能方法)

1
2
3
4
5
6
7
8
9
10
from selenium import webdriver

browser = webdriver.Chrome()

try:
browser.get('https://www.baidu.com')
browser.execute_script('alert("hello world")') # 打印警告
finally:
# browser.close()
pass

iframe元素的切换

frame相当于一个单独的网页,在父frame里是无法直接查看到子frame的元素的,必须switch_to_frame切到该frame下,才能进一步查找.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from selenium import webdriver

browser = webdriver.Chrome()

try:
browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')

browser.switch_to.frame('iframeResult') # 切换到id为iframeResult的frame

tag1 = browser.find_element_by_id('droppable')
print(tag1)

# tag2=browser.find_element_by_id('textareaCode') #报错,在子frame里无法查看到父frame的元素
browser.switch_to.parent_frame() # 切回父frame,就可以查找到了
tag2 = browser.find_element_by_id('textareaCode')
print(tag2)

finally:
browser.close()

其他

模拟浏览器的前进后退

1
2
3
4
5
6
7
8
9
10
11
12
import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.get('https://www.taobao.com')
browser.get('http://www.sina.com.cn/')

browser.back() # 后退
time.sleep(10)
browser.forward() # 前进
browser.close()

cookies

1
2
3
4
5
6
7
8
9
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies()) # 获取所有cookie
browser.add_cookie({'k1': 'xxx', 'k2': 'yyy'}) #添加cookie
print(browser.get_cookies())

# browser.delete_all_cookies() # 删除所有cookie

选项卡管理

切换选项卡,有js的方式windows.open,有windows快捷键:ctrl+t等,最通用的就是js的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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(10)
browser.switch_to_window(browser.window_handles[0])
browser.get('https://www.sina.com.cn')
browser.close()

异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException, NoSuchFrameException

browser = webdriver.Chrome()

try:
browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
browser.switch_to.frame('iframssseResult')

except TimeoutException as e:
print(e)
except NoSuchFrameException as e:
print(e)
finally:
browser.close()