爬虫神器之selenium的使用

目录

selenium介绍与安装

selenium 控制浏览器

selenium元素定位

selenium定位下拉菜单

selenium 层级定位

selenium 处理下拉框

selenium处理弹窗

selenium拖拽元素

selenium调用js方法

selenium 等待元素

selenium 参数使用

Selenium实战案例


selenium介绍与安装

Selenium是一个Web的自动化测试工具,最初是为网站自动化测试 而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自 动操作,不同是Selenium 可以直接运行在浏览器上,它支持所有主 流的浏览器(包括PhantomJS这些无界面的浏览器)。

Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要 的数据,甚至页面截屏,或者判断网站上某些动作是否发生。

Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方 浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码 中运行,所以我们可以用一个叫 PhantomJS 的工具代替真实的浏览 器。

PyPI网站下载 Selenium库 https://pypi.python.org/simple/seleni um ,也可以用第三方管理器 Selenium 官方参考文档:http://selenium-python.readthedocs.i o/index.html

安装

pip install selenium

安装Firefox geckodriver

安装firefox最新版本,添加Firefox可执行程序到系统环境变量。记得关闭firefox的自动更新

firefox下载地下:https://github.com/mozilla/geckodriver/releas es 将下载的geckodriver.exe 放到path路径下 D:\Python\python_version\

安装ChromeDriver

http://chromedriver.storage.googleapis.com/index.html

 注意 版本号要对应

 测试代码

# 导入 webdriver
from selenium import webdriver
# 要想调用键盘按键操作需要引入keys包
from selenium.webdriver.common.keys importKeys
# 调用环境变量指定的PhantomJS浏览器创建浏览器对象
driver = webdriver.Chrome()
# 如果没有在环境变量指定PhantomJS位置
# driver = webdriver.Chrome(executable_path="./phantomjs"))
# get方法会一直等到页面被完全加载,然后才会继续程序,通常测试会在这里选择 time.sleep(2)
driver.get("http://www.baidu.com/")
# 打印网页渲染后的源代码
print(driver.page_source)
# 生成新的页面快照
driver.save_screenshot("python爬虫.png")
# 获取当前url
print(driver.current_url)
# 关闭浏览器
driver.quit()

selenium 控制浏览器

 最大化窗口

我们知道调用启动的浏览器不是全屏的,这样不会影响脚本的执 行,但是有时候会影响我们“观看”脚本的执行。

browser = webdriver.Chrome()
url= 'http://www.baidu.com'
browser.get(url)
borwser.maximize_window()

设置宽与高

最大化还是不够灵活,能不能随意的设置浏览的宽、高显示?当然 是可以的。

browser = webdriver.Chrome()
url= 'http://www.baidu.com'
browser.get(url)
borwser.set_window_size(500,600)

浏览器前进、后退

浏览器上有一个后退、前进按钮,对于浏览网页的人是比较方便 的;对于做web自动化测试的同学来说应该算是一个比较难模拟的 问题 其实很简单,下面看看python的实现方式

browser = webdriver.Chrome()#访问百度首页
first_url= 'http://www.baidu.com'
browser.get(first_url)
time.sleep(2)#访问新闻页面
second_url='http://news.baidu.com'
browser.get(second_url)
time.sleep(2)#返回(后退)到百度首页print "back to %s "%(first_url)
browser.back()
time.sleep(1) #前进到新闻页print "forward to %s"%(second_url)
browser.forward()
time.sleep(2)
browser.quit()

selenium元素定位

对象的定位应该是自动化的核心,要想操作一个对象,首先应该识 别这个对象。 一个对象就是一个人一样,他会有各种的特征(属性),如比我们 可以通过一个人的身份证号,姓名,或者他住在哪个街道、楼层、门牌找到这个人。

对象定位

webdriver提供了对象定位方法

  • find_element(type,value)
  • find_elements(type,value)

利用 By 类来确定哪种选择方式

from selenium.webdriver.common.by import By
chrome.find_element(by=By.ID,value='su')

By 类的一些属性如下

  • ID = "id"
  • NAME = "name"
  • XPATH = "xpath"
  • LINK_TEXT = "link text"
  • PARTIAL_LINK_TEXT = "partial link text"
  • TAG_NAME = "tag name"
  • CLASS_NAME = "class name"
  • CSS_SELECTOR = "css selector"

 操作元素

前面讲到了不少知识都是定位元素,定位只是第一步,定位之后需 要对这个原素进行操作。 鼠标点击呢还是键盘输入,这要取决于我们定位的是按钮还输入 框。

一般来说,webdriver中比较常用的操作对象的方法有下面几个:

  • click 点击对象
  • send_keys 在对象上模拟按键输入
  • clear 清除对象的内容,如果可以的话

from selenium import webdriver
from selenium.webdriver.chrome.service
import Service
from time import sleep
from selenium.webdriver.common.by import By
def test_element():
    # 创建驱动对象
    s =Service(executable_path='./chromedriver.exe')
    # 创建一个浏览器
    driver = webdriver.Chrome(service=s)
    # 打个百度
    driver.get('https://cn.bing.com/')
    sleep(2)
    # 获取 搜索框,并输出“学习”
  driver.find_element(By.ID,'sb_form_q').send_keys('学习')
    sleep(1)
    # 获取 搜索按钮,并点击
  
driver.find_element(By.ID,'search_icon').click()
if __name__ =='__main__':
    test_element()

selenium定位下拉菜单

包含下拉菜单页面

<html>
    <head>
        <meta http-equiv="content-type"
content="text/html;charset=utf-8" />
        <title>Level Locate</title>  
        <script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery@1.1
2.4/dist/jquery.min.js"></script>
        <link
href="https://cdn.jsdelivr.net/npm/@bootcss/
v3.bootcss.com@1.0.9/dist/css/bootstrap.min.
css" rel="stylesheet" />        
    </head>
    <body>
        <h3>Level locate</h3>
        <div class="span3 col-md-3">        
            <div class="well">
                <div class="dropdown">
                    <a class="dropdowntoggle" data-toggle="dropdown"
href="#">Link1</a>
                    <ul class="dropdownmenu" role="menu" aria-labelledby="dLabel"
id="dropdown1" >
                        <li><a tabindex="-1"
href="http://www.baidu.com">Action</a></li>
                        <li><a tabindex="-1"
href="#">Another action</a></li>
                        <li><a tabindex="-1"
href="#">Something else here</a></li>
                        <li class="divider">
</li>
                        <li><a tabindex="-1"
href="#">Separated link</a></li>
                    </ul>
                </div>                
            </div>     
        </div>
        <div class="span3 col-md-3">        
            <div class="well">
                <div class="dropdown">
                    <a class="dropdowntoggle" data-toggle="dropdown"
href="#">Link2</a>
                    <ul class="dropdownmenu" role="menu" aria-labelledby="dLabel" >
                        <li><a tabindex="-1"
href="#">Action</a></li>
                        <li><a tabindex="-1"
href="#">Another action</a></li>
                        <li><a tabindex="-1"
href="#">Something else here</a></li>
                        <li class="divider">
</li>
                        <li><a tabindex="-1"
href="#">Separated link</a></li>
                    </ul>
                </div>                
            </div>            
        </div>
    </body>
    <script
src="https://cdn.jsdelivr.net/npm/@bootcss/v
3.bootcss.com@1.0.9/dist/js/bootstrap.min.js
"></script></html>

选中元素

from selenium import webdriver
from selenium.webdriver.chrome.service
import Service
from selenium.webdriver.common.by import By
import os
from time import sleep
def test_down_menu():
    # 创建一个驱动
    s =Service(executable_path='./chromedriver.exe')
    # 创建浏览器
    driver = webdriver.Chrome(service=s)
    # 设置方位的文件地址
    file_path = 'file:///'+os.path.abspath('./html/test01.html')
    # 访问页面
    driver.get(file_path)
    # 定位父级元素
  
    driver.find_element(By.LINK_TEXT,'Link1').click()
    # 找到要移动的位置
    menu = driver.find_element(By.LINK_TEXT,'Action')
    # 做一个移动光标的动作
    # 定义一个动作在driver  移动到menu的位置     执行动作
 
    webdriver.ActionChains(driver).move_to_element(menu).perform()
    # sleep(2)
    # 定位子级元素
    menu.click()
    # 睡眠2秒
    sleep(2)
    # 关闭浏览器
    driver.quit()
if __name__ == '__main__':
    test_down_menu()

selenium 层级定位

 窗口的定位

对于一个现代的web应用,经常会出现框架(frame) 或窗口 (window)的应用,这也就给我们的定位带来了一个难题。 有时候我们定位一个元素,定位器没有问题,但一直定位不了,这 时候就要检查这个元素是否在一个frame中,seelnium webdriver 提供了一个switch_to_frame方法,可以很轻松的来解决这个问题

多层框架或窗口的定位: driver.switch_to.frame()

frame.html

<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <title>frame</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
    <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"
        rel="stylesheet" />
</head>

<body>
    <div class="row-fluid">
        <div class="span10 well">
            <h3>frame</h3><iframe id="f1" src="inner.html" width="1500" , height="1200"></iframe>
        </div>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.8/dist/js/bootstrap.min.js"></script></html>
</html>

inner.html

<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <title>inner</title>
</head>
<body>
    <div class="row-fluid">
        <div class="span6 well">
            <h3>inner</h3><iframe id="f2" src="https://cn.bing.com/" width="1400" height="1100"></iframe>
        </div>
    </div>
</body>
</html>

switch_to_frame()

from selenium.webdriver.chrome.service import Service
from selenium import webdriver
from selenium.webdriver.common.by import By

import os
from time import sleep

def select_frame():
    # 创建驱动
    s = Service(executable_path='./chromedriver.exe')
    # 创建浏览器
    driver = webdriver.Chrome(service=s)
    file_path = 'file:///' + os.path.abspath('./html/outer.html')
    # 打开网页
    driver.get(file_path)
    # 切换frame
    driver.switch_to.frame('f1')
    driver.switch_to.frame('f2')
    # 定位元素,输入要搜索的内容
    driver.find_element(By.ID,'sb_form_q').send_keys('百战')
    # 定位按钮,点击搜索
    driver.find_element(By.ID,'search_icon').click()
    sleep(3)

    driver.quit()

if __name__ =='__main__':
    select_frame()

selenium 处理下拉框

 在爬取数据时,有时数据太多,而官网提供了筛选功能select标 签,像这样的数据,我们只需要定位元素,点击即可。

drop_down.html

<html>
    <body>
        <select id="ShippingMethod" onchange="updateShipping(options[selectedIndex]);" name="ShippingMethod">
            <option value="12.51">UPS Next Day Air ==> $12.51</option>
            <option value="11.61">UPS Next Day Air Saver ==> $11.61</option>
            <option value="10.69">UPS 3 Day Select ==> $10.69</option>
            <option value="9.03">UPS 2nd Day Air ==> $9.03</option>
            <option value="8.34">UPS Ground ==> $8.34</option>
            <option value="9.25">USPS Priority Mail Insured ==> $9.25</option>
            <option value="7.45">USPS Priority Mail ==> $7.45</option>
            <option value="3.20" selected="">USPS First Class ==> $3.20</option>
        </select>


        <select id="ShippingMethod2" onchange="updateShipping(options[selectedIndex]);" name="ShippingMethod">
            <option value="12.51">UPS Next Day Air ==> $12.51</option>
            <option value="11.61">UPS Next Day Air Saver ==> $11.61</option>
            <option value="10.69">UPS 3 Day Select ==> $10.69</option>
            <option value="9.03">UPS 2nd Day Air ==> $9.03</option>
            <option value="8.34">UPS Ground ==> $8.34</option>
            <option value="9.25">USPS Priority Mail Insured ==> $9.25</option>
            <option value="7.45">USPS Priority Mail ==> $7.45</option>
            <option value="3.20" selected="">USPS First Class ==> $3.20</option>
        </select>
    </body>
</html>
from selenium.webdriver.chrome.service import Service
from selenium import webdriver
from selenium.webdriver.common.by import By

from time import sleep
import os

def choose_option():
    # 创建驱动
    s = Service('./chromedriver.exe')
    #  创建浏览器对象
    driver = webdriver.Chrome(service=s)
    # 访问页面
    # 设置页面地址
    file_path = 'file:///' + os.path.abspath('./html/test02.html')
    driver.get(file_path)
    # 定位下拉框里面选项
    sleep(2)
    driver.find_element(By.XPATH,'//select[@id="ShippingMethod"]/option[@value="10.69"]').click()
    sleep(2)
    driver.find_element(By.XPATH,'//select[@id="ShippingMethod2"]/option[@value="9.25"]').click()
    # 关闭浏览器
    sleep(5)
    driver.quit()

if __name__ == '__main__':
    choose_option()

selenium处理弹窗

 有时,页面可能要弹窗口。只需要去定位弹窗上的“确定”按钮即可

  • switch_to 焦点集中到页面上的一个警告(提示) a
  • ccept() 接受警告提示

 html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>This is a page</title>
</head>
<body>
    <div id = "container">
        <div style="font: size 30px;">Hello,Python Spider</div>
    </div>
</body>
<script>
    alert('这个是测试弹窗')
</script>
</html>
from lib2to3.pgen2 import driver
from selenium.webdriver.chrome.service import Service
from selenium import webdriver

from time import sleep
import os

def test_windows():
    # 创建驱动对象
    s = Service('./chromedriver.exe')
    # 创建浏览器
    driver = webdriver.Chrome(service=s)
    # 访问页面
    # 设置页面地址
    file_path = 'file:///' + os.path.abspath('./html/test03.html')
    driver.get(file_path)
    sleep(3)
    # 定位弹出窗口,并点击
    driver.switch_to.alert.accept()
    sleep(3)
    driver.quit()

if __name__ =='__main__':
    test_windows()

selenium拖拽元素

 要完成元素的拖拽,首先需要指定被拖动的元素和拖动目标元素, 然后利用 ActionChains 类来实现,ActionChains用于定制动作。 通过ActionChains对象中的perform()执行动作,

html

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>jQuery UI Draggable - Auto-scroll</title>
	<link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
	<style>
	#draggable, #draggable2, #draggable3 { width: 100px; height: 100px; padding: 0.5em; float: left; margin: 0 10px 10px 0; }
    body {font-family: Arial, Helvetica, sans-serif;}
    table {font-size: 1em;}
    .ui-draggable, .ui-droppable {background-position: top;}
	</style>
	<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
	<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
	<script>
	$( function() {
		$( "#draggable" ).draggable({ scroll: true });
		$( "#draggable2" ).draggable({ scroll: true, scrollSensitivity: 100 });
		$( "#draggable3" ).draggable({ scroll: true, scrollSpeed: 100 });
	} );
	</script>
</head>
<body>
<div id="draggable" class="ui-widget-content">
	<p>Scroll set to true, default settings</p>
</div>

<div id="draggable2" class="ui-widget-content">
	<p>scrollSensitivity set to 100</p>
</div>

<div id="draggable3" class="ui-widget-content">
	<p>scrollSpeed set to 100</p>
</div>
<div style="height: 5000px; width: 1px;"></div>
</body>
</html>

python

from selenium.webdriver.chrome.service import Service
from selenium import webdriver
from selenium.webdriver.common.by import By

from time import sleep
import os

def test_drop():
    # 创建驱动对象
    s = Service('./chromedriver.exe')
    # 创建浏览器
    driver = webdriver.Chrome(service=s)
    # 访问页面
    # 设置页面地址
    file_path = 'file:///' + os.path.abspath('./html/test04.html')
    driver.get(file_path)
    # 定位要拖拽的元素
    div1 = driver.find_element(By.ID,'draggable')
    div2 = driver.find_element(By.ID,'draggable2')
    div3 = driver.find_element(By.ID,'draggable3')
    # 开始拖拽
    # 定义事件
    sleep(2)
    webdriver.ActionChains(driver).drag_and_drop(div1,div2).perform()
    for i in range(10):
        webdriver.ActionChains(driver).drag_and_drop_by_offset(div3,10,10).perform()
        sleep(0.5)
    # 关闭浏览器
    sleep(3)
    driver.quit()

if __name__ =='__main__':
    test_drop()

selenium调用js方法

有时候我们需要控制页面滚动条上的滚动条,但滚动条并非页面上 的元素,这个时候就需要借助js是来进行操作

一般用到操作滚动条的会两个场景:

  • 1 要操作的页面元素不在当前页面范围,无法进行操作,需要拖动滚动条
  • 2 注册时的法律条文需要阅读,判断用户是否阅读的标准是:滚动条是否拉到最下方

调用js的方法 

execute_script(script, *args)

滚动条回到顶部:

js="document.getElementById('id').scrollTop=0"
driver.execute_script(js)

滚动条拉到底部

js="document.documentElement.scrollTop=10000"
driver.execute_script(js)

可以修改scrollTop 的值,来定位右侧滚动条的位置,0是最上面, 10000是最底部

以上方法在Firefox和IE浏览器上上是可以的,但是用Chrome浏览 器,发现不管用。Chrome浏览器解决办法:

js = "document.body.scrollTop=0"
driver.execute_script(js)

横向滚动条

js = "window.scrollTo(100,400)"
driver.execute_script(js)

selenium 等待元素

  • 网速慢
  • AJAX请求数据
  • 调试 

 强制等待

使用 time.sleep

作用:当代码运行到强制等待这一行的时候,无论出于什么原因, 都强制等待指定的时间,需要通过time模块实现

优点:简单

缺点:无法做有效的判断,会浪费时间

隐式等待

chrome.implicitly_wait(time_num)

到了一定的时间发现元素还没有加载,则继续等待我们指定的 时间,如果超过了我们指定的时间还没有加载就会抛出异常, 如果没有需要等待的时候就已经加载完毕就会立即执行

优点: 设置一次即可

缺点:必须等待加载完成才能到后续的操作,或者等待超时才能进 入后续的操作

显示等待

from selenium.webdriver.support.wait import WebDriverWait

指定一个等待条件,并且指定一个最长等待时间,会在这个时 间内进行判断是否满足等待条件,如果成立就会立即返回,如 果不成立,就会一直等待,直到等待你指定的最长等待时间, 如果还是不满足,就会抛出异常,如果满足了就会正常返回

优点:专门用于对指定一个元素等待,加载完即可运行后续代码

缺点:多个元素都需要要单独设置等待 

url = 'https://www.guazi.com/nj/buy/'
driver = webdriver.Chrome()
driver.get(url)
wait = WebDriverWait(driver,10,0.5)
wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'next')))
print(driver.page_source)

selenium 参数使用

包括无头模式,代理模式,绕过检测 

from selenium.webdriver.chrome.service import Service
from selenium.webdriver import Chrome,ChromeOptions,DesiredCapabilities
from time import sleep

def test_headless():
    # 设置参数,将浏览器隐藏起来(无头浏览器)
    options = ChromeOptions()
    options.add_argument('--headless')
    # 设置驱动
    service = Service('./chromedriver')
    # 启动Chrome浏览器
    driver = Chrome(service=service,options=options)
    # 访问页面
    driver.get('https://www.baidu.com')
    # 打印代码
    print(driver.page_source)
    #  关闭浏览器
    driver.quit()

def test_proxy1():
    # 设置参数,给浏览器设置代理
    options = ChromeOptions()
    # options.add_argument('--proxy-server=http://ip:port')
    options.add_argument('--proxy-server=http://221.199.36.122:35414')
    # 设置驱动
    service = Service('./chromedriver')
    # 启动Chrome浏览器
    driver = Chrome(service=service,options=options)
    # 访问页面  "134.195.101.16",
    driver.get('http://httpbin.org/get')
    # 打印代码
    print(driver.page_source)
    #  关闭浏览器
    driver.quit()

def test_proxy2():
    from selenium.webdriver.common.proxy import ProxyType,Proxy
    # 设置参数,给浏览器设置代理
    ip = 'http://113.76.133.238:35680'
    proxy = Proxy()
    proxy.proxy_type = ProxyType.MANUAL
    proxy.http_proxy = ip
    proxy.ssl_proxy = ip
    # 关联浏览器
    capabilities = DesiredCapabilities.CHROME
    proxy.add_to_capabilities(capabilities)

    # 设置驱动
    service = Service('./chromedriver')
    # 启动Chrome浏览器
    driver = Chrome(service=service,desired_capabilities=capabilities)
    # 访问页面  "134.195.101.16",
    driver.get('http://httpbin.org/get')
    # 打印代码
    print(driver.page_source)
    #  关闭浏览器
    driver.quit()


def test_find():
    options = ChromeOptions()
    options.add_experimental_option('excludeSwitches', ['enable-automation'])
    options.add_experimental_option('useAutomationExtension', False)


    chrome = Chrome(chrome_options=options)

    chrome.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
        Object.defineProperty(navigator, 'webdriver', {
        get: () => false
        })
    """
    })

    chrome.get('http://httpbin.org/get')
    info = chrome.page_source

    print(info)
    sleep(20)

if __name__ =='__main__':
    # test_headless()
    # test_proxy1()
    # test_proxy2()
    test_find()

Selenium实战案例

from selenium.webdriver.chrome.service import Service
from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By

from lxml import etree

def spider_huya():
    # 创建一个驱动
    service = Service('./chromedriver.exe')
    # 创建一个浏览器
    driver = Chrome(service=service)
    # 设置隐式等待
    driver.implicitly_wait(5)
    # 访问网址
    driver.get('https://www.huya.com/g/lol')
    count = 1
    while True:
        # print('获取了第%d页' % count)
        # count += 1
        # 提取数据
        e = etree.HTML(driver.page_source)
        names = e.xpath('//i[@class="nick"]/@title')
        person_nums = e.xpath('//i[@class="js-num"]/text()')
        # 打印数据
        # for n,p in zip(names,person_nums):
        #     print(f'主播名:{n}  人气:{p}')
        
        # 找到下一页的按钮

        # try:
        #     next_btn = driver.find_element(By.XPATH,'//a[@class="laypage_next"]')
        #     next_btn.click()
        # except Exception as e:
        #     break
        if driver.page_source.find('laypage_next') == -1:
            break
        next_btn = driver.find_element(By.XPATH,'//a[@class="laypage_next"]')
        next_btn.click()
        
    # 关闭浏览器
    driver.quit()


if __name__ == '__main__':
    spider_huya()

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

艾派森

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

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

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

打赏作者

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

抵扣说明:

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

余额充值