Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器)。 Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。
Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行,所以我们可以用一个叫 PhantomJS 的工具代替真实的浏览器。
安装
pip3 install selenium
selenium不自带浏览器,所以我们需要第三方浏览器
驱动下载:
谷歌驱动(chromedriver)下载地址: http://chromedriver.storage.googleapis.com/index.html
火狐驱动下载路径(GeckoDriver):https://github.com/mozilla/geckodriver/releases(2.3.8是最新的,下载的驱动版本一定要支持你当前的浏览器版本)
页面的相关操作:
获取id标签值
element = driver.find_element_by_id("passwd-id")
获取name标签值
element = driver.find_element_by_name("user-name")
获取标签名值
element = driver.find_elements_by_tag_name("input")
也可以通过XPath来匹配
element=driver.find_element_by_xpath("//input[@id='passwd-id']")
页面前进和后退
操作页面的前进和后退功能:
driver.forward() #前进
driver.back() # 后退
添加cookies
driver.add_cookie(cookie_dict)
删除Cookies,用法如下
- 删除一个特定的cookie
driver.delete_cookie("CookieName") - 删除所有cookie
driver.delete_all_cookies()
设置无头浏览器
opt = webdriver.ChromeOptions()
opt.set_headless()
设置代理
opt = webdriver.ChromeOptions()
opt.add_argument("--proxy-server=http://118.20.16.82:9999")
代码:
# pip3 install selenium
# selenium不自带浏览器,必须跟第三方的浏览器配合使用
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
#如何设置屋头浏览器
opt = webdriver.ChromeOptions()
#设置为无头浏览器()
# opt.set_headless()
# 设置代理
opt.add_argument("--proxy-server=http://202.20.16.82:10152")
#创建一个浏览器的驱动
chrome_driver = webdriver.Chrome(
executable_path='/home/ljh/桌面/driver/chromedriver',
)
chrome_driver.get('https://www.baidu.com/')
#chrome_driver.save_screenshot('baidu.png')
#PhantomJS屋头浏览器
# phantom_js = webdriver.PhantomJS(executable_path='/home/ljh/桌面/driver/phantomjs')
#
# phantom_js.get('https://www.baidu.com/')
#
# phantom_js.save_screenshot('baidu2.png')
#获取页面源码(这时候获取的页面源码是经过浏览器渲染之后的结果)
#豆瓣的例子
#chrome_driver.get('https://movie.douban.com/subject_search?search_text=%E7%94%B5%E5%BD%B1&cat=1002')
html_data = chrome_driver.page_source
#获取cookies
cookies = chrome_driver.get_cookies()
print(cookies)
#可以获取当前请求的url
cur_url = chrome_driver.current_url
#模拟用户操作
#以百度为例
#再搜搜兰中输入文字
chrome_driver.find_element_by_id('kw').send_keys('中国我的国')
#点击按钮
chrome_driver.find_element_by_id('su').click()
# time.sleep(3)
# 隐士等待:当我们寻找节点的时候,有时候页面可能没有加载出来,
# 设置隐士等待,没找到的话会等一会继续寻找,如果在设定的时间内还没有找到
# 会出现异常错误
chrome_driver.implicitly_wait(10)
#显示等待
#点击下一页
# chrome_driver.find_element_by_class_name('n').click()
#根据文字寻找
chrome_driver.find_element_by_link_text('下一页>').click()
# with open('page.html','w') as file:
# file.write(html_data)
chrome_driver.find_element_by_id('kw').clear()
chrome_driver.find_element_by_id('kw').send_keys('我的媳妇是谁')
#Keys.RETURN模拟键盘的回车操作
chrome_driver.find_element_by_id('su').send_keys(Keys.RETURN)
"""
#通关节点的name属性查找对应的节点
chrome_driver.find_element_by_name()
#通过节点的class_name找到对应的节点
chrome_driver.find_element_by_class_name()
#通过css选择器查找对应的节点
chrome_driver.find_element_by_css_selector()
#通过连接所在标签的部分文字找到对应的节点
chrome_driver.find_element_by_partial_link_text()
#通过xpath路径找对对应的节点
chrome_driver.find_element_by_xpath()
.....
"""
#获取节点的属性get_attribute('属性的名称')
print(chrome_driver.find_element_by_id('su').get_attribute('value'))
#获取节点的文本.text
print(chrome_driver.find_element_by_class_name('n').text)
#回退
chrome_driver.back()
#前进
chrome_driver.forward()
#关闭浏览器(只有一个界面会退出浏览器,多个界面时只表示关闭当前界面)
chrome_driver.close()
#退出浏览器
chrome_driver.quit()
页面等待
注意:这是非常重要的一部分!! 现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。 为了避免这种元素定位困难而且会提高产生 ElementNotVisibleException 的概率。所以 Selenium 提供了两种等待方式,一种是隐式等待,一种是显式等待。
隐式等待是等待特定的时间,显式等待是指定某一条件直到这个条件成立时继续执行。
隐式等待
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
显式等待
显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,那么便会抛出异常了。 程序默认会 0.5s 调用一次来查看元素是否已经生成,如果本来元素就是存在的,那么会立即返回。
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 库,负责循环等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 类,负责条件出发
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("http://www.xxxxx.com/loading")
try:
##### 会在这里等待,如果10秒内 id="myDynamicElement"的标签出现
则返回,如果不出现则报异常
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.ID, "myDynamicElement")
)
)
finally:
driver.quit()
异常处理
请求超时异常处理
from selenium.common.exceptions import TimeoutException
try:
brower.get(url)
except TimeoutException:
print('Time out')
找不到标签的异常处理
from selenium.common.exceptions import NoSuchElementException
try:
brower.find_element_by_id('').click()
print('有标签')
except NoSuchElementException:
print('没有这个标签')
selenium动态页面模拟点击案例:
爬取斗鱼直播平台的所有房间信息:
from selenium import webdriver
import json
import time
class Douyu:
# 1.发送首页的请求
def __init__(self):
self.driver = webdriver.PhantomJS()
self.driver.get("https://www.douyu.com/directory/all") #请求首页
#获取没页面内容
def get_content(self):
time.sleep(3) #每次发送完请求等待三秒,等待页面加载完成
li_list = self.driver.find_elements_by_xpath('//ul[@id="live-list-contentbox"]/li')
contents = []
for i in li_list: #遍历房间列表
item = {}
item["img"] = i.find_element_by_xpath("./a//img").get_attribute("src") #获取房间图片
item["title"] = i.find_element_by_xpath("./a").get_attribute("title") #获取房间名字
item["category"] = i.find_element_by_xpath("./a/div[@class='mes']/div/span").text #获取房间分类
item["name"] = i.find_element_by_xpath("./a/div[@class='mes']/p/span[1]").text #获取主播名字
item["watch_num"] = i.find_element_by_xpath("./a/div[@class='mes']/p/span[2]").text #获取观看人数
print(item)
contents.append(item)
return contents
#保存本地
def save_content(self,contents):
f = open("douyu.txt","a")
for content in contents:
json.dump(content,f,ensure_ascii=False,indent=2)
f.write("\n")
f.close()
def run(self):
#1.发送首页的请求
#2.获取第一页的信息
contents = self.get_content()
#保存内容
self.save_content(contents)
#3.循环 点击下一页按钮,知道下一页对应的class名字不再是"shark-pager-next"
while self.driver.find_element_by_class_name("shark-pager-next"): #判断有没有下一页
#点击下一页的按钮
self.driver.find_element_by_class_name("shark-pager-next").click() #
# 4.继续获取下一页的内容
contents = self.get_content()
#4.1.保存内容
self.save_content(contents)
if __name__ == "__main__":
douyu = Douyu()
douyu.run()