请求库之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()