Torres-tao  

Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。对于一些JavaScript动态渲染的页面来说,此种爬取方式非常有效。

1、基本用法

#!/usr/bin/python3
#coding=utf-8

from selenium import webdriver
#要想调用键盘按键操作需引入keys包
from selenium.webdriver.common.keys import keys

#创建浏览器对象
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
#打印页面标题“百度一下你就知道”
print(driver.title)
#生成当前页面快照
driver.save_screenshot("baidu.png")
#id="kw"是百度搜索框,输入字符串“微博”,跳转到搜索中国页面
driver.find_element_by_id("kw").send_keys(u"微博")
#id="su"是百度搜素按钮,click()是模拟点击
driver.find_element_by_id("su").click()
#获取新的页面快照
driver.save_screenshot(u"微博.png")
#打印页面渲染后的源代码
print(driver.page_source)
#获取当前页面的Cookie
print(driver.get_cookies())
#ctrl + a全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,"a")
#ctrl + x剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,"x")
#输入框重新输入内容
driver.find_element_by_id("kw").send_keys("test")
#模拟Enter回车键
driver.find_element_by_id("su").send_keys(Keys.RETURN)
#清除输入框内容
driver.find_element_by_id("kw").clear()
#生成新的页面快照
driver.save_screenshot("test.png")
#获取当前的url
print(driver.current_url)
#关闭当前页面,如果只有一个页面,会关闭浏览器
driver.close()
#关闭浏览器
driver.quit()

2、页面操作

假如有以下输入框

<input type="text" name="user-name" id="passwd-id" />

寻找方法

#获取id标签值
element = driver.find_element_by_id("passwd-id")
#获取name标签值
element = driver.find_element_by_name("user-name")
#获取标签名值
element = driver.find_element_by_tag_name("input")
#也可通过Xpath来匹配
element = driver.find_element_by_xpath("//input[@id='passwd-id']")

3、定位元素的方法

定位表单框架或“有效数据”位置,Selenium本身自带有18个函数,总共8种方法从返回数据中定位“有效数据位置”。

find_element(self,by="id",value=None)
find_element_by_class_name(self,name)
find_element_by_css_selector(self,css_selector)
find_element_by_id(self,id)
find_element_by_link_text(self,link_text)
find_element_by_name(self,name)
find_element_by_partial_link_text(self,link_text)
find_element_by_tag_name(self,name)
find_element_by_xpath(self,xpath)

find_elements(self,by="id",value=None)
find_elements_by_class_name(self,name)
find_elements_by_css_selector(self,css_selector)
find_elements_by_id(self,id)
find_elements_by_link_text(self,link_text)
find_elements_by_name(self,name)
find_elements_by_partial_link_text(self,link_text)
find_elements_by_tag_name(self,name)
find_elements_by_xpath(self,xpath)

​ 这18个函数前面9个带element的函数将返回第一个符合参数要求的element。后面9个带elements的函数将返回一个列表,列表中包含所有符合参数要求的element。

命名是9个函数,为何只有8种方法呢?

​ 上面函数中,不带by的函数,配合参数可以替代其他的函数。例如:find_element(self,by="id",value="abc")就可以代替find_element_by_id(‘abc’);同理,find_elements(self,by="id",value="abc")可以代替find_elements_by_id(‘abc’)

ps:

​ 在使用浏览器请求数据时,用find_element_by_id、find_element_by_name、find_element_by_tag_name、find_element_by_class_name会比较方便,一般的表单、元素都会有name、class、id。如果仅仅是为了获取"有效数据"的位置,强烈推荐find_element_by_xpath。

4、鼠标动作

#!/usr/bin/python3
#coding=utf-8

from selenium import webdriver
#要想调用键盘按键操作需引入keys包
from selenium.webdriver.common.keys import keys
from selenium.webdriver import ActionChains

#创建浏览器对象
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

#鼠标移动到某处
action1 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action1).perform()

#鼠标移动到某处单击
action2 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action2).click(action2).perform()

#鼠标移动到某处双击
action3 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action3).double_click(action3).perform()

#鼠标移动到某处右击
action4 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action4).context_click(action4).perform()

5、Select表单

#!/usr/bin/pyhton3
#coding=utf-8

from selenium.webdriver.support.ui import Select

#找到name的选项卡
select = Select(driver.find_element_by_name("status"))

select.select_by_index(1)
select.select_by_value("0")
select/select_by_visible_text(u"xxx")

#全部取消方法
select.deselect_all()

PS:

以上是三种选择下拉框的方式,它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。注意:

  • index索引从0开始
  • value是option标签的一个属性值,并不是显示在下拉框中的值
  • visible_text是在option标签文本的值,是显示在下拉框的值

6、弹框处理

当页面出现了弹框提示

alert = driver.switch_to_alert()

7、页面切换

一个浏览器肯定会有很多窗口,所以我们肯定要有方法来实现窗口的切换,切换窗口的方法如下:

driver.switch_to.window("this is window name")

8、页面前进和后退

操作页面的前进和后退功能:

#前进
driver.forward()
#后退
driver.back()

实战一:模拟登陆豆瓣网站

#!/usr/bin/python3
#coding=utf-8

import time
from selenium import webdriver
from selenium.webdriver.common.keys import keys

driver = webdriver.Firefox()
driver.get("http://www.douban.com")

#输入账号密码
driver.find_element_by_name("form_email").send_keys("13545******")
driver.find_element_by_name("form_password").send_keys("tt*****")

#模拟点击登陆
driver.find_element_by_xpath("//input[@class='bn-submit']").click()

#等待3秒
time.sleep(3)

#生成登陆后快照
driver.save_screenshot(u"douban.pag")

#退出浏览器
driver.quit()

实战二:爬取斗鱼所有房间名和观众人数

(1)首先分析“下一页”的class变化,如果不是最后一页的时候,‘下一页’的class如下:

(2)到了最后一页,“下一页”变为隐藏,点击不了,class如下:

(3)找到具体某个房间的名字和观众人数的class

实现代码如下:

#!/usr/bin/python3
#coding=utf-8

import unittest
from selenium import webdriver
from bs4 import BeautifulSoup as bs


class Douyu(unittest.TestCase):
    #初始化方法,必须是setUp()
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.num = 0
        self.count = 0

    #测试方法必须有test字样开头
    def test_douyu(self):
        self.driver.get("https://www.douyu.com/directory/all")

        while True:
            soup = bs(self.driver.page_source,"lxml")
            #房间名,返回列表
            names_list =  soup.findall("h3",{"class" : "ellipsis"})
            #观众人数,返回列表
            numbers_list = soup.findall("span",{"class" : "dy-num fr"})

            #zip(names_list,numbers_list)将names_list和number_list这两个列表合并为一个元组
            for name,number in zip(names_list,numbers_list):
                print("观众人数:%s,房间名:%s" % (number.get_text().strip(),name.get_text().strip()))
                self.num += 1
            
            #如果在页面源码中找到“下一页”为隐藏的标签,就退出循环
            if self.driver.page_source.find("shark-pager-disable-next") != -1:
                break
            #一直点击下一页
            self.driver.find_element_by_class_name("shark-pager-next").click()

    #测试结束执行的方法
    def tear_down(self):
        #退出Firefox()浏览器
        print("当前网站直播人数:%s" % str(self.num))
        print("当前网站观众人数:%s" % str(self.count))
        self.driver.quit()

if __name__ == "__main__":
    #启动测试模块
    unittest.main()
posted on 2022-03-24 17:28  雷子锅  阅读(460)  评论(0编辑  收藏  举报