Selenium 不同于requests这种模拟浏览器进行数据爬取的库,而是直接运行在浏览器中,就如同真正的用户进行操作selenium中文文档selenium暂未发现官方文档,上述文档为爱好者自制
selenium库并非内置,所以需要导入pip install selenium
selenium是一个自动化程序,自动操控浏览器,所以需要一个插件可以对浏览器进行操作
将下载的驱动放入环境变量中(如果不知道什么是环境变量就放在Python安装文件夹中即可)
Selenium是一个很庞大的库,这里不建议直接使用import直接导入全库,而是用到什么导入什么。
启动selenium的话我们只需导入from selenium import webdriver
即可
顾名思义,这个是用于启动浏览器的方法webdriver
后面可以跟着需要启动的浏览器名称
比如.Firefox()
(火狐浏览器).Edge()
windows10系统默认浏览器.Chrome()
谷歌浏览器.Opera()
欧朋浏览器.Safari()
Mac等苹果设备自带浏览器,启用这些浏览器的前提是你已经下载好驱动并放入环境变量中(这些浏览器方法首字母需要大写!!!)
driver = webdriver.Firefox()
启动火狐浏览器并将此对象赋值给driver
driver方法 | 作用 |
---|---|
.name |
检查驱动是基于什么浏览器(假设为.Firefox(),返回值则为firefox) |
.get(网址) |
已get方法打开指定网址 |
.title |
返回当前页面标题 |
.current_url |
当前url |
.page_source |
获取当前页面的源(重要方法) |
.back() |
在浏览器的历史记录中后腿一步。 |
.forward() |
在浏览器历史记录中向前迈进了一步。 |
.refresh() |
刷新页面 |
.implicitly_wait(时间) |
隐式等待(下方有此方法详细使用说明) |
.set_script_timeout(时间) |
异步加载页面时等待的时间 |
.set_page_load_timeout(时间) |
设置等待页面加载的时间,超出后报错(在get前使用) |
.desired_capabilities |
返回当前驱动的信息 |
使用方法 | 作用 |
---|---|
.current_window_handle |
返回当前窗口的句柄(系统会给每个窗口分配一个句柄,可以根据句柄移动窗口、改变窗口大小、把窗口最小化等等。) |
.window_handles |
返回所以窗口的句柄 |
.maximize_window() |
最大化窗口 |
.minimize_window() |
最小化窗口 |
.fullscreen_window() |
将窗口全屏 |
.set_window_size(宽,高) |
指定窗口的大小 |
.get_window_size() |
获取窗口的大小 |
,set_window_position(x,y) |
设置窗口的位置 |
.get_window_position() |
获取窗口的位置 |
.set_window_rect(x,y,宽,高) |
设置状况的位置以及大小 |
.get_window_rect() |
获取当前窗口的位置以及大小 |
.close() |
关闭窗口 |
.quit() |
退出驱动程序并关闭窗口 |
.switch_to |
用于切换焦点(多窗口切换与切换到页面中内置页面frame元素中使用) |
常用查找方法 | 作用 |
---|---|
.find_element_by_id(id名) |
按id查找元素。(找到第一个符号要求的元素后立即返回) |
.find_elements_by_id(id名) |
按id查找多个元素。(找到多个符合要求的元素后合并成列表返回) |
.find_element_by_class_name(class名) |
按class名查找元素。(同样拥有查找多个元素的elements方法) |
.find_element_by_xpath(xpath规则) |
按xpath规则查找元素。(同样拥有查找多个元素的elements方法) |
.find_element_by_link_text(文本) |
根据标签中的文本查找元素,必须要全文匹配,比如 全文匹配 时文本必须为’全文匹配’(同样拥有查找多个元素的elements方法) |
.find_element_by_partial_link_text(文本) |
根据标签中的文本查找元素,部分匹配即可,比如 全文匹配 时文本可以为’匹配’(同样拥有查找多个元素的elements方法) |
.find_element_by_name(name名) |
按名称查找元素。(同样拥有查找多个元素的elements方法) |
.find_element_by_tag_name(HTML标签) |
按HTML标签查找元素。(同样拥有查找多个元素的elements方法) |
.find_element_by_css_selector(css选择器) |
根据css选择器查找元素。(同样拥有查找多个元素的elements方法) |
.find_element(策略器 ,'元素') |
策略器包含By.ID ,By.TAG_NAME ,By.CLASS_NAME ,By.NAME (同样拥有查找多个元素的elements方法) 策略器需要导入from selenium.webdriver.common.by import By |
模拟鼠标的单击,双击,右击,悬浮等操作。需要引入from selenium.webdriver.common.action_chains import ActionChains
。创建行为链需要先实例化一个鼠标ActionChains(WebDriver实例)
比如mouse = ActionChains(self.driver)
行为链模拟鼠标方法 | 作用 |
---|---|
.perform() |
执行操作(行为链是一系列操作,最后需要使用此方法让其他方法开始执行,类似数据库事务的提交操作) |
.reset_actions() |
清除操作(相当于数据库中事务的回滚) |
.click(点击对象) |
点击左键 |
.click_and_hold(点击对象) |
按住左键(与点击不同,这是按住不松) |
.context_click(点击对象) |
点击右键 |
.double_click(点击对象) |
双击鼠标左键 |
.drag_and_drop(下移对象, 上移对象) |
将指定元素上下移动 |
.drag_and_drop_by_offset(点击对象, x, y) |
点击指定对象后拖动至指定xy区域 |
.move_by_offset(x, y) |
移动鼠标到坐标xy |
.move_to_element(指定对象) |
将鼠标移动到指定对象上并开始悬停 |
.move_to_element_with_offset(指定对象, x, y) |
将鼠标移动到指定对象后并偏移xy。 |
.release(指定对象) |
在指定对象上放开鼠标,不指定对象则为当前位置放开鼠标 |
行为链模拟键盘方法 | 作用 |
---|---|
.key_down(按键, 发送对象) |
按下键盘按键,但不释放键盘(需要同时按住多键时使用),每次只能传入一个按键,如果没有发送对象,则想当前焦点发送 |
.send_keys(按键) |
选择按键 |
.key_up(按键, 发送对象) |
放开按键,如果没有发送对象,则想当前焦点发送 |
send_keys_to_element(发送对象, 按键) |
点击键盘 |
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
# 假设需要按ctrl+c
driver = webdriver.Firefox()
ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
使用方法 | 作用 |
---|---|
.get_screenshot_as_file(文件路径.png) |
要将屏幕快照保存到指定路径.save_screenshot(文件路径.png) 方法作用相同 |
.get_screenshot_as_png() |
获取屏幕快照的二进制并作为返回值返回 |
.get_screenshot_as_base64() |
获取屏幕快照的base64编码字符串并作为返回值返回,在HTML中的嵌入图像中非常有用。 |
使用方法 | 作用 |
---|---|
.get_cookies() |
用字典的方式返回获取的cookies |
.get_cookie(cookie名) |
按cookie寻找cookie |
.delete_cookie(名称) |
删除指定名称的cookie |
.delete_all_cookies() |
删除全部cookie |
.add_cookie(cookie) |
将cookie添加到当前网页 |
隐式等待只需要使用driver.implicitly_wait(等待时间)
方法即可。隐式等待一旦设置后,整个程序的生命周期中都将会启动,下列代码会让浏览器等待网页加载,但如果超过等待时间,则会出现异常(隐式等待一旦设定,整个程序中使用webdriver寻找元素都会进行等待,所以不太推荐使用隐式等待,大多数情况下可以使用显式等待)
下面有个网站,因为图片应该使用了懒加载(校点在哪,加载哪里,我们直接获取网页源码会无法得到想要的结果,所以我们就可以使用等待,等我们需要的元素出现后在保存页面)
from selenium import webdriver
class Study:
def __init__(self):
self.url = 'https://article.xuexi.cn/articles/index.html?art_id=15308933272663801705&item_id=15308933272663801705&study_style_id=feeds_default&showmenu=true&aid=15308933272663801705&item_type=1&recoid=12578234090040657023_1581240011&cid=&study_comment_disable=1&pid=34682268069627302&ref_read_id=8c1f7cad-22cf-473b-be16-3bf204f50468&ptype=100&source=share&share_to=wx_single&from=singlemessage'
self.header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
self.driver = None
def open_web(self):
"""打开浏览器"""
driver = webdriver.Firefox()
# 最小化浏览器
driver.minimize_window()
return driver
def get_url(self):
"""访问url"""
# 使用selenium
driver = self.open_web()
driver.get(self.url)
# 隐式等待
driver.implicitly_wait(1)
driver.find_element_by_css_selector('img[class="xxqg-image"]')
return driver.page_source
def run(self):
"""启动"""
# 保存网页源码
html = self.get_url()
print(html)
if __name__ == '__main__':
Study().run()
显式等待需要使用到WebDriverWait
与expected_conditions
显式等待要用到的方法我们需要先导入一下
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.implicitly_wait(3)
driver.find_element_by_css_selector('img[class="xxqg-image"]')
# 显示等待(内都)
WebDriverWait(driver, 3).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[class="xxqg-image"]'))
)
WebDriverWait会对until中的期望条件不断进行测试,如果在指定时间无法通过测试,那么就会返回异常(默认0.5秒一次,可以在WebDriverWait()
方法第三个参数处更改默认时间,如WebDriverWait(driver, 3, 0.1)
)WebDriverWait()
除了.until()
还有.until_not()
方法
相对于隐式等待,显示等待提供了很多方法可以作为等待条件expected_conditions(EC)
常用期望(expected_conditions )方法 | 作用 |
---|---|
.title_is(标题) |
检查标题是否达到预期(匹配则返回True,否则返回false。) |
.title_contains(标题) |
检查标题是否包含大小写 |
.presence_of_element_located((By类,'期望条件')) |
检查期望条件是否在页面源码中出现,不可以见元素也算(这里传入的必须是一个元组) |
.presence_of_all_elements_located((By类,'期望条件')) |
检查是否满足一直一个期望条件 |
.visibility_of_element_located((By类,'期望条件')) |
检查期望条件是否在可见页面中出现,必须为可见元素,在页面中宽高大于0的为可见元素(这里传入的必须是一个元组) |
.visibility_of(期望元素) |
页面中是否出现期望元素 |
presence_of_all_emement_located() |
检查页面是否所以元素都已经加装完毕 |
.url_contains(期望元素) |
检查url是否和期望元素完全符合 |
.url_to_be(期望元素) |
与.url_contains(元素) 方法作用类型,区别是url_to_be使用双等==判断是否一致url_contains使用is判断是否一致 |
.url_matches(期望元素) |
检查url中是否包含期望元素 |
.url_changes(期望元素) |
是否与期望元素不同 |
.element_to_be_cliable() |
检查期望调试是否已经可用并且可以点击 |
期望条件有很多我并没有列举出全部,有需要的可以去selenium库中的expected_conditions.py文件中查看
如果使用多个get,则会打开多个浏览器,如果我们想在同一个浏览器中启动做个窗口需要用到.execute_script()
方法执行js命令,打开一个新窗口的js命令为window.open('网址')
打开窗口需要用到
driver.get('https://www.baidu.com')
driver.execute_script('window.open("https://www.baidu.com/baidu?wd=python")')
切换窗口我们需要用到.switch_to
方法切换窗口与.window_handles
方法来获取窗口的句柄
.switch_to常用方法 | 用法 |
---|---|
.switch_to.window(窗口句柄) | 切换窗口焦点(必须拿到窗口句柄,可以通过.window_handles 方法获得当前浏览器中全部窗口的句柄),如driver.switch_to.window(driver.window_handles[0]) |
.switch_to.frame() | 切换到嵌套页面中(HTML中 标签中的内容即为嵌套页面),可以使用多种方法找到嵌套页面,如driver.switch_to.frame('frame_name') driver.switch_to.frame(1) driver.switch_to.frame(driver.find_element_by_tag_name("iframe")) |
.switch_to.parent_frame() | 切换到父页面中 |
class Study:
def __init__(self):
self.url = 'https://article.xuexi.cn/articles/index.html?art_id=15308933272663801705&item_id=15308933272663801705&study_style_id=feeds_default&showmenu=true&aid=15308933272663801705&item_type=1&recoid=12578234090040657023_1581240011&cid=&study_comment_disable=1&pid=34682268069627302&ref_read_id=8c1f7cad-22cf-473b-be16-3bf204f50468&ptype=100&source=share&share_to=wx_single&from=singlemessage'
self.header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
self.driver = None
def open_web(self):
"""打开浏览器"""
driver = webdriver.Firefox()
# 最小化浏览器
driver.minimize_window()
return driver
def get_url(self):
"""访问url"""
# 使用selenium
driver = self.open_web()
driver.get(self.url)
# 网页逻辑太差,且图片应该为懒加载,所以需要使用此条件来判断是否加载完成,注释下方两行获取的网页将不完整
# 显式等待
WebDriverWait(driver, 3).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[class="xxqg-image"]'))
)
return driver.page_source
def run(self):
"""启动"""
# 保存网页源码
html = self.get_url()
print(html)
if __name__ == '__main__':
Study().run()
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
"""
测试目标(此模块只是单纯的用于selenium模块的学习使用)
自动登录智慧树(https://passport.zhihuishu.com/login)
"""
# Wisdom(智慧)
class WisdomTree:
def __init__(self, uid, password, school='在这里写上一个学校'):
# 手机号登陆(参数让登陆后直接跳转到个人页面)
self.login_url = 'https://passport.zhihuishu.com/login?service=https://onlineservice.zhihuishu.com/login/gologin'
# 学号登陆
self.login_id_url = 'https://passport.zhihuishu.com/login?service=https://onlineservice.zhihuishu.com/login/gologin#studentID'
self.id_name = uid
self.password = password
self.school_name = school
self.driver = None
def open_web(self):
"""打开浏览器"""
self.driver = webdriver.Firefox()
# 最小化浏览器
self.driver.minimize_window()
def login_web(self):
"""登陆网站"""
while True:
# 判断输入的为手机号还是学号(1开头为手机号2开头为学号,其余开头为输入错误)
if self.id_name[0] == '1' and len(self.id_name) == 11:
# 打开手机账号的登陆网址
self.driver.get(self.login_url)
# 寻找登陆名输入框并输入用户名
login_name = self.driver.find_element_by_id('lUsername')
login_name.send_keys(self.id_name)
# 寻找密码栏输入框并输入密码
login_password = self.driver.find_element_by_id('lPassword')
login_password.send_keys(self.password)
# 执行点击(click)事件
login_click = self.driver.find_element_by_class_name('wall-sub-btn')
login_click.click()
return '正在通过电话号登录'
elif self.id_name[0] == '2' and len(self.id_name) == 11:
# 打开学号账号的登陆网址
self.driver.get(self.login_id_url)
# 寻找学校输入框后输入学校
school = self.driver.find_element_by_class_name('school-search-ipt')
school.send_keys(self.school_name)
# 选择学校(填写学校后需要鼠标出发点击事件确定学校,否则无法登录)
school_click = self.driver.find_element_by_xpath('//*[@id="schoolListCode"]/li')
# 实例化鼠标
mouse = ActionChains(self.driver)
# 点击学校
mouse.click(school_click)
mouse.perform()
# 寻找学号栏并输入学号
uid = self.driver.find_element_by_id('clCode')
uid.send_keys(self.id_name)
# 寻找密码栏输入框并输入密码
password = self.driver.find_element_by_id('clPassword')
password.send_keys(self.password)
# 执行点击(click)事件
login_click = self.driver.find_element_by_class_name('wall-sub-btn')
login_click.click()
return '正在通过学号登录'
else:
self.id_name = input('输入有误,请重新输入学号或手机号:')
def run(self):
"""启动代码"""
# 打开浏览器
self.open_web()
# 登陆网站
self.login_web()
if __name__ == '__main__':
user = input('请输入学号或手机号:')
pd = input('请输入密码:')
WisdomTree(user, pd).run()
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# @Author : 寻觅
# @File : 图片爬取.py
# @Time : 2020/2/12 13:24
# @Software: PyCharm
import requests
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
from bs4 import BeautifulSoup
class Study:
def __init__(self):
self.url = 'https://article.xuexi.cn/articles/index.html?art_id=15308933272663801705&item_id=15308933272663801705&study_style_id=feeds_default&showmenu=true&aid=15308933272663801705&item_type=1&recoid=12578234090040657023_1581240011&cid=&study_comment_disable=1&pid=34682268069627302&ref_read_id=8c1f7cad-22cf-473b-be16-3bf204f50468&ptype=100&source=share&share_to=wx_single&from=singlemessage'
self.header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
self.driver = None
def open_web(self):
"""打开浏览器"""
driver = webdriver.Firefox()
# 最小化浏览器
driver.minimize_window()
return driver
def get_url(self):
"""访问url"""
# 使用requests无法取得完整的页面源码,如下
# html = requests.get(self.url, headers=self.header)
# html.encoding = 'utf-8'
# return html.content
# 使用selenium
driver = self.open_web()
driver.get(self.url)
# 网页逻辑太差,且图片应该为懒加载,所以需要使用此条件来判断是否加载完成,注释下方两行获取的网页将不完整
# 隐式等待
# driver.implicitly_wait(1)
# driver.find_element_by_css_selector('img[class="xxqg-image"]')
# 显式等待
WebDriverWait(driver, 3).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[class="xxqg-image"]'))
)
return driver.page_source
def write_html(self, html):
"""写入到本地"""
with open('河南学习强国.html', 'w') as w:
w.write(html)
# extract(提取)
def data_extract(self, data):
"""数据提取"""
bs_data = BeautifulSoup(data, 'lxml')
data = bs_data.select('img[class="xxqg-image"]')
img_url = []
for i in data:
img_url.append(i['data-src'])
return img_url
def get_img(self, img_url):
"""将图片链接转为二进制格式的图片"""
img_data = []
i = 1
print('获取的网页中首个图片为:', img_url[0])
for url in img_url:
print('\r共有%d张图片。正在下载第%d张图片' % (len(img_url), i), end=" ")
img = requests.get(url, headers=self.header)
img_data.append(img)
i += 1
return img_data
def write_img(self, img_data):
"""保存图片"""
i = 1
for img in img_data:
with open(f'图片/第{i}张图片.jpg', 'wb') as w:
print('\r共有%d张图片。正在保存第%d张图片' % (len(img_data), i), end=" ")
w.write(img.content)
i += 1
def run(self):
"""启动"""
# 保存网页源码
html = self.get_url()
# 保存网页源码
self.write_html(html)
# 获取网页源码
# html = open('河南学习强国.html').read()
# 提取图片链接
# print('正在获取图片链接')
# img_url = self.data_extract(html)
# 将链接转换为图片
# print('正在将链接转换为图片')
# img_data = self.get_img(img_url)
# 保存图片
# print('\n正在保存')
# self.write_img(img_data)
# print('\n程序完成')
if __name__ == '__main__':
Study().run()