Selenium网页自动登陆项目(基于Python从0到1)

Selenium是一个自动化测试工具,利用它咱们能够驱动浏览器执行特定的动做,如点击、下拉等操做。
本文讲述的是经过自动化的方式登录某一网站,其中包含Selenium+python自动化项目环境如何部署, 获取图形验证码登陆,元素获取方法,项目中遇到的问题,看完你会发现原来Selenium自动化轻松入门,是多么的简单,Selenium+python也能够用于爬虫。
本文将从环境部署到项目开发一步步讲解,包括这个过程所可能遇到的一些问题,都会一一解答,有不会的问题能够在下方评论留言一块儿思考解决。css

一.环境部署

环境部署包括mac和linuxhtml

1.安装Selenium

pip3 install selenium

这里推荐你们使用Anaconda管理python包及环境,Anaconda是一个方便的python包管理和环境管理软件,通常用来配置不一样的项目环境。若是你的电脑只能安装一个环境,而两个项目却用着不一样的环境,那么你可使用Anaconda建立多个互不干扰的环境,分别运行不一样版本的软件包,以达到兼容的目的。python

Anaconda经过管理工具包、开发环境、Python版本,大大简化了你的工做流程。不只能够方便地安装、更新、卸载工具包,并且安装时能自动安装相应的依赖包,同时还能使用不一样的虚拟环境隔离不一样要求的项目。linux

Anaconda的安装流程及使用git

https://www.cnblogs.com/trotl/p/11863544.htmlgithub

2.安装ChromeDriver

2.1.查看浏览器版本
2.2.在浏览器的帮助/关于Google Chrome 查看浏览器版本
2.3.下载相应的ChromeDriver(两种方法)

方法一 :web

  1. 打开ChromeDriver官方网站,根据上面的浏览器版本,下载相应版本的ChromeDriver
  2. 将解压好的文件放入/usr/local/bin目录中,因为mac的不少目录都是隐藏的,因此咱们按快捷键command+shift+g,在弹出的窗口输入/usr/local/bin,就能够打开这个目录,接着将解压好的驱动放入此目录便可。
  3. 进行测试(在终端输入: chromedriver --version,能够查看到版本)

方法二 :
1.安装brew及使用可能遇到的问题chrome

https://www.cnblogs.com/trotl/p/11862796.htmlwindows

2.下载chromedriver数组

经过命令brew cask install chromedriver去下载

3.测试

在终端输入: chromedriver --version,能够查看到版本

3.安装识别验证码的包

1.用homebrew 在电脑上安装tesseract库

brew install tesseract

2.用pip安装支持python的tesseract

pip install pytesseract

若是是识别中文
去往https://github.com/tesseract-ocr/tessdata下载中文数据集chi_sim.traineddata,把它放到这目录下:
/usr/local/Cellar/tesseract/3.05.01/share/tessdata

3.安装容易遇到的问题:

  • 提示brew update,表明homebrew须要更新
  • 提示must be writable!或者Permission denied之类问题,试试前面加sudo
  • 提示Please check the permissions and owner of that directory,说明权限有问题,那么使用sudo chown root 文件路径命令得到临时root权限
  • 提示Xcode alone is not sufficient on Sierra,使用xcode-select --install

二.实现逻辑

开始想的逻辑是,获取到验证码的地址,而后爬取下来并请求,下载验证码图片并识别再填上去,发现这样行不通,每次请求得到的验证码图片不一致,这得从会话角度去解决问题。这里我换了种思惟更简单的去解决这个问题,经过截图的方式把页面上的验证码截图下来保存为图片并识别出文字。

1. 实现中所遇到的问题

  1. chromedriver的截图只能截取当前页面的图片,不能获得整个页面的图片,这样就不能经过定位验证码图片的位置去截取验证码图片,对于页面有滑动的只能手动调试位置。

  2. 处理验证码失败的提示框
  3. 当从a页面跳转到b网页,而后获取b页面的某个元素时,容易出错。由于代码执行速度比网页加载速度快,一般会出现没法找到该元素的错误。遇到没法找到页面元素的状况,要考虑是不是代码加载过快的缘由,处理方法:在获取元素前➕time.sleep(2)
  4. 快速获取元素路径的方式:网页->检查->选中对应标签->右键选择copy->copy xpath

2. 用到的一些方法

2.1 处理Windows弹出框(三种状况)

使用 driver.switch_to.alert 切换到Windows弹出框
Alert类提供了一系列操做方法:
accept() 肯定
dismiss() 取消
text() 获取弹出框里面的内容
send_keys(keysToSend) 输入字符串

A.定位alert弹出框

#点击页面元素,触发alert弹出框
driver.find_element_by_xpath('//*[@id="alert"]').click()
time.sleep(3)
#等待alert弹出框可见
WebDriverWait(driver,20).until(EC.alert_is_present())
#从html页面切换到alert弹框 
alert = driver.switch_to.alert
#获取alert的文本内容
print(alert.text)
#接受--选择“肯定”
alert.accept()

B.定位confirm弹出框

driver.find_element_by_xpath('//*[@id="confirm"]').click()
time.sleep(3)
WebDriverWait(driver,20).until(EC.alert_is_present())
alert =driver.switch_to.alert
print(alert.text)
# 接受--选择“取消”
alert.dismiss()

C.定位prompt弹出框

driver.find_element_by_id("prompt").click()
time.sleep(3)
WebDriverWait(driver,20).until(EC.alert_is_present())
alert =driver.switch_to.alert
alert.send_keys("jaja")
time.sleep(5)
print(alert.text)
# alert.dismiss()
alert.accept()
2.2 python+selenium调用js方法
from selenium import webdriver
js = '''var str="联想词:%s===>车系:%s";window.alert(str);''' % (alias, name)
driver.execute_script(js)

execute_script(js)和execute_async_script(js)分别是是同步和异步方法,前者会等待js代码执行完毕后主线程执行,后者它不会阻塞主线程执行。
execute_script(js) 方法若是有返回值,有如下几种状况:
    * 若是返回一个页面元素(document element), 这个方法就会返回一个WebElement
    * 若是返回浮点数字,这个方法就返回一个double类型的数字
    * 返回非浮点数字,方法返回Long类型数字
    * 返回boolean类型,方法返回Boolean类型
    * 若是返回一个数组,方法会返回一个List<Object>
    * 其余状况,返回一个字符串
    * 若是没有返回值,此方法就会返回null
2.3selenium+python的经常使用方法
1.建立webdriver对象
browser=webdriver.Chrome()
2.打开百度页面
browser.get('https://www.baidu.com')
3.获取网页源码
browser.page_source
4.在百度页面id为kw的输入框中输入book
driver.find_element_by_id('kw').send_keys('book’)
5.在百度页面id为kw的输入框中清除book
driver.find_element_by_id('kw’).clear()
6.在百度页面id为search的按钮点击搜索
a.driver.find_element_by_id('search').click()
b.action3 = self.driver.find_element_by_class_name('next')
  ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()
7.向前跳转回上一个页面
driver.back()
8.向后跳转回上一个页面
driver.forward()
9.关闭浏览器
browser.close()   关闭当前窗口
browser.quit()   退出并关闭窗口的每个相关的驱动程序
10.获取某个元素的文本内容
driver.find_element_by_class_name("loading_btn").text
11.将浏览器窗口最大化显示
driver.maximize_window() 
12.设置浏览器宽480、高800显示:
driver.set_window_size(480, 800)
13.获取验证码图片的大小
codeEelement = driver.find_element_by_id(‘code')
imgSize = codeEelement.size   
14.获取验证码元素坐标
imgLocation = imgElement.location 
15.计算验证码总体坐标
rangle = (int(imgLocation['x']),int(imgLocation['y']),int(imgLocation['x'] + imgSize['width']),int(imgLocation['y']+imgSize['height']))

注意:submit和click的区别。Click方法只适用于button,而submit能够用于提交表单。

2.4 获取元素的方法之find_element_by_css_selector
-----------------经过类class获取---------------
<h1 class="important">This heading is very important.</h1>
<p class="important">This paragraph is very important.</p>
<p class="important warning">This paragraph is a very important warning.</p>
1.获取class值为important的h1标签
find_element_by_css_selector(h1.importane)
2.获取全部class值为important的标签
find_element_by_css_selector(*.importane)或者find_element_by_css_selector(.importane)
3.获取class值为important warning的标签
find_element_by_css_selector(.importane.warning)

-----------------经过类ID获取---------------
<p id="intro">This is a paragraph of introduction.</p>
 find_element_by_css_selector(#"intro")
 
 -----------------属性选择器---------------
1.<a title="W3School Home" href="http://w3school.com.cn">W3School</a>
 属性中包含了title和href,find_element_by_css_selector('a[title][href]’)
2<a href="http://www.w3school.com.cn/about_us.asp">About W3School</a>
 定位属性中href="http://www.w3school.com.cn/about_us.asp"的元素,
find_element_by_css_selector('a[href="http://www.w3school.com.cn/about_us.asp"]’)
3.<a href="http://www.w3school.com.cn/" title="W3School">W3School</a>
 经过href和title来定位
find_element_by_css_selector("a[href='http://www.w3school.com.cn/about_us.asp'][title='W3School']”)

 -----------------部分属性定位---------------
<h1>能够应用样式:</h1>
<img title="Figure 1" src="/i/figure-1.gif" />
<img title="Figure 2" src="/i/figure-2.gif" />
 
<hr />
 
<h1>没法应用样式:</h1>
<img src="/i/figure-1.gif" />
<img src="/i/figure-2.gif" />
 定位title中包含有figure的元素:
find_element_by_css_selector("image[title~='figure']")

-----------------其余-------------------
[abc^="def"]  选择 abc 属性值以 "def" 开头的全部元素
[abc$="def"]   选择 abc 属性值以 "def" 结尾的全部元素
[abc*="def"]  选择 abc 属性值中包含子串 "def" 的全部元素

-----------------后代选择器--------------
<h1>This is a <em>important</em> heading</h1>
<p>This is a <em>important</em> paragraph.</p>
 find_element_by_css_selector("h1 em")
2.5 获取元素的方法之find_element_by_xpath

这个方法是很是强大的元素查找方式,使用这种方法几乎能够定位到页面上的任意元素。在正式开始使用XPath进行定位前,咱们先了解下什么是XPath。XPath是XML Path的简称,因为HTML文档自己就是一个标准的XML页面,因此咱们可使用XPath的语法来定位页面元素。
  Xpath经过路径来定位控件,分为绝对路径和相对路径。绝对路径以单/号表示,相对路径则以//表示。当xpath的路径以/开头时,表示让Xpath解析引擎从文档的根节点开始解析。当xpath路径以//开头时,则表示让xpath引擎从文档的任意符合的元素节点开始进行解析。而当/出如今xpath路径中时,则表示寻找父节点的直接子节点,当//出如今xpath路径中时,表示寻找父节点下任意符合条件的子节点。弄清这个原则,就能够理解其实xpath的路径能够绝对路径和相对路径混合在一块儿来进行表示,想怎么玩就怎么玩。

快速获取你想要的元素xpath方式:
网页->检查->选中对应标签->右键选择copy->copy xpath
在这里插入图片描述

绝对路径写法(只有一种),写法以下:
引用页面上的form元素(即源码中的第3行):/html/body/form
下面是相对路径的引用写法:
查找页面根元素:
//
查找页面上全部的input元素:
//input
查找页面上第一个form元素内的直接子input元素(即只包括form元素的下一级input元素):
//form/input
查找页面上第一个form元素内的全部子input元素(只要在form元素内的input都算,无论还嵌套了多少个其余标签,使用相对路径表示,双//号):
//form//input
查找页面上第一个form元素:
//form
查找页面上id为loginForm的form元素:
//form[@id='loginForm']
查找页面上具备name属性为username的input元素:
//input[@name='username']
查找页面上id为loginForm的form元素下的第一个input元素:
//form[@id='loginForm']/input[1]
查找页面具备name属性为contiune而且type属性为button的input元素:
//input[@name='continue'][@type='button']
查找页面上id为loginForm的form元素下第4个input元素:
//form[@id='loginForm']/input[4]
以百度主页为例,搜索框的HTML示例代码以下,其xpath为//*[@id=''kw]。

获取元素的方法之find_element_by_css_selector
获取元素的方法之find_element_by_xpath
这两种方法来自于百度,方便你们更好的学习,我在这里借花献佛总结了一下放在了这里,由于我在写项目的时候记录笔记到了其余地方,具体的地址忘了,若是原创做者看到了,请留下你的地址。

三.代码展现

import re
import time

import pandas as pd
import pytesseract
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait


class CrackTouClick(object):
    def __init__(self):
        self.url = ""
        self.search_url = ""
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver, 20)
        self.j_username = laosiji_username
        self.j_password = laosiji_password

    def open(self):
        self.driver.get(self.url)
        self.driver.find_element_by_name("j_username").send_keys(self.j_username)
        self.driver.find_element_by_name("j_password").send_keys(self.j_password)
        action3 = self.driver.find_element_by_id("code")
        ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()

    def get_window_png(self):
        ele = self.driver.find_element_by_class_name('logo')
        ele.screenshot('ele.png')

    def verification_code(self):
        self.driver.maximize_window()
        self.driver.save_screenshot('./element.png')  # 截取当前网页,该网页有咱们须要的验证码
        rangle = (1434, 961, 1598, 1017)  # 写成咱们须要截取的位置坐标
        element = Image.open("./element.png")  # 打开截图
        frame4 = element.crop(rangle)  # 使用Image的crop函数,从截图中再次截取咱们须要的区域
        frame4.save('./code.png')
        code = Image.open('./code.png')
        text = pytesseract.image_to_string(code)  # 使用image_to_string识别验证码
        return text

    def write(self):
        while True:
            code = self.verification_code()
            # 判断验证码是否识别到且为4位数字与字母的字符串
            if len(code.strip()) == 4 and code.isalnum():
                self.driver.find_element_by_name("rand").send_keys(code)
                break
            else:
                action3 = self.driver.find_element_by_id("rand_img")
                ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()

    def login(self):
        self.write()
        login_action = self.driver.find_element_by_class_name("btn")
        ActionChains(self.driver).move_to_element(login_action).double_click(login_action).perform()

    # 判断是否有弹出框
    def alert_is_present(self):
        try:
            alert = self.driver.switch_to.alert
            print(alert)
            return alert
        except:
            return False

    def read(self):
        while True:
            self.login()
            time.sleep(1)

            # 若是有弹出框 点击肯定
            if self.alert_is_present():
                self.driver.switch_to.alert.accept()
                self.driver.switch_to.alert.accept()
                time.sleep(1)
            else:
                break

        time.sleep(1)
        self.driver.get(self.search_url)
        self.driver.quit()

三.开发中遇到的BUG

1.运行时chrome报错,终端打不开

File "/usr/local/python3/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally
  (unknown error: DevToolsActivePort file doesn't exist)
  (The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
  (Driver info: chromedriver=70.0.3538.97 (d035916fe243477005bc95fe2a5778b8f20b6ae1),platform=Linux 3.10.0-862.14.4.el7.x86_64 x86_64)

缘由:运行过程当中开启的进程太多
解决方法:若是你是mac,按 Command + 空格键来调出 Spotlight,输入 Activity Monitor 即可启动活动监视器。若是手动关闭几个名称为chromedriver的进程,而后再尝试打开终端,按进程名杀死进程输入killall chromedriver。

若是以为不错,请留下您的大拇指哦👍
若是有什么疑问,请留下您的评论哦👍

相关文章
相关标签/搜索