请求库之selenium

一、介绍

selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题

selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器

from selenium import webdriver

# 得到一个浏览器对象,相当于你打开了一个浏览器
browser=webdriver.Chrome()
browser=webdriver.Firefox()
browser=webdriver.PhantomJS()
browser=webdriver.Safari()
browser=webdriver.Edge()

官网

二、安装

1、有界面浏览器

#安装:selenium+chromedriver
pip3 install selenium

浏览器驱动,镜像站:http://npm.taobao.org/mirrors/chromedriver/
最新的版本去官网找:https://sites.google.com/a/chromium.org/chromedriver/downloads

驱动要跟浏览器版本对应 84.0.4147.105:驱动用84.0.4147.30/ 找比本机低的版本,向下兼容
下载--->解压是不同平台的可执行文件,windows是exe文件
下载chromdriver.exe放到python安装路径的scripts目录中,因为python路径已经加到环境变量中了

#验证安装
# chromdriver.exe如果没有加入环境变量,需要指定使用跟那个驱动
# 指定路径写绝对路径,这里因为放在项目根路径下,用的相对路径
from selenium import webdriver
import time

driver=webdriver.Chrome(executable_path="./chromedriver.exe")  # 得到一个谷歌浏览器对象
time.sleep(2)
driver.get("https://www.baidu.com/")                           # 相当于在浏览器地址栏里输入了百度网址
time.sleep(2)
print(driver.page_source)                                      # 拿到html页面,如果页面执行了js,就能拿到js渲染的数据
time.sleep(2)
driver.close()                                                 # 关闭浏览器

2、无界面浏览器

phantomjs,已经不维护了

# 谷歌浏览器支持不打开页面
from selenium.webdriver.chrome.options import Options
from selenium import webdriver

chrome_options = Options()                                           # 得到一个配置
chrome_options.add_argument("window-size=1920x3000")                 #指定浏览器分辨率
chrome_options.add_argument("--disable-gpu")                         #谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument("--hide-scrollbars")                     #隐藏滚动条, 应对一些特殊页面
chrome_options.add_argument("blink-settings=imagesEnabled=false")    #不加载图片, 提升速度

# 手动指定使用的浏览器位置,Chrome驱动exe放在环境变量 或executable_path指定了,这句就不用写了
chrome_options.binary_location = r"C:ProgramFiles(x86)GoogleChromeApplicationchrome.exe" 

# 浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
chrome_options.add_argument("--headless") 

drive=webdriver.Chrome(chrome_options=chrome_options, executable_path="./chromedriver.exe")
drive.get("https://www.baidu.com/")
print(drive.page_source)
drive.close()   # 不打开浏览器页面,但是进程是开启的,如果请求后不关闭,后面再执行,进程就越开越多

三、基本使用

#模拟登录百度

from selenium import webdriver
from selenium.webdriver.common.by import By                 #按照什么方式查找,By.ID, By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys             #键盘按键操作
import time

drive=webdriver.Chrome(executable_path="./chromedriver.exe")
# 1、模拟输入-->搜索
drive.get("https://www.baidu.com/")
time.sleep(0.01)
input_search=drive.find_element(By.ID, "kw")     # 按id查找,找到搜索的input框
input_search.send_keys("美女")                   # 在框里写入美女,可以从自己数据库拿出来动态输入
time.sleep(2)
方式1:
sou=drive.find_element(By.ID, "su")              # 找到搜索按钮
sou.click()                                      # 点击搜索按钮
方式2:模拟键盘操作,直接输入回车
input_search.send_keys(Keys.ENTER)
time.sleep(3)
drive.close()


# 2、模拟登录
drive=webdriver.Chrome(executable_path="./chromedriver.exe")
# 隐式等待:找一个控件,如果控件没有加载出来,等待5s,如果超过5秒没加载出来报错
# 隐式等待是等待所有,只需要写这一句,以后找所有控件都按这个操作来
drive.implicitly_wait(5)  
drive.get("https://www.baidu.com/")

# 登录按钮a标签,按a标签内容"登录"查找到这个a标签
login_button=drive.find_element(By.LINK_TEXT, "登录")
login_button.click()  

# 找到用户名密码登录按钮并点击,如果后面的控件还没有加载出来就点击会报错,所以用了隐式等待
login_u=drive.find_element(By.ID, "TANGRAM__PSP_11__footerULoginBtn")
login_u.click()

# 找到用户名密码输入框,输入用户名密码
username=drive.find_element(By.ID, "TANGRAM__PSP_11__userName")
username.send_keys("yxp654799481")
password=drive.find_element(By.ID, "TANGRAM__PSP_11__password")
password.send_keys("yxp997997")
time.sleep(3)

# 找到并点击提交按钮
submit=drive.find_element(By.ID, "TANGRAM__PSP_11__submit")
submit.click()
time.sleep(10)
# 拿到登录的cookie(建cookie池,用requests模块发请求),如果没登录进去会返回未登录的cookie
print(drive.get_cookies())

drive.close()

四、选择器

1、selenium内置的选择器

1、find_element_by_id   # 通过id查找控件
   新版 find_element(By.ID, "search_input") 
    
2、find_element_by_link_text  # 通过标签内容(文本)找
	新版 find_element(By.LINK_TEXT, "hao123")
    
3、find_element_by_partial_link_text  # 通过标签内容找,模糊匹配
	新版 find_element(By.PARTIAL_LINK_TEXT, "hao")

4、find_element_by_tag_name   # 通过标签名查找
	新版 find_element(By.TAG_NAME, "title")

5、find_element_by_class_name  # 通过类名查找
	新版 find_element(By.CLASS_NAME, "s_ipt") 
    
6、find_element_by_name        # name属性
	新版 find_element(By.NAME, "wd") 

7、find_element_by_css_selector  # 通过css选择器
	新版 find_element(By.CSS_SELECTOR, "#kw") 
    
8、find_element_by_xpath       # 通过xpaht选择器
	新版 find_element(By.XPATH, "//*[@id="kw"]") 
    
# 强调:
# 新版用法,先声明By模块,from selenium.webdriver.common.by import By
# find_element_by_xxx  单数只找第一个
# find_elements_by_xxx 复数是查找到所有,结果为列表

2、xpath选择器

介绍
xpath: XPath 是一门在 XML 文档中查找信息的语言
/  :从根节点选取。类似bs4的遍历文档树
// :不管位置,直接找
.  :选取当前节点
/@属性名  :取当前标签的属性
/text()  : 取当前标签的文本
浏览器调试可赋值css和xpath

# 示例文档
doc="""
<html>
 <head>
  <base href="http://example.com/" />
  <title>Example website</title>
 </head>
 <body>
  <div id="images">
   <a href="image1.html" aa="bb">Name: My image 1 <br /><img src="image1_thumb.jpg" /></a>
   <a href="image2.html">Name: My image 2 <br /><img src="image2_thumb.jpg" /></a>
   <a href="image3.html">Name: My image 3 <br /><img src="image3_thumb.jpg" /></a>
   <a href="image4.html">Name: My image 4 <br /><img src="image4_thumb.jpg" /></a>
   <a href="image5.html" class="li li-item" name="items">Name: My image 5 <br /><img src="image5_thumb.jpg" /></a>
   <a href="image6.html" name="items"><span><h5>test</h5></span>Name: My image 6 <br /><img src="image6_thumb.jpg" /></a>
  </div>
 </body>
</html>
"""

from lxml import etree

html=etree.HTML(doc)
html=etree.parse("search.html",etree.HTMLParser())  # 直接读取文本文件进行解析

# 1 找出所有节点,拿到一个列表,里面是所有标签对象
res=html.xpath("//*") 

# 2 指定节点(结果为列表),找head标签
res=html.xpath("//head")

# 3 子节点,子孙节点
a=html.xpath("//div/a")   # 找所有div下的a
a=html.xpath("//body/a")  # 无数据,body的子节点没有a标签,找不到
a=html.xpath("//body//a") # body为根节点就能找到所有a标签

# 4 父节点
a=html.xpath("//body//a[@href="image1.html"]/..")   # a标签按herf属性="image1.html"过滤
a=html.xpath("//body//a[1]/..")                     # 取第一个a标签,/..找父节点
# 也可以这样
a=html.xpath("//body//a[1]/parent::*")

# 5 属性匹配
a=html.xpath("//body//a[@href="image1.html"]") 

# 6 文本获取(重要)  /text() 取当前标签的文本
a=html.xpath("//body//a[@href="image1.html"]/text()")   # 取出1个a标签文本放在列表里
a=html.xpath("//body//a/text()")                        # 取出所有a标签文本,放在列表

# 7 属性获取  @href 取当前标签的href属性
a=html.xpath("//body//a/@href")   # 取出所有a标签href属性,放在列表

# 注意索引从1开始(不是从0)
a=html.xpath("//body//a[1]/@href") 

# 8 属性多值匹配
#  a 标签有多个class类,class="li li-item",直接匹配就不可以了,需要用contains
a=html.xpath("//body//a[@class="li"]")            # 还差一个class属性,取不到
a=html.xpath("//body//a[contains(@class,"li")]")  # class属性包含li,能取到a标签
a=html.xpath("//body//a[contains(@class,"li")]/text()")

# 9 多属性匹配
a=html.xpath("//body//a[contains(@class,"li") or @name="items"]")            # 或的关系,能拿出两个
a=html.xpath("//body//a[contains(@class,"li") and @name="items"]/text()")    #只能拿出一个
a=html.xpath("//body//a[contains(@class,"li")]/text()")

# 10 按序选择 
a=html.xpath("//a[2]/text()")            # 第二个a标签
a=html.xpath("//a[2]/@href")
a=html.xpath("//a[last()]/@href")         # 取最后一个
a=html.xpath("//a[position()<3]/@href")   # 位置小于3的
a=html.xpath("//a[last()-2]/@href")       # 倒数第二个

# 11 节点轴选择
# ancestor:祖先节点
a=html.xpath("//a/ancestor::*")     # 使用了* 获取所有祖先节点
a=html.xpath("//a/ancestor::div")   # 获取祖先节点中的div

# attribute:属性值
a=html.xpath("//a[1]/attribute::*")  # 拿出第一个a标签的所有属性
a=html.xpath("//a[1]/@aa")           # 拿出第一个a标签的aa属性

# child:直接子节点
a=html.xpath("//a[1]/child::*")
a=html.xpath("//a[1]/child::img/@src") # 拿第一个a标签img子节点的src属性

# descendant:所有子孙节点
a=html.xpath("//a[6]/descendant::*")
a=html.xpath("//a[6]/descendant::h5/text()")

# following:当前节点之后所有节点(兄弟节点和兄弟内部的节点)
a=html.xpath("//a[1]/following::*")
a=html.xpath("//a[1]/following::*[1]/@href")

# following-sibling:当前节点之后同级节点(只找兄弟)
a=html.xpath("//a[1]/following-sibling::*")
a=html.xpath("//a[1]/following-sibling::a")
a=html.xpath("//a[1]/following-sibling::*[2]")
a=html.xpath("//a[1]/following-sibling::*[2]/@href")
print(a)

浏览器network找到需要的标签,复制selector(css选择器),复制xpath(xpath选择器)
//以后去查找标签,bs4的find,  css,xpath(通用的)

3、获取标签属性

# 重点
tag.get_attribute("href")   # tag是查找出来的标签(控件),get_attribute找当前控件的href属性对的值
tag.text                    # 获取文本内容
tag.location                # 当前控件在页面位置,应用:验证码截图

# 了解
tag.id        # 当前控件id号
tag.tag_name  # 标签名
tag.size      # 标签的大小

4、等待元素被加载

#1、selenium只是模拟浏览器的行为,而浏览器解析页面是需要时间的(执行css,js),一些元素可能需要过一段时间才能加载出来,为了保证能查找到元素,必须等待

#2、等待的方式分两种:
隐式等待:在browser.get("xxx")前就设置,针对所有元素有效
显式等待:在browser.get("xxx")之后设置,只针对某个元素有效

#隐式等待:在查找所有元素时,如果尚未被加载,则等10秒
browser.implicitly_wait(10)

5、元素交互操作

5.1 基本操作
tag.send_keys()  # 往里面写内容(搜索框、input框)
tag.click()      # 点击控件(提交按钮)
tag.clear()      # 清空控件内容


5.2、自己写js
# 有一些操作需要借助js来做,交互动作难实现,自己手写js代码,比如写js代码取出cookie
from selenium import webdriver
import time
bro=webdriver.Chrome(executable_path="./chromedriver.exe")
bro.implicitly_wait(5) 
bro.get("https://www.baidu.com/")

bro.execute_script("alter("hello")") # 里面写js代码
bro.execute_script("window.open()")  # js操作新打开一个页面
bro.execute_script("window.open()")  # js操作再新打开一个页面
time.sleep(2)
bro.close()


5.3 ActionChains 动作链(了解)
# 移动x轴和y轴的距离
ActionChains(driver).move_by_offset(xoffset=2,yoffset=2).perform()

# 直接移动到某个控件上
ActionChains(driver).move_to_elment().perform()

# 在某个控件上,移动X轴与y轴的距离
ActionChains(driver).move_to_element_with_offset(img, xoffset, yoffset).perform()

# 点击一个控件,并按住不动,相当于鼠标左键一直按着,再移动距离就实现了拖动
# 用来模拟滑动验证,但是滑动验证后台规则设计复杂,已经很难破解了
ActionChains(driver).click_and_hold(sourse).perform()

# 释放动作链
ActionChains(driver).release().perform()


5.4 frame的切换,现在很少了,相当于1个浏览器双开了2个页面,可以相互切换
bro.switch_to.frame("iframeResult") #切换到id为iframeResult的frame上


5.5 如何把屏幕拉到最下(js控制)
# scrollTo(起始位,终止位) 函数
bro.execute_script("window.scrollTo(0,document.body.offsetHeight)")

五、其他

1、模拟浏览器前进和后退

from selenium import webdriver
import time
bro=webdriver.Chrome(executable_path="./chromedriver.exe")
bro.get("https://www.baidu.com")
bro.get("https://www.taobao.com")
bro.get("http://www.sina.com.cn/")

bro.back()
time.sleep(1)
brow.forward()
bro.close()

2、cookies

bro.get_cookies()                       # 获取cookie
bro.add_cookie({"k1":"xxx","k2":"yyy"}) # 已经有cookie,登录时自动带cookie登录(了解)
bro.delete_all_cookies()                # 删除浏览器中的所有cookie(了解)

3、选项卡管理(了解)

from selenium import webdriver
import time
browser=webdriver.Chrome()
browser.get("https://www.baidu.com")
browser.execute_script("window.open()")               # 执行js代码,新打开一个标签页面

print(browser.window_handles)                         #获取所有的选项卡
browser.switch_to_window(browser.window_handles[1])   # 移动到新打开的标签上
browser.get("https://www.taobao.com")
time.sleep(2)
browser.switch_to_window(browser.window_handles[0])   # 移动到旧的标签上
browser.get("https://www.sina.com.cn")
browser.close()                                        # 只关闭了0页面,还要切到1上再关闭1的标签

4、异常处理

from selenium import webdriver
# selenlium中的异常分几类,不用分这么细,总的捕获异常就行了,所有操作放在try中
from selenium.common.exceptions import TimeoutException,NoSuchElementException,NoSuchFrameException

browser=webdriver.Chrome()
try:
  browser.get("")
except Exception as e:
     print(e)
finally:  # 无论是否出异常,最终都要关掉
    browser.close()  
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 请求库之selenium