Python selenium模块

一、环境安装

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

posted @ 2023-03-10 01:12  与鹿逐秋  阅读(95)  评论(0编辑  收藏  举报