python爬虫---selenium模块

1、原理及安装

1.1 原理

Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,Edge等。这个工具的主要功能包括:测试与浏览器的兼容性——测试应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成.Net、Java、Perl等不同语言的测试脚本。—百度百科

自动化程序与浏览器流程图

1.2 安装
1.2.1 selenium
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
1.2.2 Chrome浏览器
1.2.3 Chrome浏览器驱动

浏览器驱动

1.3 环境配置
  • 浏览器驱动下载后将其放在没有中文的路径下(只需留下exe应用程序即可)

驱动位置

  • 复制路径将其放入环境变量中

环境变量配置

  • 若不配置环境变量则每次都需要配置路径
from selenium import webdriver

wd = webdriver.Chrome(service=Service(r'E:\software\anaconda3\envs\crawler\chromedriver.exe'))
  • 配置环境变量后则可以省去此步骤
from selenium import webdriver

wd = webdriver.Chrome()

2、元素定位

  • 每次使用selenium控制驱动打开浏览器的时候,网页总是自动关闭
from selenium import webdriver

# 创建 WebDriver 对象
wd = webdriver.Chrome()
# 调用WebDriver对象的get方法打开指定网址
wd.get('https://www.byhy.net/_files/stock1.html')
  • 可以使用下面的驱动方式使得页面一直显示
from selenium import webdriver

# 不自动关闭浏览器
options = webdriver.ChromeOptions()
options.add_experimental_option("detach", True)

# 将option作为参数添加到Chrome中
wd = webdriver.Chrome(options=options)
wd.get('https://www.baidu.com/')
2.1 通过id定位
# 根据id选择元素,返回的就是该元素对应的WebElement对象
element_id = wd.find_element(By.ID, 'wrapper')
2.2 通过class定位
element_class = wd.find_element(By.CLASS_NAME, "wrapper_new")
print(element_class)
2.3 通过name定位
element_name = wd.find_element(By.NAME, "baidu-site-verification")
print(element_name)  # 没有内容只返回对象
print(element_name)
2.4 通过tag_name定位
element_tag_name = wd.find_element(By.TAG_NAME, "meta")
print(element_tag_name)  # 没有内容只返回对象
print(element_tag_name)
2.5 通过Xpath语法定位

只能定位到标签位置,并不能直接定位到内容然后返回,只能返回对象再使用.text获取内容

element_Xpath = wd.find_element(By.XPATH, "//div[@class='nav-logo']/a")
print(element_Xpath)
2.6 通过css语法定位
element_CSS = wd.find_element(By.CSS_SELECTOR, "#db-nav-movie")
print(element_CSS)
2.7 通过文本定位
wd.find_element(By.XPATH, "//*[contains(text(),'排行榜')]").click() # 点击并进行跳转操作

我们发现直接使用上面的程序进行获取会报错,这是因为浏览器的加载需要时间,程序没有等待而是直接获取元素,这就导致获取失败

  • 解决方式:

    • 强制等待:

      # 让程序睡眠一秒等待浏览器加载
      import time
      time.sleep(1)
      
    • 显式等待:

      # 实际上是依据try-except异常捕获进行判断
      
      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.common.exceptions import TimeoutException
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC
      
      wd = webdriver.Chrome()
      wd.get("https://movie.douban.com/top250?start=25&filter=")
      def search():
      	try:
          	element = WebDriverWait(driver, 10, 0.5).until(
              	EC.presence_of_element_located((By.ID, "wrapper"))
          	)
      	except TimeoutException:
          	return search()
      
    • 隐式等待:

      # 隐式等待,每隔半秒寻找一次元素,最长等10秒
      wd.implicitly_wait(10) 
      

3、浏览器控制

3.1 修改浏览器窗口大小
3.1.1 修改指定大小
wd.set_window_size(600, 800)
3.1.2 全屏显示
wd.maximize_window()
3.2 浏览器访问

webdriver提供了backforward两种方式实现页面的前进或后退。

下面我们使用豆瓣电影TOP250作为例子进行演示:

​ 1、访问主页

​ 2、进入排行榜

​ 3、进入剧情分类

​ 4、返回排行榜

​ 5、返回主页

​ 6、进入排行榜

import time

from selenium import webdriver

wd = webdriver.Chrome()
# 访问主页链接
wd.get("https://movie.douban.com/top250")
time.sleep(1)

# 进入排行榜
wd.get("https://movie.douban.com/chart") # 在原标签页面打开
# # 新标签中打开
# js = "window.open('https://movie.douban.com/chart')"
# wd.execute_script(js)
time.sleep(1)

# 进入剧情分类
wd.get("https://movie.douban.com/typerank?type_name=%E5%89%A7%E6%83%85&type=11&interval_id=100:90&action=")
time.sleep(5)

# 返回排行榜
wd.back()
time.sleep(1)

# 返回主页
wd.back()
time.sleep(1)

# 进入排行榜
wd.forward()
time.sleep(1)
  • 刷新页面
wd.refrech()
  • 切换页面
# 获取打开的多个窗口句柄
windows = driver.window_handles
# 切换到当前最新打开的窗口
wd.switch_to.window(windows[-1])

4、鼠标操作

并不是直接操作我们现在使用的鼠标,而是使用抽象出来的鼠标进行操作

4.1 ActionChains方法

执行动作需要要使用perform()方法,否则动作不执行

click(on_element=None) ——单击鼠标左键
click_and_hold(on_element=None) ——点击鼠标左键,不松开
context_click(on_element=None) ——点击鼠标右键
double_click(on_element=None) ——双击鼠标左键
drag_and_drop(source, target) ——拖拽到某个元素然后松开
key_down(value, element=None) ——按下某个键盘上的键
key_up(value, element=None) ——松开某个键
move_to_element(to_element) ——鼠标移动到某个元素
perform() ——执行链中的所有动作
release(on_element=None) ——在某个元素位置松开鼠标左键
send_keys(*keys_to_send) ——发送某个键到当前焦点的元素
send_keys_to_element(element, *keys_to_send) ——发送某个键到指定元素
move_by_offset(x,y)  ——移动到某个坐标
4.2 鼠标移动

待执行动作:

​ 1、移动到value值为Write on hover的元素上,显示为Mouse moved;

​ 2、移动到value值为Blank on hover的元素上,显示框清空;

​ 3、最后再移动到value值为Write on hover的元素上。

这种方式对有隐藏属性元素操作十分有用。

action = ActionChains(wd)
time.sleep(2)

action.move_to_element(write_element).perform()
time.sleep(2)

action.move_to_element(blank_element).perform()
time.sleep(2)

action.move_to_element(write_element).perform()
time.sleep(3)

wd.quit()
4.3 鼠标拖拽

待执行动作:

​ 1、将被拖拽元素拖拽到第一个方框,观察变化;

​ 2、将被拖拽元素拖拽到第二个方框,观察变化。

action.drag_and_drop(item, item1).perform()
time.sleep(1)

action.drag_and_drop(item, item3).perform()
time.sleep(5)
4.4 鼠标点击
  • 示例网站:http://sahitest.com/demo/clicks.htm

待执行动作:

​ 1、点击单击元素;

​ 2、点击双击元素;

​ 3、点击右击元素;

​ 4、点击选择元素。

# 链式用法
ActionChains(wd).click(click).double_click(click_double).context_click(click_right).\
    click(click_select1).click(click_select2).click(click_select3).\
    click(click_checkbox).perform()

5、键盘操作

5.1 keys类键盘操作
操作作用说明
Keys.F1F1键
Keys.SPACE空格
Keys.TABTab键
Keys.ESCAPEESC键
Keys.ALTAlt键
Keys.SHIFTShift键
Keys.ARROW_DOWN向下箭头
Keys.ARROW_LEFT向左箭头
Keys.ARROW_RIGHT向右箭头
Keys.ARROW_UP向上箭头
5.2 组合操作
操作作用说明
send_keys(Keys.CONTROL,‘a’)全选(Ctrl+A)
send_keys(Keys.CONTROL,‘c’)复制(Ctrl+C)
send_keys(Keys.CONTROL,‘x’)剪切(Ctrl+X)
send_keys(Keys.CONTROL,‘v’)粘贴(Ctrl+V)
5.3 示例

待执行动作:

​ 1、找到包含排行第一电影名称的元素;

​ 2、将其复制到豆瓣电影的搜索框中;

​ 3、使用鼠标操作进行点击。

# 定位到第一个电影标题
title = wd.find_element(By.XPATH, "//div[@class='hd']/a/span[1]")

# 获取元素的文本
text_to_copy = title.text

# # 使用JavaScript将文本复制到剪贴板
wd.execute_script("window.getSelection().selectAllChildren(arguments[0]);window.getSelection().rangeCount > 0 && window.getSelection().getRangeAt(0).deleteContents();", title)
# wd.execute_script("document.execCommand('copy')")
action = ActionChains(wd)
action.send_keys(Keys.CONTROL, "c")
# 定位到搜索框
input_ = wd.find_element(By.XPATH, "//div[@class='inp']/input")

# 粘贴复制的文本到搜索框
input_.send_keys(text_to_copy)

# 等待搜索按钮加载完成
search_button = WebDriverWait(wd, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[@value='搜索']")))

# 点击搜索按钮
search_button.click()

6、元素等待

6.1 强制等待
# 让程序睡眠一秒等待浏览器加载
import time
time.sleep(1)
6.2 显式等待
# 使用EC类中的方法进行判断

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wd = webdriver.Chrome()
wd.get("https://movie.douban.com/top250?start=25&filter=")
def search():
	try:
    	element = WebDriverWait(driver, 10, 0.5).until(
        	EC.presence_of_element_located((By.ID, "wrapper")) # 判断ID为wrapper元素是否可见
    	)
	except TimeoutException:
    	return search()
方法描述
title_is(‘百度一下’)判断当前页面的 title 是否等于预期
title_contains(‘百度’)判断当前页面的 title 是否包含预期字符串
presence_of_element_located(locator)判断元素是否被加到了 dom 树里,并不代表该元素一定可见
visibility_of_element_located(locator)判断元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0
text_to_be_present_in_element(locator , ‘百度’)判断元素中的 text 是否包含了预期的字符串
ext_to_be_present_in_element_value(locator , ‘某值’)判断元素中的 value 属性是否包含了预期的字符串
frame_to_be_available_and_switch_to_it(locator)判断该 frame 是否可以 switch 进去,True 则 switch 进去,反之 False
invisibility_of_element_located(locator)判断元素中是否不存在于 dom 树或不可见
element_to_be_clickable(locator)判断元素中是否可见并且是可点击的
staleness_of(element)等待元素从 dom 树中移除
element_to_be_selected(element)判断元素是否被选中,一般用在下拉列表
element_selection_state_to_be(element, True)判断元素的选中状态是否符合预期,参数 element,第二个参数为 True/False
element_located_selection_state_to_be(locator, True)跟上一个方法作用相同,但传入参数为 locator
alert_is_present()判断页面上是否存在 alert
6.3 隐式等待
# 隐式等待,每隔半秒寻找一次元素,最长等10秒,超过时间后返回异常
wd.implicitly_wait(10) 

7、高级操作

7.1 无界面启动

优势:

​ 1、速度更快:Headless模式下的测试速度通常比普通模式更快。这对于大规模测试或需要频繁执行的 测试场景非常有利。

​ 2、更加稳定Headless模式下的测试不会弹出可见的浏览器窗口,可以在后台静默运行,不影响用户体 验。同时,由于无需考虑浏览器窗口的操作,测试更稳定,容易集成到持续集成(CI)系统中。

from selenium import webdriver

option = webdriver.ChromeOptions()
# 加载浏览器的静默模式
option.add_argument("--headless")

driver = webdriver.Chrome(options=option)
driver.get("https://www.baidu.com")
print(driver.page_source)

driver.quit()
7.2 页面切换

点击跳转链接打开新页面时,selenium依然在之前的页面上进行操作,若想在新页面操作,需要更新操作页面。

# 返回的值是一个列表,按照时间顺序进行排序
wd.window_handles[i]
from selenium.webdriver.common.by import By
from selenium import webdriver
import time

handles = []
wd = webdriver.Chrome()
wd.get("https://movie.douban.com/top250?start=")
wd.implicitly_wait(5)

handles.append(wd.current_window_handle)
wd.find_element(By.XPATH, "//div[@class='global-nav-items']/ul/li/a").click()

time.sleep(1)
# 切换到最新打开的窗口
# wd.switch_to.window(wd.window_handles[-1])
handles.append(wd.current_window_handle)

print(handles)

>>>['74AB56A47773D439438ECAB53147B24B', '74AB56A47773D439438ECAB53147B24B']
from selenium.webdriver.common.by import By
from selenium import webdriver
import time

handles = []
wd = webdriver.Chrome()
wd.get("https://movie.douban.com/top250?start=")
wd.implicitly_wait(5)

handles.append(wd.current_window_handle)
wd.find_element(By.XPATH, "//div[@class='global-nav-items']/ul/li/a").click()

time.sleep(1)
# 切换到最新打开的窗口
wd.switch_to.window(wd.window_handles[-1])
handles.append(wd.current_window_handle)

print(handles)

>>>['5FEA7C45627785F02C6B7D56409D0E39', '8EC96C8F3F2978F524D49AE2F54F55A1']
  • 通过观察句柄的异同,我们可以判断,实现了页面的更新。
7.3 表单切换

在页面中有时可能遇到frame/iframe表单嵌套的操作,无法直接获取被嵌套元素,这时我们就需要进行表单切换操作。

# 以QQ切换为密码登录为例

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

handles = []
wd = webdriver.Chrome()
wd.get("https://qzone.qq.com/")
wd.implicitly_wait(5)

login_frame = wd.find_element(By.ID, "login_frame")

# 切换到iframe
wd.switch_to.frame(login_frame)
wd.find_element(By.ID, "switcher_plogin").click()

username = wd.find_element(By.XPATH, "//input[@id='u']")
password = wd.find_element(By.XPATH, "//input[@id='p']")

username.send_keys("123")
password.send_keys("123")

wd.find_element(By.XPATH, "//a[@class='login_button']").click()
time.sleep(1)
7.4 selenium模拟Javascript
7.4.1 弹窗处理

获取弹窗内容方式。

方法描述
text获取弹窗中的文字
accept接受(确认)弹窗内容
dismiss解除(取消)弹窗
send_keys发送文本至警告框
7.4.2 模拟动作
from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
temp_height = 0
while True:
    # 滑动下拉框
    driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
    time.sleep(1)
    check_height = driver.execute_script(
        "return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;")
    if check_height == 11922:
        break
7.5 cookies操作
7.5.1 调用方法
方法描述
get_cookies获得所有cookies信息
get_cookies(name)返回指定name名称的cookies信息
add_cookies(cookie_dict)添加cookie,必须有name值和value值
delete_cookie(name)删除特定的cookie信息
delete_all_cookies()删除所有的cookie信息
7.5.2 cookies属性值
属性含义
name必选参数,规定cookies的名称
value必选参数,规定cookies的值
expire可选参数,规定cookies的有效期
domain可选参数,规定cookies的域名
path可选参数,规定cookies服务器的路径
secure可选参数,规定是否通过安全的https连接来传输cookies
httpOnly可选参数,防止XSS攻击(跨站脚本攻击)
7.6 其他操作
7.6.1 常见操作
# 截图
get_screenshot_as_file()

# 获取当前页面url
driver.current_url

# 获取当前html源码
driver.page_source

# 获取当前页面标题
driver.title

# 获取浏览器名称
driver.name

# 对页面进行截图,返回二进制数据
driver.get_screenshot_as_png()

# 设置浏览器尺寸
driver.get_window_size()

# 获取浏览器尺寸,位置
driver.get_window_rect()

# 获取浏览器位置(左上角)
driver.get_window_position()

# 设置浏览器尺寸
driver.set_window_size(width=640, height=480)

# 设置浏览器位置(左上角)
driver.set_window_position(x=500, y=600)

# 设置浏览器的尺寸,位置
driver.set_window_rect(x=200, y=400, width=1000, height=600)
7.6.2 隐藏selenium指纹特征
import time
from selenium.webdriver import Chrome

option = webdriver.ChromeOptions()
option.add_argument("--headless")
# 无头浏览器需要添加user-agent来隐藏特征
option.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36')

driver = Chrome(options=option)
driver.implicitly_wait(5)

with open('stealth.min.js') as f:
    js = f.read()

driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  "source": js
})

driver.get('https://bot.sannysoft.com/')
driver.save_screenshot('hidden_features.png')

相关代码地址: https://gitee.com/justinc666/crawler/tree/master/selenium

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值