Selenium模块
-
便捷的获取网站中动态加载的数据,而无需单找ajax
-
便捷实现模拟登录。以前模拟登陆都是用url夹带cookie、data、params等。现在只需要卡密
什么是selemium?
一个基于浏览器自动化的模块,封装了一系列操作浏览器的动作(有点像pyautogui),实现能将访问url的操作下达给浏览器执行,由于是浏览器访问,自然有js引擎等翻译执行js等代码。简单来说这个东西就是高度模拟浏览器的行为达到跟真的一样的效果
环境配置
-
pip install selemium
-
需要下载浏览器的驱动程序,可以是EDGE、firefox等浏览器,在此用Chrome。这个页面好像是官方的谷歌驱动和谷歌浏览器的对应关系https://chromedriver.chromium.org/downloads
查看我的谷歌浏览器版本,发现是111版本,
(仅限114版本以前)
(chromedriver.exe是windows版的驱动,chromedriver是linux版的驱动)
下载对应驱动后,将驱动chromedriver放至项目的工作目录下
实战 - 爬取PTA的ajax刷新的内容
-
browser = webdriver.Chrome(executable_path='./chromedriver.exe') 实例化一个浏览器对象
-
browser.get('https://pintia.cn/problem-sets/dashboard') 浏览器访问网页。实战发现selenium会等待网页加载完毕才会继续向下执行代码,这点很nice
-
page_text = browser.page_source 拿到网页连同来自ajax内容的源码。如果连续对同一个网页进行本操作,其中第一次本操作后点击了某个刷新按钮,然后进行了第二次本操作,得到的page_text 是不一样的,或者说page_source 是实时最新的
-
parser = etree.HTMLParser(encoding='utf-8') tree = etree.HTML(page_text, parser=parser) # etree用HTML()去解析,毕竟咱也没保存过源码到本地啊~ result = tree.xpath(r'//a[@class="name_PCfmF"]//text()') 解析去吧
from selenium import webdriver
from lxml import etree
import time
# 实例化一个浏览器对象,参数为浏览器驱动路径
browser = webdriver.Chrome(executable_path='./chromedriver.exe')
# input() # 只执行上面代码,会因执行完打开浏览器而从浏览器闪退,可以在browser语句后面加个input就可以了
browser.get('https://pintia.cn/problem-sets/dashboard')
# time.sleep(5) # 可能会网页响应过慢 需要的内容没加载出来就执行下面代码了,不妨等它一会
page_text = browser.page_source
parser = etree.HTMLParser(encoding='utf-8')
tree = etree.HTML(page_text, parser=parser)
result = tree.xpath(r'//a[@class="name_PCfmF"]//text()')
print(result)
browser.quit() # 关闭浏览器
input()
输出结果:
webriiver类提供了常用的浏览器,你可以用之实例化出一个浏览器对象
实战 - 浏览器自动化操作
from selenium.webdriver.common.by import By
-
发起请求 browser.get('https://www.baidu.com')
-
标签定位 search_input = browser. find_element(By.ID, 'q') 见下表
-
标签交互 / 输入文字(都可以在无头浏览器时执行) search_input.send_keys('iphone')
-
执行js代码 browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
-
前进、后退网页
browser.execute_script('window.history.go(-1)') # 等同于browser.back()
browser.execute_script('window.history.go(1)') # 等同于browser.forward()
-
关闭浏览器 browser.quit()
-
更多操作是有的 需要了再搜
定位元素 | find_element() |
---|---|
通过元素id定位 | find_element(By.ID,x) |
通过元素name定位 | find_element(By.NAME,x) |
通过xpath表达式定位 | find_element(By.XPATH,x) |
通过完整超链接定位 | find_element(By.LINK_TEXT,x) |
通过部分链接定位 | find_element(By.PARTIAL_LINK_TEXT,x) |
通过标签定位 | find_element(By.TAG_NAME,x) |
通过类名进行定位 | find_element(By.CLASS_NAME,x) |
通过css选择器进行定位 | find_element(By.CSS_SELECTOR,x) |
from selenium import webdriver
from time import sleep
from lxml import etree
from selenium.webdriver.common.by import By
browser = webdriver.Chrome('./chromedriver.exe')
browser.get('https://www.taobao.com/')
# 定位标签
search_input = browser. find_element(By.ID, 'q') # id是最好的 因为正规的前端里id是一次性的
# 标签交互 / 输入文字
search_input.send_keys('iphone')
# 执行一组js代码,例如滚动
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
search_btn = browser.find_element(By.CLASS_NAME, 'btn-search')
search_btn.click() # 点击搜索按钮
sleep(2)
browser.get('https://www.baidu.com')
sleep(2)
# 后退
browser.execute_script('window.history.go(-1)') # 等同于browser.back()
sleep(2)
# 前进
browser.execute_script('window.history.go(1)') # 等同于browser.forward()
sleep(2)
browser.quit()
干掉滑块验证码
-
from selenium.webdriver import ActionChains 导包
-
browser.switch_to.frame('iframeResult') # 如果需要的标签在iframe里,切换浏览器标签定位的作用域,从默认的主战场即最大的html文档切换到<iframe id="iframeResult">里的html文档。这就意味着我们在选定元素时还要看看该标签是否在iframe里。
-
action = ActionChains(browser) 实例化动作链对象
-
action.click_and_hold(btn4) 初始化动作链
-
action.move_by_offset(17, 0).perform() 继续初始化动作链并执行
-
action.release() 释放动作链
附:有人说:要破解滑动验证可以深入学学OpenCV或者人工智能
iframe这个标签可以让目网页嵌套子网页,滑块验证码往往用到iframe,例如上图代码,我想定位到iframe里的<div id="droppable">标签,就不能用传统的browser. find_element(By.ID, 'droppable'),是找不到的。解决:
browser.switch_to.frame('iframeResult') # 切换浏览器标签定位的作用域,从默认的主战场即最大的html文档切换到<iframe id="iframeResult">里的html文档
browser. find_element(By.ID, 'droppable') # 此时就能定位到
# 登录QQ空间
# 省略输入密码等已会的操作,接下来是滑块验证码
# 续上面代码
browser.switch_to.frame('tcaptcha_iframe_dy')
btn4 = browser.find_element(By.XPATH, r'//div[@id="bodyWrap"]//div[@class="tc-opera"]/div[@class="tc-fg-item"]') # 没有id,用XPATH定位
# 将动作链和浏览器对象绑定并动作链对象
action = ActionChains(browser)
action.click_and_hold(btn4) # 初始化动作链,我们的动作时点击后按住滑块按钮
for i in range(5): # 为了教学效果才分五步
# action.move_by_offset(17)是在继续初始化动作链,.perform()是执行动作链
action.move_by_offset(17, 0).perform() # 每步水平偏移17像素,垂直偏移0像素
sleep(0.5)
action.release() # 释放动作链
input()
browser.quit()
Opencv
安装
pip install opencv-python
使用
# 案例
import cv2 #opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np
img=cv2.imread('cat.png')
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
用opencv识别滑块验证码的目标位置
这是验证码:
这是缺口图片,取名为1.png:
这是背景图片,取名为2.png:
import cv2
# 教程原文 http://www.manongjc.com/detail/59-upemuxhdgjgvnlj.html
def identify_gap(bg,tp,out):
'''
bg: 背景图片
tp: 缺口图片
out:输出图片
'''
# 读取背景图片和缺口图片
bg_img = cv2.imread(bg) # 背景图片
tp_img = cv2.imread(tp) # 缺口图片
# 识别图片边缘
bg_edge = cv2.Canny(bg_img, 100, 200)
tp_edge = cv2.Canny(tp_img, 100, 200)
# 转换图片格式
bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
# 缺口匹配
res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配
# 绘制方框
th, tw = tp_pic.shape[:2]
tl = max_loc # 左上角点的坐标
br = (tl[0]+tw,tl[1]+th) # 右下角点的坐标
cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2) # 绘制矩形
cv2.imwrite(out, bg_img) # 保存在本地
# 返回缺口的X坐标
return tl[0]
identify_gap('./2.png','1.png','./3.png')
执行上述代码得到3.png:
感悟
非要玩高级爬虫和opencv,我其实不建议,我不是专业的爬虫工程师。opencv很像matlab,我连付宇的matlab数字隐写课我都不感兴趣,我也不太想细学opencv。不建议非职业人士走深了。再比如,我现在有了上面的函数,我能确定灰色待填充框的左边界坐标了。结果我还要想办法找出缺口图片在背景图片中的左边界坐标、QQ空间传输的缺口图片使用精灵图实现的,这意味着我要得到纯洁的缺口图片还需要用opencv裁剪出来。
无头浏览器
用户在用我们的爬虫时莫名其妙弹出浏览器,对用户来说很灵异。我们可不可以不要图形化界面,让操作对用户透明?。
注意:那要是我没写关闭的代码咋手动关闭啊?:所以你不能不写browser.quit(),你还不能让代码永远执行不到browser.quit()
from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options # 非职业人士请不要背代码,复制粘贴即可
# 实例化Options对象
chrome_options = Options()
chrome_options.add_argument('--headless') # 无头
chrome_options.add_argument('--disable-gpu') # 禁用GPU # gpu是显示芯片,是做图像和图形相关运算工作的微处理器,GPU是显卡的“心脏
# 如果options=chrome_options报错,可能是版本改动了,换写chrome_options=chrome_options
browser = webdriver.Chrome(executable_path='./chromedriver.exe', options=chrome_options) # 至此无头浏览器诞生
browser.get('https://qzone.qq.com/')
page_source = browser.page_source
print(page_source) # 发现打印了页面源码,说明虽然我看不见页面但脚本确实在执行
出名的无头浏览器只有Chrome和phantomJs,但后者停止维护了。所以以后用无头浏览器也就Chrome可用了。
为linux编写的无头脚本还必须加:(windows可以不加)
chrome_options.add_argument('--no-sandbox') # 禁用沙盒 chrome_options.add_argument('--disable-dev-shm-usage') # 大量渲染时候写入/tmp而非/dev/shm
规避selenium被反爬(方法已失效,请忽略)
由于selenium越来越流行,很多门户网站知晓了这个库,他们可能有为selenium定制的反爬措施,当检测到是selenium发起的请求,就拒绝服务。
如何让selenium规避被网站服务器端检测到的风险?:
# 需要加入以下代码
from selenium.webdriver import ChromeOptions # 用于规避反爬检测
# 实现规避检测
# 友情提示:Chrome79以后版本 用这个方法不能规避检测
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
browser = webdriver.Chrome(executable_path='./chromedriver.exe', chrome_options=chrome_options, options=option)
具体示例:
from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options # 实现无可视化界面 # 非职业人士请不要背代码,复制粘贴即可
from selenium.webdriver import ChromeOptions # 用于规避反爬检测
# 实例化Options对象。实现无可视化界面
chrome_options = Options()
chrome_options.add_argument('--headless') # 无头
# 禁用GPU # gpu是显示芯片,是做图像和图形相关运算工作的微处理器,GPU是显卡的“心脏
chrome_options.add_argument('--disable-gpu')
# 实现规避检测
# 友情提示:Chrome79以后版本 用这个方法不能规避检测
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
# 如果chrome_options=chrome_options报错,可能是版本改动了,换写options=chrome_options
browser = webdriver.Chrome(executable_path='./chromedriver.exe', chrome_options=chrome_options, options=option) # 至此无头浏览器诞生
browser.get('https://qzone.qq.com/')
page_source = browser.page_source
print(page_source) # 发现打印了页面源码,说明虽然我看不见页面但脚本确实在执行
截图
# 可以在爬虫模拟浏览器时将当前的网页截图保存成图片,常用于无头浏览器的调试
browser.save_screenshot('screenshot.png')
经验
我做了个爬取天气网的api,执行可以返回天气。在非无头浏览器时是按预期输出的。无头是怎么也输出不了,报错是element isn't interactive,但是element.click()和element.send_keys('string')是可以在无头浏览器下执行的。就browser.save_screenshot('1.png') 截图嘛,发现是分辨率小了(屏幕尺寸没拉满),导致我要点击的element没显示出来。加了browser.set_window_size(1920,1080)成功解决了。
汇总 写Selenium爬虫至少有哪些参数
import requests
import sys
import json
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By
from lxml import etree
from selenium.webdriver.chrome.options import Options
from selenium.webdriver import ChromeOptions
executable_path = '/usr/local/sbin/chromedriver'
chrome_options = Options()
chrome_options.add_argument("--headless") # 无头
chrome_options.add_argument('--disable-gpu') # 禁用GPU
chrome_options.add_argument('--no-sandbox') # 禁用沙盒
chrome_options.add_argument('--disable-dev-shm-usage') # 大量渲染时候写入/tmp而非/dev/shm
chrome_options.add_argument('--start-maximized') # 最大化启动
# 设置UA,需要根据具体情况来设置UA值
chrome_options.add_argument('user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0"')
browser = webdriver.Chrome(executable_path=executable_path, chrome_options=chrome_options)
# 设置分辨率,需要根据具体情况来设值,尤其是响应式布局。你需要用的元素应能显示在画面上
browser.set_window_size(1920, 1080)
browser.get('http://www.weather.com.cn/')
browser.save_screenshot('shot.png')
附:Chrome浏览器的options参数
Selenium 默认在启动浏览器的时候,浏览器是以窗口化运行的,可对于页面点击或则进行动作链操作的时候,需要将浏览器最大化,否则可能执行出错。
chrome_options.add_argument('--start-maximized') # 最大化启动
像这样的参数还有很多,如下:
为linux编写的无头脚本还必须加:(windows可以不加)
chrome_options.add_argument('--no-sandbox') # 禁用沙盒
chrome_options.add_argument('--disable-dev-shm-usage') # 大量渲染时候写入/tmp而非/dev/shm
from selenium import webdriver
option = webdriver.ChromeOptions()
# 添加UA
options.add_argument('user-agent="MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"')
# 指定浏览器分辨率
options.add_argument('window-size=1920x3000')
# 谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('--disable-gpu')
# 隐藏滚动条, 应对一些特殊页面
options.add_argument('--hide-scrollbars')
# 不加载图片, 提升速度
options.add_argument('blink-settings=imagesEnabled=false')
# 浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
options.add_argument('--headless')
# 以最高权限运行
options.add_argument('--no-sandbox')
# 手动指定使用的浏览器位置
options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
#添加crx插件
option.add_extension('d:\crx\AdBlock_v2.17.crx')
# 禁用JavaScript
option.add_argument("--disable-javascript")
# 设置开发者模式启动,该模式下webdriver属性为正常值
options.add_experimental_option('excludeSwitches', ['enable-automation'])
# 禁用浏览器弹窗
prefs = {
'profile.default_content_setting_values' : {
'notifications' : 2
}
}
options.add_experimental_option('prefs',prefs)
driver=webdriver.Chrome(chrome_options=chrome_options)
其他配置项目参数:
-user-data-dir=”[PATH]”
# 指定用户文件夹User Data路径,可以把书签这样的用户数据保存在系统分区以外的分区
-disk-cache-dir=”[PATH]“
# 指定缓存Cache路径
-disk-cache-size=
# 指定Cache大小,单位Byte
-first run
# 重置到初始状态,第一次运行
-incognito
# 隐身模式启动
-disable-javascript
# 禁用Javascript
--omnibox-popup-count="num"
# 将地址栏弹出的提示菜单数量改为num个
--user-agent="xxxxxxxx"
# 修改HTTP请求头部的Agent字符串,可以通过about:version页面查看修改效果
--disable-plugins
# 禁止加载所有插件,可以增加速度。可以通过about:plugins页面查看效果
--disable-javascript
# 禁用JavaScript,如果觉得速度慢在加上这个
--disable-java
# 禁用java
--start-maximized
# 启动就最大化
--no-sandbox
# 取消沙盒模式
--single-process
# 单进程运行
--process-per-tab
# 每个标签使用单独进程
--process-per-site
# 每个站点使用单独进程
--in-process-plugins
# 插件不启用单独进程
--disable-popup-blocking
# 禁用弹出拦截
--disable-plugins
# 禁用插件
--disable-images
# 禁用图像
--incognito
# 启动进入隐身模式
--enable-udd-profiles
# 启用账户切换菜单
--proxy-pac-url
# 使用pac代理 [via 1/2]
--lang=zh-CN
# 设置语言为简体中文
--disk-cache-dir
# 自定义缓存目录
--disk-cache-size
# 自定义缓存最大值(单位byte)
--media-cache-size
# 自定义多媒体缓存最大值(单位byte)
--bookmark-menu
# 在工具 栏增加一个书签按钮
--enable-sync
# 启用书签同步
借助cookie实现免登录
原理
首先手动完成登录后,把cookies保存到本地;下次再把cookies注入到浏览器里面,就自动实现了登录
FIRST - 把cookies保存到本地
# 保存cookie.py
from selenium import webdriver
import json
browser = webdriver.Chrome("###########") # 自己填
### 打开要自动登录的网站,比如说csdn、淘宝
browser.get("https://www.csdn.net/")
###手动完成登录后,随便在控制台输入内容,就保存下来了
input("等待登录成功,登录成功后随便输入内容。")
dictCookies = browser.get_cookies()
jsonCookies = json.dumps(dictCookies)
with open('cookies.txt', 'w') as f:
f.write(jsonCookies)
print('cookies保存成功!')
此时生成《cookies.txt》
SECOND - 把保存到本地的cookies注入到浏览器里面
from selenium import webdriver
import json
browser = webdriver.Chrome("###########") # 自己填
### 打开要自动登录的网站如CSDN
browser.get("https://www.csdn.net/")
with open(name, 'r', encoding='utf8') as f: # name取《cookies.txt》路径
listCookies = json.loads(f.read())
for cookie in listCookies:
cookie_dict = {
### 这个domain看《cookies.txt》就知道了,需要找到并填入
'domain': '.csdn.net', # 自己填
'name': cookie.get('name'),
'value': cookie.get('value'),
"expires": '',
'path': '/',
'httpOnly': False,
'HostOnly': False,
'Secure': False
}
browser.add_cookie(cookie_dict)
# browser.refresh() # 刷新网页,cookies才成功
browser.get("https://www.csdn.net/") # 发现已登陆
注意事项
曾尝试不用《保存cookie.py》抓cookie,结果浏览器抓到的cookie,少很多键值对,比如就没有domain、name。
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://www.ink0.cn/index.php/2023/03/10/05selenium%e6%a8%a1%e5%9d%97/
共有 0 条评论