selenium模块

selenium模块的定义

基于浏览器自动化的一个模块

使用selenium模块的优点

  • 便捷的获取网站加载的动态数据
  • 便捷实现模拟登陆

selenium模块使用流程

环境安装:

pip install selenium

下载chrome浏览器的驱动程序(网站不太稳定,可能需要多进几次):http://chromedriver.storage.googleapis.com/index.html

步骤

  1. 实例化一个浏览器对象
  2. 编写基于浏览器自动化的操作代码

先看一个自动加载药监局网站并获取上面企业名称的例子

from selenium import webdriver
from lxml import etree
from time import sleep

if __name__ == '__main__':
    # 实例化一个浏览器对象(一定要传入浏览器驱动程序)
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    # 让浏览器对指定url发起请求
    bro.get('http://scxk.nmpa.gov.cn:81/xk/')

    # 获取浏览器当前页面源码数据
    page_text = bro.page_source

    # 解析企业名称
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//ul[@id="gzlist"]/li') # 定位到企业名称的li标签
    for li in li_list:
        title_name = li.xpath('./dl/@title')[0]
        print(title_name)

    sleep(5) # 在网站停留五秒
    bro.quit() # 自动退出网站

再看一个在淘宝上自动搜索商品的操作

from selenium import webdriver
import time

if __name__ == '__main__':
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    bro.get('https://www.taobao.com/')

    # 标签定位,这里是根据id来定位
    search_input = bro.find_element_by_id('q')
    # 标签交互
    search_input.send_keys('macbook')
    time.sleep(2)

    # 执行js代码
    bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    time.sleep(5)
    # 点击搜索按钮
    btn = bro.find_element_by_class_name('btn-search')
    btn.click()

    time.sleep(5)
    bro.quit()

代码中,bro.find_element_by_id()函数用于定位网页源码中id标签,函数的参数就是id标签的值;

send_keys()用于向输入框中输入字符;

如果想要模拟鼠标的滑轮向下滑的操作,可以用js代码实现,而执行js代码的函数是execute_script(),相应的js代码window.scrollTo(0,document.body.scrollHeight)0代表的是x轴即横向移动的像素,另一个参数如果是数字的话,就是y轴即竖着移动的像素,这里的document.body.scrollHeight是向下滑动显示屏的大小;

在输入想要搜索的内容后,还有一个点击搜索按钮的操作,可以用click()函数来实现。

bro.get('https://www.baidu.com/')
time.sleep(2)
# 回退
bro.back()
time.sleep(2)
# 前进
bro.forward()

这里还有两个常用操作,back()用于返回浏览器上一页,forward()用于返回上一页后再回去。

selenium处理iframe

先来了解下什么是iframe

iframe 用于在网页内显示网页。
<iframe src=“URL”></iframe>
URL 指向隔离页面的位置。

在程序中,如果定位的标签是存在于iframe中,则必须通过switch_to.frame('iframe标签id')再进行标签定位。

实现拖动的操作,在我们实际操作时,需要点击+长按鼠标来拖动,在selenium模块中就要使用到动作链。

动作链

导入动作链对应的类:

from selenium.webdriver import ActionChains

实例化一个动作链对象:

action = ActionChains(bro)

执行长按且点击的操作:

action.click_and_hold(div)

执行拖动操作(x是水平移动的像素,y是竖直移动的像素):

action.move_by_offset(x, y)

让动作链立即执行:perform()

释放动作链对象:release()

下面是代码实现runoob上拖动的操作

from selenium import webdriver
from time import sleep
# 导入动作链对应的类
from selenium.webdriver import ActionChains

if __name__ == '__main__':
    bro = webdriver.Chrome('./chromedriver.exe')
    bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')

    bro.switch_to.frame('iframeResult')
    div = bro.find_element_by_id('draggable')
    # print(div)

    # 动作链
    action = ActionChains(bro)
    # 点击长按指定标签
    action.click_and_hold(div)
    for i in range(5):
        # move_by_offset()有x、y两个参数
        # perform()表示立即执行动作链操作
        action.move_by_offset(17, 0).perform()

    # 释放动作链
    action.release()
    bro.quit()

自动登录QQ空间

网站url:https://qzone.qq.com/

先进行信息搜集,打开qq空间url后,出现的是扫码登录页面,需要点击账号密码登录才能输入账号密码,然后点击登录,最后成功。

from selenium import webdriver
from time import sleep

if __name__ == '__main__':
    bro = webdriver.Chrome('./chromedriver.exe')
    bro.get('https://qzone.qq.com/')

    # 登录页面在一个iframe中
    bro.switch_to.frame('login_frame')
    btn = bro.find_element_by_id('switcher_plogin')
    btn.click()
    username_search = bro.find_element_by_id('u')
    username_search.send_keys('xxxxxxx') # 用户账号
    password_search = bro.find_element_by_id('p')
    password_search.send_keys('xxxxxx') # 用户密码
    login_btn = bro.find_element_by_id('login_button')
    login_btn.click()

    sleep(5)
    bro.quit()

一开始,我不知道登录框在一个iframe中,一直不成功,后来才发现登录框在一个名为login_frameiframe中,需要先切换才能进行后面的操作。

无头谷歌浏览器

在前面,程序执行时会弹出一个浏览器的窗口,当我们不想它弹出窗口时,就要用到无头浏览器的知识。

导入相关类:

from selenium.webdriver.chrome.options import Options

调用类中方法进行参数设定:

chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

例如请求百度

from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options

if __name__ == '__main__':

    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    
    bro = webdriver.Chrome(executable_path='./chromedriver.exe', chrome_options=chrome_options)

    bro.get('https://www.baidu.com')
    print(bro.page_source)
    sleep(2)
    bro.quit()

程序运行后一直未弹出浏览器加载的界面,并且最后也输出了网站的源码。

selenium检测的规避

导入相关类:

from selenium.webdriver import ChromeOptions

调用类中方法进行参数设置:

option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])

还是上面那个例子

from selenium import webdriver
from time import sleep
# 实现无可视化界面
from selenium.webdriver.chrome.options import Options
# 规避检测
from selenium.webdriver import ChromeOptions

if __name__ == '__main__':

    # 实现无可视化操作
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')

    # 规避被检测到的风险
    option = ChromeOptions()
    option.add_experimental_option('excludeSwitches', ['enable-automation'])

    bro = webdriver.Chrome(executable_path='./chromedriver.exe', chrome_options=chrome_options, options=option)

    bro.get('https://www.baidu.com')
    print(bro.page_source)
    sleep(2)
    bro.quit()

12306模拟登陆

在这里插入图片描述
12306的登录界面主要是这个选图片的验证码,可以使用超级鹰打码平台进行识别。在验证码类型中,选择的是坐标多选,返回1~4个坐标,如:x1,y1|x2,y2|x3,y3
在这里插入图片描述

import requests
from hashlib import md5


class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        password = password.encode('utf8')

        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }


    def PostPic(self, im, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files,
                          headers=self.headers)
        return r.json()


    def ReportError(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()


if __name__ == '__main__':
    chaojiying = Chaojiying_Client('用户名', '登录密码', '软件id')  # 用户中心>>软件ID 生成一个替换 96001
    im = open('a.jpg', 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    print(chaojiying.PostPic(im, 9004)['pic_str'])  # 9004 验证码类型  官方网站>>价格体系 3.4+版 print 后要加()

模拟登录编码流程:

  1. 使用selenium打开登录页面
  2. 对当前selenium打开的这张页面进行截图
  3. 对当前截取的图片局部区域(验证码)进行裁剪
  4. 使用超级鹰识别验证码图片(返回坐标数据)

网站打开后是扫码登录的页面,首先要切换到账号密码登录

# 切换成账号密码登录
account_login_btn = bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a')
account_login_btn.click()

其次,打码平台能解决识别验证码的问题,如何把验证码保存到本地呢?可以使用截图的方法,先截图整个屏幕,然后再将验证码的那一块图片截出来。

# 截图并保存
bro.save_screenshot('aa.jpg')
# 确定验证码图片的左上角和右下角的坐标
code_img_ele = bro.find_element_by_class_name('imgCode')
location = code_img_ele.location  # 验证码图片左上角的坐标x,y
print('location:', location)
size = code_img_ele.size  # 验证码标签对应的长和宽
print('size:', size)
# 图片左上角和右下角的坐标
rangle = (
    int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
# 至此验证码图片区域确定下来

接下来是要用到python的PIL模块,我下载时失败了,后来才知道要下Pillow模块

from PIL import Image
# 实例化image对象
i = Image.open('./aa.jpg')
code_img_name = './code.png'
# 使用crop根据指定区域进行图片裁剪
frame = i.crop(rangle)
frame.save(code_img_name)

到这里,验证码的图片就被保存到了本地,接下来是用超级鹰对验证码进行识别。

识别完成后,注意到最后的结果是xxx,xxx|xxx,xxx这一种的,想到可以以|进行分割,将每一个坐标存为一个列表,最后所有的结果再存为一个大列表,类似于[[x1,y1],[x2,y2]],然后使用数组遍历,依次模拟鼠标点击。

from selenium.webdriver import ActionChains

if '|' in result:
    list_1 = result.split('|')
    count_1 = len(list_1)
    for i in range(count_1):
        xy_list = []
        x = int(list_1[i].split(',')[0])
        y = int(list_1[i].split(',')[1])
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
else:
    x = int(result.split(',')[0])
    y = int(result.split(',')[1])
    xy_list = []
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list)
print(all_list)

# 遍历列表,使用动作链进行点击
for l in all_list:
    x = l[0]
    y = l[1]
    ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
    time.sleep(0.5)

最后是简单的输入12306的用户名和密码,并点击登录

# 录入用户名和密码
username_btn = bro.find_element_by_id('J-userName')
password_btn = bro.find_element_by_id('J-password')
username_btn.send_keys('12306用户名')
password_btn.send_keys('12306密码')
login_btn = bro.find_element_by_id('J-login')
login_btn.click()

完整的模拟登录代码

import requests
from hashlib import md5

from selenium import webdriver
import time
from PIL import Image
from lxml import etree
from selenium.webdriver import ActionChains


class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        password = password.encode('utf8')

        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files,
                          headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()


# 使用selenium打开页面


bro = webdriver.Chrome(executable_path='chromedriver.exe')
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
bro.maximize_window()
time.sleep(1)

# 切换成账号密码登录
account_login_btn = bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a')
account_login_btn.click()
# 截图并保存
bro.save_screenshot('aa.jpg')

# 确定验证码图片的左上角和右下角的坐标
code_img_ele = bro.find_element_by_class_name('imgCode')
location = code_img_ele.location  # 验证码图片左上角的坐标x,y
print('location:', location)
size = code_img_ele.size  # 验证码标签对应的长和宽
print('size:', size)
# 图片左上角和右下角的坐标
rangle = (
    int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
# 至此验证码图片区域确定下来
# 实例化image对象
i = Image.open('./aa.jpg')
code_img_name = './code.png'
# 使用crop根据指定区域进行图片裁剪
frame = i.crop(rangle)
frame.save(code_img_name)

# 将验证码提交给超级鹰识别
chaojiying = Chaojiying_Client('超级鹰用户名', '超级鹰密码', '软件id')  # 用户中心>>软件ID 生成一个替换 96001
im = open(code_img_name, 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
result = chaojiying.PostPic(im, 9004)['pic_str']
print(result)  # 1902 验证码类型  官方网站>>价格体系 3.4+版 print 后要加()
all_list = []  # 存储即将被点击的点的坐标 [[],[]]
if '|' in result:
    list_1 = result.split('|')
    count_1 = len(list_1)
    for i in range(count_1):
        xy_list = []
        x = int(list_1[i].split(',')[0])
        y = int(list_1[i].split(',')[1])
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
else:
    x = int(result.split(',')[0])
    y = int(result.split(',')[1])
    xy_list = []
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list)
print(all_list)

# 遍历列表,使用动作链进行点击
for l in all_list:
    x = l[0]
    y = l[1]
    ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
    time.sleep(0.5)

# 录入用户名和密码
username_btn = bro.find_element_by_id('J-userName')
password_btn = bro.find_element_by_id('J-password')
username_btn.send_keys('12306账号')
password_btn.send_keys('12306密码')
login_btn = bro.find_element_by_id('J-login')
login_btn.click()

如果在第一次运行后想要再多运行几次的,一定要记得删掉当前文件夹下保存的屏幕截图和验证码区域的截图,然后才能开始运行。

最后又弹出来一个滑块验证,如果用脚本登录的话就算拖动完也会报错,不让登录,真不愧是12306,十几年的防黄牛经验啊。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lum1n0us

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值