Python selenium模块
一、环境安装
- 下载安装selenium:pip install selenium
- 下载浏览器驱动程序:http://chromedriver.storage.googleapis.com/index.html
二、selenium的简单实用
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
if __name__ == '__main__':
# 配置chromdriver驱动
browser = webdriver.Chrome(service=Service('./chromedriver.exe'))
url = 'https://www.bilibili.com/'
browser.get(url)
time.sleep(1)
# 访问bilibili搜索selenium
browser.find_element(By.XPATH, '//*[@id="nav-searchform"]/div[1]/input').send_keys('selenium')
time.sleep(1)
browser.find_element(By.XPATH, '//*[@id="nav-searchform"]/div[2]').click()
time.sleep(6)
browser.quit()
# 注意:在selenium旧版本采用以下方式配置驱动
webdriver.Chrome(executable_path='./chromedriver')
三、selenium提取数据
-
driver对象的常用属性和方法
在使用selenium过程中,实例化webdriver对象后,webdriver对象有一些常用的属性和方法 driver.page_source 当前标签页浏览器渲染之后的网页源代码 driver.current_url 当前标签页的url driver.close() 关闭当前标签页,如果只有一个标签页则关闭整个浏览器 driver.quit() 关闭浏览器 driver.forward() 页面前进 driver.back() 页面后退 driver.screen_shot(img_name) 页面截图
-
webdriver对象定位标签元素获取标签对象的方法
find_element_by_id (返回一个元素) find_element(s)_by_class_name (根据类名获取元素列表) find_element(s)_by_name (根据标签的name属性值返回包含标签对象元素的列表) find_element(s)_by_xpath (返回一个包含元素的列表) find_element(s)_by_link_text (根据连接文本获取元素列表) find_element(s)_by_partial_link_text (根据链接包含的文本获取元素列表) find_element(s)_by_tag_name (根据标签名获取元素列表) find_element(s)_by_css_selector (根据css选择器来获取元素列表) # 注意: # selenium更新新版本之后统一采用以下方法获取标签对象: from selenium.webdriver.common.by import By driver.find_element(By.XPATH, 'xpath') driver.find_element(By.ID, 'id') # 以上其它类似使用
-
标签对象提取文本内容和属性值
find_element仅仅能够获取元素,不能够直接获取其中的数据,获取数据需要使用以下方法 element.click() 对定位到的标签对象进行点击操作 element.send_keys(data) 对定位到的标签对象输入数据 element.text 获取文本内容 element.get_attribute("属性名") 传入属性名,获取属性的值 #获取标签ID element.id #获取标签位置 element.location #获取标签名称 element.tag_name #获取标签大小 element.size
四、selenium动作链
首先需要了解ActionChains的执行原理,当你调用ActionChains的方法时,不会立即执行,而是会将所有的操作按顺序存放在一个队列里,当你调用perform()方法时,队列中的时间会依次执行。
# ActionChains方法列表
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) ——拖拽到某个元素然后松开
drag_and_drop_by_offset(source, xoffset, yoffset) ——拖拽到某个坐标然后松开
key_down(value, element=None) ——按下某个键盘上的键
key_up(value, element=None) ——松开某个键
move_by_offset(xoffset, yoffset) ——鼠标从当前位置移动到某个坐标
move_to_element(to_element) ——鼠标移动到某个元素
move_to_element_with_offset(to_element, xoffset, yoffset) ——移动到距某个元素(左上角坐标)多少距离的位置
perform() ——执行链中的所有动作
release(on_element=None) ——在某个元素位置松开鼠标左键
send_keys(*keys_to_send) ——发送某个键到当前焦点的元素
send_keys_to_element(element, *keys_to_send) ——发送某个键到指定元素
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
# 常用
ActionChains(driver).move_to_element_with_offset(verify_box, x, y).click().perform()
ActionChains(driver).click_and_hold(span_tag).move_by_offset(code_width / 2, 0).perform()
五、selenium标签页的切换
- 获取所有标签页的窗口句柄
- 利用窗口句柄字切换到句柄指向的标签页
这里的窗口句柄是指:指向标签页对象的标识
具体的方法:
# 1. 获取当前所有的标签页的句柄构成的列表
current_windows = driver.window_handles
# 2. 根据标签页句柄列表索引下标进行切换
driver.switch_to.window(current_windows[0])
六、switch_to切换frame标签
iframe是html中常用的一种技术,即一个页面中嵌套了另一个网页,selenium默认是访问不了frame中的内容的,对应的解决思路是
driver.switch_to.frame(frame_element)
切换到定位的frame标签嵌套的页面中
driver.switch_to.frame(通过find_element函数定位的frame、iframe标签对象)
利用切换标签页的方式切出frame标签
windows = driver.window_handles
driver.switch_to.window(windows[0])
返回父级frame
driver.switch_to.parent_frame()
七、selenium对cookie的处理
-
获取cookie
# driver.get_cookies()返回列表,其中包含的是完整的cookie信息,不光有name、value,还有domain等cookie其他维度的信息。所以如果想要把获取的cookie信息和requests模块配合使用的话,需要转换为name、value作为键值对的cookie字典 # 获取当前标签页的全部cookie信息 print(driver.get_cookies()) # 把cookie转化为字典 cookies_dict = {cookie['name']: cookie['value'] for cookie in driver.get_cookies()}
-
删除cookie
#删除一条cookie driver.delete_cookie("CookieName") # 删除所有的cookie driver.delete_all_cookies()
八、selenium控制浏览器执行js代码
# 执行js的方法:driver.execute_script(js)
import time
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://movie.douban.com/")
time.sleep(1)
js = 'window.scrollTo(0,document.body.scrollHeight)' # js语句
driver.execute_script(js) # 执行js的方法
time.sleep(3)
driver.quit()
九、页面等待
-
强制等待
其实就是time.sleep() 缺点时不智能,设置的时间太短,元素还没有加载出来;设置的时间太长,则会浪费时间
-
隐式等待
针对元素定位,设置了一个时间,在一段时间内判断元素定位成功就进行下一步;
在设置的时间内没有定位成功,则会报超时加载;
示例:
from selenium import webdriver from selenium.webdriver.chrome.service import Service driver = webdriver.Chrome(service=Service('./chromedriver.exe')) driver.implicitly_wait(10) # 隐式等待,最长等20秒 driver.get('https://www.baidu.com') driver.find_element(By.XPATH, '')
-
显式等待
- 每经过多少秒就查看一次等待条件是否达成,如果达成就停止等待,继续执行后续代码
- 如果没有达成就继续等待直到超过规定的时间后,报超时异常
示例代码:
from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Chrome(service=Service('./chromedriver.exe')) driver.get('https://www.baidu.com') # 显式等待 WebDriverWait(driver, 20, 0.5).until( EC.presence_of_element_located((By.LINK_TEXT, '好123'))) # 参数20表示最长等待20秒 # 参数0.5表示0.5秒检查一次规定的标签是否存在 # EC.presence_of_element_located((By.LINK_TEXT, '好123')) 表示通过链接文本内容定位标签 # 每0.5秒一次检查,通过链接文本内容定位标签是否存在,如果存在就向下继续执行;如果不存在,直到20秒上限就抛出异常 print(driver.find_element(By.LINK_TEXT, '好123').get_attribute('href')) driver.quit()
-
手动实现页面等待
原理:
- 利用强制等待和显式等待的思路来手动实现
- 不停的判断或有次数限制的判断某一个标签对象是否加载完毕(是否存在)
示例:
import time from selenium import webdriver from selenium.webdriver.chrome.service import Service driver = webdriver.Chrome(service=Service('./chromedriver.exe')) driver.get('https://www.taobao.com/') time.sleep(1) # i = 0 # while True: for i in range(10): i += 1 try: time.sleep(3) element = driver.find_element(By.XPATH, '//div[@class="shop-inner"]/h3[1]/a') print(element.get_attribute('href')) break except: js = 'window.scrollTo(0, {})'.format(i*500) # js语句 driver.execute_script(js) # 执行js的方法 driver.quit()
十、selenium开启无界面模式
绝大多数服务器是没有界面的,selenium控制谷歌浏览器也存在无界面模式,开启无界面模式(又称之为无头模式)
开启无界面模式:
from selenium.webdriver.chrome.options import Options
实例化配置对象
chrom_options = Options()
配置对象添加开启无界面模式的命令
chrom_options.add_argument('--headless')
配置对象添加禁用gpu的命令
chrom_options.add_argument('--disable-gpu')
实例化带有配置对象的driver对象
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrom_options)
十一、selenium使用代理IP
在 selenium 框架中想使用 ip 代理的方式访问 url,必须先安装selenium-wire 模块,再从 seleniumwire 导入 webdriver 后使用。否则就会报上面的错误。安装方式:
pip install selenium-wire
# 想使用 ip 代理,必须先安装 selenium-wire 模块,再从 seleniumwire 导入 webdriver
# 否则报错:selenium.common.exceptions.WebDriverException: Message: unknown error: net::ERR_TUNNEL_CONNECTION_FAILED
from seleniumwire import webdriver
实例化配置对象
chrom_options = Options()
配置对象添加使用代理ip的命令
chrom_options.add_argument('--proxy-server=http://202.20.16.82:9527')
实例化带有配置对象的driver对象
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrom_options)
示例:
from selenium.webdriver.chrome.options import Options
chrom_options = Options() # 创建一个配置对象
chrom_options.add_argument('--proxy-server=http://202.20.16.82:9527') # 使用代理ip
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrom_options) # 实例化带有配置的driver对象
driver.get('https://movie.douban.com/')
print(driver.title)
driver.quit()
十二、selenium替换user-agent
实例化配置对象
chrom_options = Options()
配置对象添加替换UA的命令
chrom_options.add_argument('--user-agent=Mozilla/5.0 HAHA')
实例化带有配置对象的driver对象
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrom_options)
示例:
from selenium.webdriver.chrome.options import Options
chrom_options = Options() # 创建一个配置对象
chrom_options.add_argument('--user-agent=Mozilla/5.0 HAHA') # 替换User-Agent
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrom_options)
driver.get('https://movie.douban.com/')
print(driver.title)
driver.quit()
十三、selenium规避检测
使用stealth.min.js文件防止selenium被检测
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_argument(
'user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36')
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrome_options)
with open('./stealth.min.js') as f:
js = f.read()
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": js
})
stealth.min.js文件链接: https://pan.baidu.com/s/1HI6fsF5sMPifO5gg1vaKXA
提取码: 47wm
十四、案例
(一)模拟登录B站(ActionChains+图鉴)
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
import verify_code
if __name__ == '__main__':
url = 'https://www.bilibili.com/'
driver = webdriver.Chrome(service=Service('./chromedriver.exe'))
driver.get(url=url)
time.sleep(1)
driver.find_element(By.XPATH, '//*[@id="i_cecream"]/div[2]/div[1]/div[1]/ul[2]/li[1]/li/div[1]/div').click()
time.sleep(2)
driver.find_element(By.XPATH, '/html/body/div[3]/div/div[4]/div[2]/form/div[1]/input').send_keys('****')
time.sleep(2)
driver.find_element(By.XPATH, '/html/body/div[3]/div/div[4]/div[2]/form/div[3]/input').send_keys('****')
time.sleep(2)
driver.find_element(By.XPATH, '/html/body/div[3]/div/div[4]/div[2]/div[2]/div[2]').click()
time.sleep(2)
verify_box = driver.find_element(By.XPATH, '/html/body/div[4]/div[2]/div[6]/div/div')
verify_box.screenshot('./code_img.png')
position_str = verify_code.get_verify_code('./code_img.png', 27)
position_list = [position for position in position_str.split('|')]
verify_box_width = verify_box.size.get('width') // 2
verify_box_height = verify_box.size.get('height') // 2
action = ActionChains(driver)
for position_move in position_list:
x = int(position_move.split(',')[0]) - verify_box_width
y = int(position_move.split(',')[1]) - verify_box_height
action.move_to_element_with_offset(verify_box, x, y).click().perform()
time.sleep(1)
action.release()
driver.find_element(By.XPATH, '/html/body/div[4]/div[2]/div[6]/div/div/div[3]/a/div').click()
time.sleep(3)
driver.quit()
# 查询图鉴平台相关信息
verify_code.check_tujian_info()
import base64
import json
import requests
# 一、图片文字类型(默认 3 数英混合):
# 1 : 纯数字
# 1001:纯数字2
# 2 : 纯英文
# 1002:纯英文2
# 3 : 数英混合
# 1003:数英混合2
# 4 : 闪动GIF
# 7 : 无感学习(独家)
# 11 : 计算题
# 1005: 快速计算题
# 16 : 汉字
# 32 : 通用文字识别(证件、单据)
# 66: 问答题
# 49 :recaptcha图片识别
# 二、图片旋转角度类型:
# 29 : 旋转类型
#
# 三、图片坐标点选类型:
# 19 : 1个坐标
# 20 : 3个坐标
# 21 : 3 ~ 5个坐标
# 22 : 5 ~ 8个坐标
# 27 : 1 ~ 4个坐标
# 48 : 轨迹类型
#
# 四、缺口识别
# 18 : 缺口识别(需要2张图 一张目标图一张缺口图)
# 33 : 单缺口识别(返回X轴坐标 只需要1张图)
# 五、拼图识别
# 53:拼图识别
def base64_api(uname, pwd, img, typeid):
with open(img, 'rb') as f:
base64_data = base64.b64encode(f.read())
b64 = base64_data.decode()
data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64}
result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
if result['success']:
return result["data"]["result"]
else:
# !!!!!!!注意:返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别
return result["message"]
return ""
username = '****'
password = '****'
def get_verify_code(img_path, type_id):
result = base64_api(uname=username, pwd=password, img=img_path, typeid=type_id)
return result
# 查询图鉴平台相关信息
def check_tujian_info():
url = 'http://api.ttshitu.com/queryAccountInfo.json'
params = {
'username': username,
'password': password
}
response = requests.get(url=url, params=params).json()
if response.get('success'):
data = response.get('data')
print(
f'此次共计消费:{data.get("consumed")},余额:{data.get("balance")},识别成功总数量:{data.get("successNum")},识别错误总数量:{data.get("failNum")}。')
else:
print(response.get('message'))
(二)获取17k小说收藏书架(selenium获取cookie+requests发起请求)
import time
import requests
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
if __name__ == '__main__':
chrom_options = Options()
chrom_options.add_argument('--headless')
chrom_options.add_argument('--disable_gpu')
# 登录
url = 'https://www.17k.com/'
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrom_options)
driver.implicitly_wait(10)
driver.get(url)
time.sleep(0.5)
driver.find_element(By.XPATH, '//*[@id="header_login_user"]/a[1]').click()
time.sleep(0.5)
iframe = driver.find_element(By.CSS_SELECTOR, 'body > div.QUI_POP_BOX > div > div.QUI_POP_CONT > iframe')
driver.switch_to.frame(iframe)
time.sleep(0.5)
driver.find_element(By.XPATH, '/html/body/form/dl/dd[2]/input').send_keys('****')
time.sleep(0.5)
driver.find_element(By.XPATH, '/html/body/form/dl/dd[3]/input').send_keys('****')
time.sleep(0.5)
driver.find_element(By.XPATH, '//*[@id="protocol"]').click()
time.sleep(0.5)
driver.find_element(By.XPATH, '/html/body/form/dl/dd[5]/input').click()
time.sleep(0.5)
# 处理cookie
cookies_dic = {cookie['name']: cookie['value'] for cookie in driver.get_cookies()}
book_shelf_url = 'https://user.17k.com/ck/author/shelf'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
params = {
'page': '1',
'appKey': '2406394919'
}
# 使用requests发送请求获取动态数据
json_data = requests.get(url=book_shelf_url, headers=headers, cookies=cookies_dic).json()
for book_info in json_data['data']:
print(book_info['bookId'], book_info['authorPenName'], book_info['bookName'])
(三)模拟登录12306(规避检测)
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
if __name__ == '__main__':
# 规避检测
chrome_options = Options()
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_argument(
'user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36')
driver = webdriver.Chrome(service=Service('./chromedriver.exe'), options=chrome_options)
with open('./stealth.min.js') as f:
js = f.read()
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": js
})
# 登录
url = 'https://kyfw.12306.cn/otn/resources/login.html'
driver.implicitly_wait(10)
driver.get(url)
time.sleep(0.5)
driver.find_element(By.XPATH, '//*[@id="J-userName"]').send_keys('****')
time.sleep(0.5)
driver.find_element(By.XPATH, '//*[@id="J-password"]').send_keys('****')
time.sleep(0.5)
driver.find_element(By.XPATH, '//*[@id="J-login"]').click()
time.sleep(0.5)
# 识别滑动验证码
span_tag = driver.find_element(By.XPATH, '//*[@id="nc_1_n1z"]')
# code_width:340px
code_width = driver.find_element(By.XPATH, '//*[@id="nc_1__scale_text"]/span').size.get('width')
for i in range(2):
ActionChains(driver).click_and_hold(span_tag).move_by_offset(xoffset=code_width / 2,
yoffset=0).perform()
time.sleep(0.01)
time.sleep(5)
driver.quit()