一个神奇的自动化爬虫利器 - DrissionPagae
Art_s 2024-06-19 14:37:02 阅读 68
DrissionPagae
DrissionPage:类似 selenuium 的网页自动化工具。这是一个基于 Python 的网页自动化工具,支持 Chromium 内核浏览器。它将控制浏览器和收发请求两大功能合二为一,并提供了统一、简洁的接口。
环境
操作系统:Windows、Linux 或 Mac。
python 版本:3.6 及以上
支持应用:Chromium 内核浏览器(如 Chrome、Edge),electron 应用
相关
github - DrissionPage
文档 - DrissionPage
DrissionPageJava: DrissionPage的Jave版本
SaossionPage: Drissionpage 库的兄弟版 SaossionPage 简称骚神
元素定位助手 和 代码生成助手: https://gitee.com/haiyang0726/SaossionPage/releases
DataRecorder
数据写入
优势
无 webdriver 特征无需为不同版本的浏览器下载不同的驱动运行速度更快可以跨<iframe>
查找元素,无需切入切出把<iframe>
看作普通元素,获取后可直接在其中查找元素,逻辑更清晰可以同时操作浏览器中的多个标签页,即使标签页为非激活状态,无需切换可以直接读取浏览器缓存来保存图片,无需用 GUI 点击另存可以对整个网页截图,包括视口外的部分(90以上版本浏览器支持)可处理非open
状态的 shadow-root支持应用:Chromium 内核浏览器(如 Chrome、Edge),electron 应用 可能之所以不被检测到,是因为DrissionPage的底层基于cdp协议(Chrome DevTools Protocol)),
以下是懒神推荐读的cdp代码 https://chromedevtools.github.io/devtools-protocol/
什么是cdp
众所周知F12能够打开开发者工具Q进行调试,开发者工具即DevTools大家应该都知道,那么ChromeDevTools就是用的CDP协议来跟浏览器进行交互的调试等一系列操作的。CDP是通过RESTfulAPI提供了对浏览器内部运行情况的访问,可以通过这些API来控制Chrome浏览器的行为,来做到与DevTools类似的功能:获取页面信息、监控网络活动、执行JS等操作。cdp协议简称chrome调试协议,是基于scoket(websocketQ、usb、adb)消息的jsonrpc协议。用来调用chrome内部的方法实现js,css,dom的开发调试。可以将实现了cdp协议的应用看做rpc调用的服务端(chrome,puppeteer),将调试面板看做rpc调用的客户端(devtools)。
pip install DrissionPage#更新较快,快进行更新pip install DrissionPage --upgrade
默认配置
默认配置在这里
D:\ruanjian\PY\Miniconda3\Lib\site-packages\DrissionPage\_configs\config.ini
[paths]download_path =tmp_path =[chromium_options]address = 127.0.0.1:9222browser_path = chromearguments = ['--no-default-browser-check', '--disable-suggestions-ui', '--no-first-run', '--disable-infobars', '--disable-popup-blocking', '--hide-crash-restore-bubble', '--disable-features=PrivacySandboxSettings4']extensions = []prefs = {'profile.default_content_settings.popups': 0, 'profile.default_content_setting_values': {'notifications': 2}}flags = {}load_mode = normaluser = Defaultauto_port = Falsesystem_user_path = Falseexisting_only = False[session_options]headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'connection': 'keep-alive', 'accept-charset': 'GB2312,utf-8;q=0.7,*;q=0.7'}[timeouts]base = 10page_load = 30script = 30[proxies]http =https = [others]retry_times = 3retry_interval = 2
SessionPage
SessionPage
对象和WebPage
对象的 s 模式,可用收发数据包的形式访问网页。
顾名思义,SessionPage
是一个使用使用Session
(requests 库)对象的页面,它使用 POM 模式封装了网络连接和 html 解析功能,使收发数据包也可以像操作页面一样便利。
并且,由于加入了本库独创的查找元素方法,使数据的采集便利性远超 requests + beautifulsoup 等组合。
创建页面对象
通过配置信息创建
如果需要在使用前进行一些配置,可使用SessionOptions。它是专门用于设置Session对象初始状态的类,内置了常用的配置。详细使用方法见“启动配置”一节。
从指定 ini 文件创建
以上方法是使用默认 ini 文件中保存的配置信息创建对象,你可以保存一个 ini 文件到别的地方,并在创建对象时指定使用它。
from DrissionPage import SessionPage, SessionOptions# 创建配置对象时指定要读取的ini文件路径so = SessionOptions(ini_path=r'./config1.ini')# 使用该配置对象创建页面page = SessionPage(session_or_options=so)
不使用 ini 文件
可以用以下方法,指定不使用 ini 文件的配置,而把配置写在代码中。
from DrissionPage import SessionPage, SessionOptionsso = SessionOptions(read_file=False) # read_file设为Falseso.set_retry(5)page = SessionPage(so)
传递控制权
当需要使用多个页面对象共同操作一个页面时,可在页面对象创建时接收另一个页面间对象传递过来的Session对象,以达到多个页面对象同时使用一个Session对象的效果。
# 创建一个页面page1 = SessionPage()# 获取页面对象内置的Session对象session = page1.session# 在第二个页面对象初始化时传递该对象page2 = SessionPage(session_or_options=session)
访问
get
get()
方法语法与 requests 的get()
方法一致,在此基础上增加了连接失败重试功能。与 requests 不一样的是,它不返回Response
对象。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
url | str | 必填 | 目标 url |
show_errmsg | bool | False | 连接出错时是否显示和抛出异常 |
retry | int | None | 重试次数,为None 时使用页面参数,默认 3 |
interval | float | None | 重试间隔(秒),为None 时使用页面参数,默认 2 |
timeout | float | None | 加载超时时间(秒) |
**kwargs | - | None | 连接所需其它参数,具体见 requests 用法 |
读取本地文件
get()
的url
参数可指向本地文件,实现本地 html 解析。
from DrissionPage import SessionPagepage = SessionPage()page.get(r'D:\demo.html')
访问在线网页
from DrissionPage import SessionPagepage = SessionPage()url = 'https://www.baidu.com'headers = { 'referer': 'gitee.com'}cookies = { 'name': 'value'}proxies = { 'http': '127.0.0.1:1080', 'https': '127.0.0.1:1080'}page.get(url, headers=headers, cookies=cookies, proxies=proxies)
post
post 方式请求页面。用法与get()一致。返回bool
# 向 data 参数传入字符串page.post(url, data='abc=123')# 向 data 参数传入字典page.post(url, data={'abc': '123'})# 向 json 参数传入字符串page.post(url, json='abc=123')# 向 json 参数传入字典page.post(url, json={'abc': '123'})page.json()
ChromiumPage
ChromiumPage
对象和WebPage
对象的 d 模式,可操控浏览器。本章介绍ChromiumPage
。
顾名思义,ChromiumPage
是 Chromium 内核浏览器的页面,它用 POM 方式封装了操控网页所需的属性和方法。
使用它,我们可与网页进行交互,如调整窗口大小、滚动页面、操作弹出框等等。
通过从中获取的元素对象,我们还可以跟页面中的元素进行交互,如输入文字、点击按钮、选择下拉菜单等等。
甚至,我们可以在页面或元素上运行 JavaScript 代码、修改元素属性、增删元素等。
除了与页面和元素的交互,ChromiumPage
还扮演着浏览器控制器的角色,可以说,一个ChromiumPage
对象,就是一个浏览器。
它可以对标签页进行管理,可以对下载任务进行控制。可以为每个标签页生成独立的页面对象(ChromiumTab
),以实现多标签页同时操作,而无需切入切出。
ChromiumPage()参数 addr_or_opts: 浏览器地址:端口、ChromiumOptions对象或端口数字(int)tab_id: 要控制的标签页id,不指定默认为激活的timeout: 超时时间(秒)
启动或接管浏览器
会使用默认配置,自动生成页面对象
只要这个浏览器不关闭,下次运行程序时会接管同一个浏览器继续操作(配置的 ip: port 信息不变)。这种方式极大地方便了程序的调试,使程序不必每次重新开始,可以单独调试某个功能。
from DrissionPage import ChromiumPage# 创建对象同时启动浏览器,如果浏览器已经存在,则接管它page = ChromiumPage()
接管已打开的浏览器
页面对象创建时,只要指定的地址(ip: port)已有浏览器在运行,就会直接接管。无论浏览器是下面哪种方式启动的。
多浏览器共存(推荐)
如果想要同时操作多个浏览器,或者自己在使用其中一个上网,同时控制另外几个跑自动化,就需要给这些被程序控制的浏览器设置单独的端口和用户文件夹,否则会造成冲突。
from DrissionPage import ChromiumPage, ChromiumOptionsco = ChromiumOptions().set_paths(local_port=9999, user_data_path='./user_data')page = ChromiumPage(addr_or_opts=co)page.get('https://www.baidu.com')
ChromiumOptions对象的auto_port()
方法,可以指定程序每次使用空闲的端口和临时用户文件夹创建浏览器。也是每个浏览器要使用独立的ChromiumOptions对象。但这种方法创建的浏览器不能重复使用。
# 初始化Chromium浏览器选项co = ChromiumOptions().auto_port()# 创建Chromium页面对象page = ChromiumPage(co)
使用系统浏览器用户目录
这种情况下用户不能打开一个浏览器使用
初始默认配置下,程序会为每个使用的端口创建空的用户目录,并且每次接管都使用,这样可以有效避免浏览器冲突。
有些时候我们希望使用系统安装的浏览器的默认用户文件夹。以便复用用户信息和插件等。
from DrissionPage import ChromiumPage, ChromiumOptionsco = ChromiumOptions().use_system_user_path()page = ChromiumPage(co)
使用 ini 文件
把这个配置记录到 ini 文件,就不用每次使用都配置。
from DrissionPage import ChromiumOptionsChromiumOptions().use_system_user_path().save()
ChromiumOptions对象
命令行参数设置
ChromiumOptions对象下的方法
[!NOTE] set_argument():用于设置启动参数。
arg [str] 必填 启动参数名称value[str|None|False]=None 参数的值。带值的参数传入属性值,没有值的传入None。如传入False,删除该参数。
[!NOTE] remove_argument()
Contents
[!NOTE] clear_arguments()
Contents
# 设置启动时最大化co.set_argument('--start-maximized')# 设置初始窗口大小co.set_argument('--window-size', '800,600')# 使用来宾模式打开浏览器co.set_argument('--guest')#禁用通知警告co.set_argument('--disable-notifications')#禁止所有弹出窗口co.set_pref(arg='profile.default_content_settings.popups', value='0')#阻止“自动保存密码”的提示气泡co.set_pref('credentials_enable_service', False)#阻止“要恢复页面吗?Chrome未正确关闭”的提示气泡co.set_argument('--hide-crash-restore-bubble')#通知用户他们的浏览器是由自动测试控制的。co.set_argument('--enable-automation')
运行路径及端口
📌 set_browser_path()
📌 set_tmp_path()
📌 set_local_port()
📌 set_address()
📌 auto_port()
📌 set_user_data_path()
📌 use_system_user_path()
📌 set_cache_path()
📌 existing_only()
使用插件
📌 add_extension()
📌 remove_extensions()
方法
参数
ChromiumOptions() read_file=True,ini_path=None
方法
ChromiumOptions()对象.方法名
运行参数设置
set_timeouts(base,page_load,script):用于设置几种超时时间,以秒为单位
base默认超时时间,用于元素等待、alert 等待、WebPage的 s 模式连接等等,除以下两个参数的场景,都使用这个设置page_load 页面加载超时时间script JavaScript 运行超时时间
set_load_mode():用于设置网页加载策略。加载策略是指强制页面停止加载的时机,如加载完 DOM 即停止,不加载图片资源等,以提高自动化效率。
'normal'
:阻塞进程,等待所有资源下载完成(默认)'eager'
:DOM 就绪即停止加载'none'
:网页连接成功即停止加载
set_proxy():用于设置浏览器代理。
常用设置
set_paths():快捷的路径设置函数
browser_path: 浏览器可执行文件路径C:\Program Files\Google\Chrome\Application\chrome.exe
local_port: 本地端口号address: 调试浏览器地址,例:127.0.0.1:9222download_path: 下载文件路径user_data_path: 用户数据路径cache_path: 缓存路径
一般来说用户文件夹的名称是 User Data
。对于默认情况下的 Windows 中的 Chrome 浏览器来说,此文件夹位于 %USERPROFILE%\AppData\Local\Google\Chrome\User Data\
实际路径请在浏览器输入 chrome://version/
,查阅其中的个人资料路径
或者叫用户配置路径
。
📌 set_tmp_path():用于设置临时文件存放路径。
📌 auto_port():设置是否使用自动分配的端口,启动一个全新的浏览器。
如果设置为True,程序会自动寻找一个可用端口,并在指定路径或系统临时文件夹创建一个文件夹,用于储存浏览器数据。由于端口和用户文件夹都是唯一的,所以用这种方式启动的浏览器不会产生冲突,但也无法多次启动程序时重复接管同一个浏览器。set_local_port()、set_address()和set_user_data_path()方法,会和auto_port()互相覆盖,即以后调用的为准。
📌 set_user_data_path()此方法用于设置用户文件夹路径。用户文件夹用于存储当前登陆浏览器的账号在使用浏览器时留下的痕迹,包括设置选项等。
📌 use_system_user_path():设置是否使用系统安装的浏览器默认用户文件夹
📌 existing_only():设置是否仅使用已启动的浏览器,如连接目标浏览器失败,会抛出异常,不会启动新浏览器。
on_off bool True bool表示开关
属性
📌 address为要控制的浏览器地址,格式为 ip:port,默认为’127.0.0.0:9222’。类型:str
📌 browser_path:该属性返回浏览器可执行文件的路径。类型:str
📌 user_data_path
该属性返回用户数据文件夹路径。
类型:str
📌 tmp_path:该属性返回临时文件夹路径,可用于保存自动分配的用户文件夹路径。类型:str
📌 download_path
该属性返回默认下载路径文件路径。
类型:str
📌 user:该属性返回用户配置文件夹名称。类型:str
📌 load_mode该属性返回页面加载策略。有’normal’、‘eager’、'none’三种 ,类型:str
📌 timeouts:该属性返回超时设置。包括三种:‘base’、‘page_load’、‘script’。类型:dict
print(co.timeouts)
输出:
{ 'base': 10, 'page_load': 30, 'script': 30}
📌 retry_times该属性返回连接失败时的重试次数。类型:int
📌 retry_interval该属性返回连接失败时的重试间隔(秒)。类型:float
📌 proxy该属性返回代理设置。类型:str
📌 arguments该属性以list形式返回浏览器启动参数。类型:list
📌 extensions该属性以list形式返回要加载的插件路径。类型:list
📌 preferences该属性返回用户首选项配置。类型:dict
📌 system_user_path该属性返回是否使用系统按照的浏览器的用户文件夹。类型:bool
📌 is_existing_only该属性返回是否仅使用已打开的浏览器。类型:bool
📌 is_auto_port:该属性返回是否仅使用自动分配端口和用户文件夹路径。类型:bool
访问网页
ChromiumPage
对象和WebPage
对象的 d 模式都能控制浏览器访问网页。这里只对ChromiumPage
进行说明
get():用于跳转到一个网址。当连接失败时,程序会进行重试。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
url | str | 必填 | 目标 url,可指向本地文件路径 |
show_errmsg | bool | False | 连接出错时是否显示和抛出异常 |
retry | int | None | 重试次数,为None 时使用页面参数,默认 3 |
interval | float | None | 重试间隔(秒),为None 时使用页面参数,默认 2 |
timeout | float | None | 加载超时时间(秒) |
加载模式
加载模式是指程序在页面加载阶段的行为模式,有以下三种:
normal()
:常规模式,会等待页面加载完毕,超时自动重试或停止,默认使用此模式
eager()
:加载完 DOM 或超时即停止加载,不加载页面资源
none()
:超时也不会自动停止,除非加载完成
前两种模式下,页面加载过程会阻塞程序,直到加载完毕才执行后面的操作。
none()
模式下,只在连接阶段阻塞程序,加载阶段可自行根据情况执行stop_loading()
停止加载。
这样提供给用户非常大的自由度,可等到关键数据包或元素出现就主动停止页面加载,大幅提升执行效率。
加载完成是指主文档完成,并不包括由 js 触发的加载和重定向的加载。 当文档加载完成,程序就判断加载完毕,此后发生的重定向或 js 加载数据需用其它逻辑处理。
配置对象中设置
from DrissionPage import ChromiumOptions, ChromiumPageco = ChromiumOptions().set_load_mode('none')page = ChromiumPage(co)
运行中设置
from DrissionPage import ChromiumPagepage = ChromiumPage()page.set.load_mode.none()
none
模式技巧
示例 1,配合监听器
跟监听器配合,可在获取到需要的数据包时,主动停止加载。
from DrissionPage import ChromiumPagepage = ChromiumPage()page.set.load_mode.none() # 设置加载模式为nonepage.listen.start('api/getkeydata') # 指定监听目标并启动监听page.get('http://www.hao123.com/') # 访问网站packet = page.listen.wait() # 等待数据包page.stop_loading() # 主动停止加载print(packet.response.body) # 打印数据包正文
示例 2,配合元素查找
跟元素查找配合,可在获取到某个指定元素时,主动停止加载。
from DrissionPage import ChromiumPagepage = ChromiumPage()page.set.load_mode.none() # 设置加载模式为nonepage.get('http://www.hao123.com/') # 访问网站ele = page.ele('中国日报') # 查找text包含“中国日报”的元素page.stop_loading() # 主动停止加载print(ele.text) # 打印元素text
示例 2,配合页面特征
可等待到页面到达某种状态时,主动停止加载。比如多级跳转的登录,可等待 title 变化到最终目标网址时停止。
from DrissionPage import ChromiumPagepage = ChromiumPage()page.set.load_mode.none() # 设置加载模式为nonepage.get('http://www.hao123.com/') # 访问网站page.wait.title_change('hao123') # 等待title变化出现目标文本page.stop_loading() # 主动停止加载
获取网页信息
成功访问网页后,可使用ChromiumPage
自身属性和方法获取页面信息。
操控浏览器除了ChromiumPage
,还有ChromiumTab
和ChromiumFrame
两种页面对象分别对应于标签页对象和<iframe>
元素对象,后面会有单独章节介绍。
页面信息
📌 html:返回当前页面 html 文本。
📌 json:把请求内容解析成 json。
📌 title:返回当前页面title文本。
📌 user_agent:返回当前页面 user agent 信息。
📌 browser_version:返回当前浏览器版本号。
📌 save():把当前页面保存为文件,同时返回保存的内容。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
path | str
| None | 保存路径,为None 且name 不为None 时保存到当前路径 |
name | str | None | 保存的文件名,为None 且path 不为None 时使用 title 值 |
as_pdf | bool | False | 为Ture 保存为 pdf,否则保存为 mhtml 且忽略kwargs 参数 |
**kwargs | 多种 | 无 | pdf 生成参数 |
运行状态信息
📌 url:返回当前访问的 url。
📌 address:返回当前对象控制的页面地址和端口。
📌 tab_id:返回当前标签页的 id。
📌 process_id:返回浏览器进程 id。
📌 states.is_loading:返回页面是否正在加载状态。
📌 states.is_alive:返回页面是否仍然可用,标签页已关闭则返回False。
📌 states.ready_state:返回页面当前加载状态,有 4 种: ‘connecting’: 网页连接中'loading'
:表示文档还在加载中'interactive'
:DOM 已加载,但资源未加载完成'complete'
:所有内容已完成加载
📌 url_available:以布尔值返回当前链接是否可用。
📌 states.has_alert:以布尔值返回页面是否存在弹出框。
窗口信息
📌rect.size
:以tuple返回页面大小,格式:(宽, 高)。📌 rect.window_size
:以tuple返回窗口大小,格式:(宽, 高)。📌 rect.window_location
:以tuple
返回窗口在屏幕上的坐标,左上角为(0, 0)。📌 rect.window_state
:以返回窗口当前状态,有'normal'
、'fullscreen'
、'maximized'
、 'minimized'
几种。📌 rect.viewport_size:以tuple
返回视口大小,不含滚动条,格式:(宽, 高)。📌 rect.viewport_size_with_scrollbar
:以tuple
返回浏览器窗口大小,含滚动条,格式:(宽, 高)。📌 rect.page_location
:以tuple
返回页面左上角在屏幕中坐标,左上角为(0, 0)。📌 rect.viewport_location
:以tuple
返回视口在屏幕中坐标,左上角为(0, 0)。 配置参数信息
📌 timeout
📌 timeouts
📌 retry_times
📌 retry_interval
📌 load_mode
cookies 和缓存信息
📌 cookies()
:返回 cookies 信息。
📌 session_storage()
:用于获取 sessionStorage 信息,可获取全部或单个项。
📌 local_storage()
:用于获取 localStorage 信息,可获取全部或单个项。
内嵌对象
📌 driver
:返回当前页面对象使用的Driver对象。
自动等待
页面对象的等待
wait.load_start()
:等待页面进入加载状态后。
wait.doc_loaded()
wait.ele_loaded()
wait.ele_displayed()
wait.ele_hidden()
wait.ele_deleted()
wait.download_begin()
wait.upload_paths_inputted()
wait.new_tab()
wait.title_change()
wait.url_change()
wait()
标签页操作
一个 Tab 对象(ChromiumTab
和WebPageTab
)控制一个浏览器的标签页,是页面控制的主要单位。
一个标签页也可以被多个 Tab 对象同时控制(需禁用单例)。
DrissionPage 支持多 tab 对象共存,对象之间互不影响,而且标签页无需激活即可操作。
多标签页用法
标签页总览
📌 tabs_count
📌 tab_ids
新建标签页
new_tab()参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
url | str
| None | 新标签页访问的网址,不传入则新建空标签页 |
new_window | bool | False | 是否在新窗口打开标签页 |
background | bool | False | 是否不激活新标签页,如new_window 为True 则无效 |
new_context | bool | False | 是否创建新的上下文,为True 则打开一个无痕模式的新窗口,新窗口与其它窗口不共用 cookies |
获取标签页对象
📌 get_tab():获取一个标签页对象。可指定标签页序号、id、标题、url、类型等条件用于检索。📌 get_tabs():查找符合条件的 tab 对象。可指定标签页标题、url、类型等条件用于检索。 title str 要匹配的标题文本,模糊匹配,为None则匹配所有url str 要匹配的 url 文本,模糊匹配,为None则匹配所有tab_type 标签页类型,可用列表输入多个,如’page’,'iframe’等,as_id bool 是否返回标签页 id 而不是标签页对象 📌 latest_tab:返回最后激活的标签页对象。指最新出现或最新被激活的标签页。tab = page.get_tab() # 获取Page对象控制的标签页的Tab对象(即Page和Tab对象同时控制一个标签页)tab = page.get_tab(1) # 获取列表中第1个标签页的对象tab = page.get_tab('5399F4ADFE3A27503FFAA56390344EE5') # 获取列表中指定id标签页的对象tab = page.get_tab(url='baidu.com') # 获取所有url中带 'baidu.com' 的标签页对象
from DrissionPage import ChromiumPagepage = ChromiumPage()page.get('https://www.baidu.com')page.new_tab('https://www.baidu.com')tabs = page.get_tabs(url='baidu.com')print(tabs)
# 打开了一个标签页ele.click()# 获取最新标签页对象tab = page.latest_tab # 与page.get_tab(0)效果一致
使用多例
默认情况下,Tab 对象是单例的,即一个标签页只有一个对象,即使重复使用get_tab()
,获取的都是同一个对象。
这主要是防止新手不理解机制,反复创建多个连接导致资源耗费。
实际上允许多个 Tab 对象同时操作一个标签页,每个负责不同的工作。比如一个执行主逻辑流程,另外的监视页面,处理各种弹窗。
要允许多例,可用Settings
设置:
from DrissionPage.common import SettingsSettings.singleton_tab_obj = False
from DrissionPage import ChromiumPagefrom DrissionPage.common import Settingspage = ChromiumPage()page.new_tab()page.new_tab()# 未启用多例:tab1 = page.get_tab(1)tab2 = page.get_tab(1)print(id(tab1), id(tab2))# 启用多例:Settings.singleton_tab_obj = Falsetab1 = page.get_tab(1)tab2 = page.get_tab(1)print(id(tab1), id(tab2))
关闭和重连
📌 close():用于标签页关闭自己。Page 对象和 Tab 对象都有此方法。📌 disconnect():用于页面对象断开和浏览器的连接,但不关闭标签页。断开后,对象不能对标签页进行操作。Page 对象和 Tab 对象都有此方法。📌 reconnect():用于关闭与页面连接,然后重建一个新连接。这主要用于应付长期运行导致内存占用过高,断开连接可释放内存,然后重连继续控制浏览器。Page、Tab 和ChromiumFrame对象都有此方法。📌 close_tabs():用于关闭指定的标签页,可关闭多个。默认关闭当前的。只有 Page 对象拥有。 tabs_or_ids:要处理的标签页对象或 id,可传入列表或元组,为None时处理当前页others [bool]:是否关闭指定标签页之外的激活标签页
📌 set.tab_to_front():此方法用于激活标签页使其处于最前面。但不会把当前对象焦点跳转到该标签页。只有 Page 对象拥有📌 set.activate():此方法用于 Tab 对象或 Page 对象激活自己。多标签页协同
iframe 操作
获取<iframe>
对象
获取<iframe>
对象的方法有两种,可用获取普通元素的方式获取,或者用get_frame()
方法获取。推荐优先使用get_frame()
方法,因为当作普通元素获取时,IDE 无法正确识别获取到的是<iframe>
元素。
# 使用定位符获取iframe = page.get_frame('#sss')# 获取第2个iframeiframe = page.get_frame(1)
📌 get_frame()
📌 get_frames():获取页面中多个符合条件的<frame>
或<iframe>
对象。获取所有<iframe>
会很慢,而且浪费资源,一般使用获取需要用到的就好。
📌 普通元素方式
查找<iframe>
内元素
在<iframe>
内查找
# 使用定位符获取iframe = page.get_frame('#sss')ele = iframe('首页')print(ele)#<ChromiumElement a href='https://www.runoob.com/' data-id='index' title='菜鸟教程' class='current'>
页面跨<iframe>
查找
如果<iframe>
元素的网址和主页面是同域的,我们可以直接用页面对象查找<iframe>
内部元素,而无需先获取ChromiumFrame
对象:
ele = page('首页')print(ele)#<ChromiumElement a href='https://www.runoob.com/' data-id='index' title='菜鸟教程' class='current'>
监听网络数据
许多网页的数据来自接口,在网站使用过程中动态加载,如使用 JS 加载内容的翻页列表。
这些数据通常以 json 形式发送,浏览器接收后,对其进行解析,再加载到 DOM 相应位置。
做数据采集的时候,我们往往从 DOM 中去获取解析后数据的,可能存在数据不全、加载响应不及时、难以判断加载完成等问题。
如果我们可以拿到浏览器收发的数据包,根据数据包状态判断下一步操作,甚至直接获取数据,岂不是爽爆了?
DrissionPage 每个页面对象(包括 Tab 和 Frame 对象)内置了一个监听器,专门用于抓取浏览器数据包。可以提供等待和捕获指定数据包,实时返回指定数据包功能。
等待并获取
from DrissionPage import ChromiumPagepage = ChromiumPage()page.get('https://gitee.com/explore/all') # 访问网址,这行产生的数据包不监听page.listen.start('gitee.com/explore') # 开始监听,指定获取包含该文本的数据包for _ in range(5): page('@rel=next').click() # 点击下一页 res = page.listen.wait() # 等待并获取一个数据包 print(res.url) # 打印数据包url
实时获取
from DrissionPage import ChromiumPagepage = ChromiumPage()page.listen.start('gitee.com/explore') # 开始监听,指定获取包含该文本的数据包page.get('https://gitee.com/explore/all') # 访问网址i = 0for packet in page.listen.steps(): print(packet.url) # 打印数据包url page('@rel=next').click() # 点击下一页 i += 1 if i == 5: break
设置目标和启动监听
📌 listen.start():用于启动监听器,启动同时可设置获取的目标特征。可设置多个特征,符合条件的数据包会被获取。如果监听未停止时调用这个方法,可清除已抓取的队列。📌 listen.set_targets():可在监听过程中修改监听目标,也可在监听开始前设置。如监听未启动,不会启动监听。以上两个函数的参数一样
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
targets | str
| None | 要匹配的数据包 url 特征,可用列表指定多个,为True 时获取所有 |
is_regex | bool | None | 设置的 target 是否正则表达式,为None 时保持原来设置 |
method | str
| None | 设置监听的请求类型,可指定多个,默认('GET', 'POST') ,为True 时监听所有,为None 时保持原来设置 |
res_type | str
| None | 设置监听的 ResourceType 类型,可指定多个,为True 时监听所有,为None 时保持原来设置 |
等待和获取数据包
📌 listen.wait():用于等待符合要求的数据包到达指定数量。所有符合条件的数据包都会存储到队列,wait()实际上是逐个从队列中取结果,不用担心页面已刷走而丢包。📌 listen.steps():此方法返回一个可迭代对象,用于for循环,每次循环可从中获取到的数据包。可实现实时获取并返回数据包。如果timeout超时,会中断循环。📌 listen.wait_silent():用于等待所有指定的请求完成。📌 listen.wait():用于等待符合要求的数据包到达指定数量。所有符合条件的数据包都会存储到队列,wait()实际上是逐个从队列中取结果,不用担心页面已刷走而丢包。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
count | int | 1 | 需要捕捉的数据包数量 |
timeout | float
| None | 超时时间,为None 无限等待 |
fit_count | bool | True | 是否必需满足总数要求,如超时,为True 返回False ,为False 返回已捕捉到的数据包 |
raise_err | bool | None | 超时时是否抛出错误,为None 时根据Settings 设置,如不抛出,超时返回False |
返回类型 | 说明 |
---|---|
DataPacket | count 为1 且未超时,返回一个数据包对象 |
List[DataPacket] | count 大于1 ,未超时或fit_count 为False ,返回数据包对象组成的列表 |
False | 超时且fit_count 为True 时 |
📌 listen.steps():此方法返回一个可迭代对象,用于for循环,每次循环可从中获取到的数据包。可实现实时获取并返回数据包。如果timeout超时,会中断循环。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
count | int | None | 需捕获的数据包总数,为None 表示无限 |
timeout | float
| None | 每个数据包等待时间,为None 表示无限等待 |
gap | int | 1 | 每接收到多少个数据包返回一次数据 |
返回类型 | 说明 |
---|---|
DataPacket | gap 为1 时,返回一个数据包对象 |
List[DataPacket] | gap 大于1 ,返回数据包对象组成的列表 |
📌 listen.wait_silent():用于等待所有指定的请求完成。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
timeout | float
| None | 等待时间,为None 表示无限等待 |
targets_only | bool | False | 是否只等待targets 指定的请求结束 |
limit | int | 0 | 剩下多少个连接时视为结束 |
返回类型 | 说明 |
---|---|
bool | 是否等待成功 |
暂停和恢复
📌 listen.pause(clear):用于暂停监听。 clear [bool] True 是否清空已获取队列 📌 listen.resume():此方法用于继续暂停的监听。📌 listen.stop():此方法用于终止监听器的运行,会清空已获取的队列,不清空 targets。DataPacket对象
DataPacket
对象是获取到的数据包结果对象,包含了数据包各种信息。
对象属性
属性名称 | 数据类型 | 说明 |
---|---|---|
tab_id | str | 产生这个请求的标签页的 id |
frameId | str | 产生这个请求的框架 id |
target | str | 产生这个请求的监听目标 |
url | str | 数据包请求网址 |
method | str | 请求类型 |
is_failed | bool | 是否连接失败 |
resourceType | str | 资源类型 |
request | Request | 保存请求信息的对象 |
response | Response | 保存响应信息的对象 |
fail_info | FailInof | 保存连接失败信息的对象 |
wait_extra_info()
有些数据包有extra_info
数据,但这些数据可能会迟于数据包返回,用这个方法可以等待这些数据加载到数据包对象。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
timeout | float
| None | 超时时间,None 为无限等待 |
返回类型 | 说明 |
---|---|
bool | 是否等待成功 |
📌 wait_extra_info()
Request对象
Request
对象是DataPacket
对象内用于保存请求信息的对象,有以下属性:
属性名称 | 数据类型 | 说明 |
---|---|---|
url | str | 请求的网址 |
method | str | 请求类型 |
headers | CaseInsensitiveDict | 以大小写不敏感字典返回 headers 数据 |
cookies | List[dict] | 返回发送的 cookies |
postData | str
| post 类型的请求所提交的数据,json 以dict 格式返回 |
除以上常用属性,还有以下属性,自行体会:
urlFragment、hasPostData、postDataEntries、mixedContentType、initialPriority、referrerPolicy、isLinkPreload、trustTokenParams、isSameSite
Response对象
DataPacket.respose
Response
对象是DataPacket
对象内用于保存响应信息的对象,有以下属性:
属性名称 | 数据类型 | 说明 |
---|---|---|
url | str | 请求的网址 |
headers | CaseInsensitiveDict | 以大小写不敏感字典返回 headers 数据 |
body | str
| 如果是 json 格式,自动进行转换,如果时图片格式,进行 base64 转换,其它格式直接返回文本 |
raw_body | str | 未被处理的 body 文本 |
status | int | 请求状态 |
statusText | str | 请求状态文本 |
除以上属性,还有以下属性,自行体会:
headersText、mimeType、requestHeaders、requestHeadersText、connectionReused、connectionId、remoteIPAddress、remotePort、fromDiskCache、fromServiceWorker、fromPrefetchCache、encodedDataLength、timing、serviceWorkerResponseSource、responseTime、cacheStorageCacheName、protocol、alternateProtocolUsage、securityState、securityDetails
FailInfo对象
FailInfo
对象是DataPacket
对象内用于保存连接失败信息的对象,有以下属性:
属性名称 | 数据类型 | 说明 |
---|---|---|
errorText | str | 错误信息文本 |
canceled | bool | 是否取消 |
blockedReason | str | 拦截原因 |
corsErrorStatus | str | cors 错误状态 |
动作链
动作链可以在浏览器上完成一系列交互行为,如鼠标移动、鼠标点击、键盘输入等。
ChromiumPage、WebPage、ChromiumTab、ChromiumFrame对象支持使用动作链。可以链式操作,也可以分开执行,每个动作执行即生效,无需perform()。这些操作皆为模拟,真正的鼠标不会移动,因此可以多个标签页同时操作。
有两种方式可以使用动作链,两者区别是,前者会等待页面加载完毕再执行,后者不会。
使用内置actions属性调用动作链: page.actions.主动创建一个动作链对象,Actions (ChromiumPage|WebPage|ChromiumTab)
from DrissionPage import ChromiumPagefrom DrissionPage.common import Actions#1.使用内置actions属性page = ChromiumPage()page.get('https://www.baidu.com')page.actions.move_to('#kw').click().type('DrissionPage')page.actions.move_to('#su').click()#2.使用新对象page = ChromiumPage()ac = Actions(page)page.get('https://www.baidu.com')ac.move_to('#kw').click().type('DrissionPage')ac.move_to('#su').click()
移动鼠标
[!NOTE]- move_to (): 此方法用于移动鼠标到元素中点,或页面上的某个绝对坐标。可设置偏移量,当带偏移量时,偏移量相对于元素左上角坐标。
初始化参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
ele_or_loc | ChrmoiumElement / str / Tuple[int, int] | 必填 | 元素对象、文本定位符或绝对坐标,坐标为 tuple (int, int) 形式 |
offset_x | int | 0 | x 轴偏移量,向右为正,向左为负 |
offset_y | int | 0 | y 轴偏移量,向下为正,向上为负 |
duration | float | 0.5 | 拖动用时,传入 0 即瞬间到达 |
返回类型 | Actions | 0 | 动作链对象本身 |
📌 move()
📌 up()
📌 down()
📌 left()
📌 right()
鼠标按键
📌 click()
📌 r_click()
📌 m_click()
📌 db_click()
📌 hold()
📌 release()
📌 r_hold()
📌 r_release()
📌 m_hold()
📌 m_release()
滚动滚轮
📌 scroll()
键盘按键和文本输入
📌 key_down()
📌 key_up()
📌 input()
📌 type()
截图和录制
页面截图
页面对象的get_screenshot()
方法对页面进行截图,可对整个网页、可见网页、指定范围截图。
下面三个参数三选一,优先级:as_bytes
>as_base64
>path
。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
path | str
| None | 保存图片的路径,为None 时保存在当前文件夹,如包含文件名的完整路径,name 参数无效。 |
name | str | None | 完整文件名,后缀可选'jpg' 、'jpeg' 、'png' 、'webp' ,为None 时以用 jpg 格式 |
as_bytes | str
| None | 是否以字节形式返回图片,可选'jpg' 、'jpeg' 、'png' 、'webp' 、None 、True 不为 为 |
as_base64 | str
| None | 是否以 base64 形式返回图片,可选'jpg' 、'jpeg' 、'png' 、'webp' 、None 、True 不为 为 |
full_page | bool | False | 是否整页截图,为True 截取整个网页,为False 截取可视窗口 |
left_top | Tuple[int, int] | None | 截取范围左上角坐标 |
right_bottom | Tuple[int, int] | None | 截取范围右下角坐标 |
返回类型 | 说明 |
---|---|
bytes | as_bytes 生效时返回图片字节 |
str | as_bytes 和as_base64 为None 时返回图片完整路径 |
str | as_base64 生效时返回 base64 格式的字符串 |
页面录像
页面对象.screencast
:可以录取屏幕图片或视频。 📌 设置录制模式
📌 设置存放路径
📌 screencast.start()
📌 screencast.stop()
📌 注意事项
📌 示例
WebPage
WebPage()参数 mode: ‘d’ 或 ‘s’,即driver模式和session模式timeout: 超时时间(秒),d模式时为寻找元素时间,s模式时为连接时间,默认10秒chromium_options: Driver对象,只使用s模式时应传入Falsesession_or_options: Session对象或SessionOptions对象,只使用d模式时应传入Falsefrom DrissionPage import WebPage, ChromiumOptionsclass Obj(object): def __init__(self, page): self.page = page def main(self): passif __name__ == '__main__': co = ChromiumOptions().use_system_user_path() page = WebPage(mode='d', chromium_options=co) ob = Obj(page) ob.main()
元素
元素定位
定位符语法简化
定位语法都有其简化形式
页面和元素对象都实现了__call__()
方法,所以page.ele(‘…’)可简化为page(‘…’)
查找方法都支持链式操作
原写法 | 简化写法 | 说明 |
---|---|---|
@id | # | 表示 id 属性,简化写法只在语句最前面且单独使用时生效 |
@class | . | 表示 class 属性,简化写法只在语句最前面且单独使用时生效 |
text | tx | 按文本匹配 |
@text() | @tx() | 按文本查找与 @ 或 @@ 配合使用时 |
tag | t | 按标签类型匹配 |
xpath | x | 用 xpath 方式查找元素 |
css | c | 用 css selector 方式查找元素 |
# 查找tag为div的元素ele = page.ele('tag:div') # 原写法ele = page('t:div') # 简化写法# 用xpath查找元素ele = page.ele('xpath://xxxxx') # 原写法ele = page('x://xxxxx') # 简化写法# 查找text为'something'的元素ele = page.ele('text=something') # 原写法ele = page('tx=something') # 简化写法# 根据 class 或 id 查找page.ele('#ele_id') # 等价于 page.ele('@id=ele_id')page.ele('#:ele_id') # 等价于 page.ele('@id:ele_id')page.ele('.ele_class') # 等价于 page.ele('@class=ele_class')page.ele('.:ele_class') # 等价于 page.ele('@class:ele_class')# 根据 tag name 查找page.ele('tag:li') # 查找第一个 li 元素 page.eles('tag:li') # 查找所有 li 元素 # 根据 tag name 及属性查找page.ele('tag:div@class=div_class') # 查找 class 为 div_class 的 div 元素
相对定位参数简化
相对定位时,有时需要获取当前元素后某个元素,而不关心该元素是什么类型,
ele2 = ele1.parent(2)ele2 = ele1.next(2)('tx=xxxxx')ele2 = ele1.before(2)# 如此类推
匹配模式
模糊匹配 :模糊匹配 :匹配开头 ^匹配结尾 $# 获取name属性为'row1'的元素ele = page.ele('@name=row1')# 获取name属性包含'row1'的元素ele = page.ele('@name:row1')# 获取name属性以'row1'开头的元素ele = page.ele('@name^ro')# 获取name属性以'w1'结尾的元素ele = page.ele('@name$w1')
基本方法
id 匹配符 # :表示id属性,只在语句最前面且单独使用时生效,可配合匹配模式使用。类型匹配符 tag:表示元素的标签,只在语句最前面且单独使用时生效,可与@、@@或@|配合使用。tag:与tag=效果一致,没有tag^和tag$语法。# 定位div元素ele2 = ele1.ele('tag:div')# 定位class属性为p_cls的p元素ele2 = ele1.ele('tag:p@class=p_cls')# 定位文本为"第二行"的p元素ele2 = ele1.ele('tag:p@text()=第二行')# 定位class属性为p_cls且文本为“第二行”的p元素ele2 = ele1.ele('tag:p@@class=p_cls@@text()=第二行')# 定位class属性为p_cls或文本为“第二行”的p元素ele2 = ele1.ele('tag:p@|class=p_cls@|text()=第二行')# 查找直接文本节点包含“二行”字符串的p元素ele2 = ele1.ele('tag:p@text():二行')# 查找内部文本节点包含“二行”字符串的p元素ele2 = ele1.ele('tag:p@@text():二行')
属性
class 匹配符 .# 查找class属性为p_cls的元素ele2 = ele1.ele('.p_cls')# 查找class属性'_cls'文本开头的元素ele2 = ele1.ele('.^_cls') # 精确查找class属性为`p_cls1 p_cls2 `的元素ele2 = ele1.ele('.p_cls1 p_cls2 ')#如果某元素有多个类名,必须写 class 属性的完整值(类名的顺序也不能变)# 模糊查找class属性含有类名 'p_cls2' 的元素ele2 = ele1.ele('.:p_cls2')
单属性匹配符 @:表示某个属性,只匹配一个属性。可单独使用,也可与tag配合使用。
# 查找name属性为row1的元素ele2 = ele1.ele('@name=row1')# 查找name属性包含row文本的元素,可以跟匹配模式ele2 = ele1.ele('@name:row')# 查找有name属性的元素ele2 = ele1.ele('@name')# 查找没有任何属性的元素ele2 = ele1.ele('@')# 查找email属性为abc@def.com的元素,有多个@也不会重复处理ele2 = ele1.ele('@email=abc@def.com')# 属性中有特殊字符的情形,匹配abc@def属性等于v的元素ele2 = ele1.ele('css:div[abc\@def="v"]')
多属性与匹配符 @@:匹配同时符合多个条件的元素时使用,每个条件前面添加@@作为开头。多属性或匹配符@| :匹配符合多个条件中任一项的元素时使用,每个条件前面添加@|作为开头。属性否定匹配符@! :用于否定某个条件,可与@@或@|混用,也可单独使用。
# 查找name属性为row1且class属性包含cls文本的元素ele2 = ele1.ele('@@name=row1@@class:cls')ele = page.ele('tag:div@@class=p_cls@@name=row1')# 查找id属性为one或id属性为two的元素ele2 = ele1.ele('@|id=one@|id=two')ele = page.ele('tag:div@|class=p_cls@|name=row1')# 匹配arg1等于abc且arg2不等于def的元素page.ele('@@arg1=abc@!arg2=def')# 匹配arg1等于abc或arg2不等于def的div元素page.ele('t:div@|arg1=abc@!arg2=def')# 匹配arg1不等于abcpage.ele('@!arg1=abc')# 匹配没有arg1属性的元素page.ele('@!arg1')
文本
文本匹配符 text: 要匹配的文本,查询字符串如开头没有任何关键字,也表示根据传入的文本作模糊查找。如果元素内有多个直接的文本节点,精确查找时可匹配所有文本节点拼成的字符串,模糊查找时可匹配每个文本节点。如果要匹配的文本包含特殊字符(如’ ‘、’>'),需将其转换为十六进制形式,详见《语法速查表》一节。# 查找文本为“第二行”的元素ele2 = ele1.ele('text=第二行')# 查找文本包含“第二”的元素ele2 = ele1.ele('text:第二')# 与上一行一致ele2 = ele1.ele('第二')# 匹配包含 文本的元素ele2 = ele1.ele('第\u00A0二') # 需将 转为\u00A0
文本匹配符 text(): 作为查找属性时使用的文本关键字,必须与@或@@配合使用。text
在作为属性查找条件是改为text()
,是为了避免遇到名为text
的属性时产生冲突。
# 查找文本为“第二行”的元素ele2 = ele1.ele('@text()=第二行')# 查找文本包含“第二行”的元素ele2 = ele1.ele('@text():二行')# 查找文本以“第二”开头且class属性为p_cls的元素ele2 = ele1.ele('@@text()^第二@@class=p_cls')# 查找文本为“二行”且没有任何属性的元素(因第一个 @@ 后为空)ele2 = ele1.ele('@@@@text():二行')# 查找直接子文本包含“二行”字符串的元素ele = page.ele('@text():二行')
@@text()的技巧
css和xpath
css selector 匹配符 css :表示用 css selector 方式查找元素。css:
与css=
效果一致,没有css^
和css$
语法。 # 查找 div 元素ele2 = ele1.ele('css:.div')# 查找 div 子元素元素,这个写法是本库特有,原生不支持ele2 = ele1.ele('css:>div')
xpath 匹配符 xpath
# 查找后代中第一个 div 元素ele2 = ele1.ele('xpath:.//div')# 和上面一行一样,查找元素的后代时,// 前面的 . 可以省略ele2 = ele1.ele('xpath://div')# 使用xpath获取div元素的class属性(页面元素无此功能)ele_class_str = ele1.ele('xpath://div/@class')
selenium 的 loc 元组
from DrissionPage.common import By# 查找id为one的元素loc1 = (By.ID, 'one')ele = page.ele(loc1)# 按 xpath 查找loc2 = (By.XPATH, '//p[@class="p_cls"]')ele = page.ele(loc2)
相对定位
父子元素
[!NOTE] parent(level_or_loc=1,index=1)获取父级元素
level_or_loc[int|str|Tuple[str, str]]:第几级父元素,从
1
开始,或用定位符在祖先元素中进行筛选index [int] :当level_or_loc
传入定位符,使用此参数选择第几个结果,从当前元素往上级数;当level_or_loc
传入数字时,此参数无效
# 获取 ele1 的第二层父元素ele2 = ele1.parent(2)# 获取 ele1 父元素中 id 为 id1 的元素ele2 = ele1.parent('#id1')
child()
此方法返回当前元素的一个直接子节点,可指定筛选条件和第几个。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
locator | str
| '' | 用于筛选节点的查询语法,为int 类型时index 参数无效 |
index | int | 1 | 查询结果中的第几个,从1 开始,可输入负数表示倒数 |
timeout | float | None | 无实际作用 |
ele_only | bool | True | 是否只查找元素,为False 时把文本、注释节点也纳入查找范围 |
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
locator | str
| '' | 用于筛选节点的查询语法 |
timeout | float | None | 无实际作用 |
ele_only | bool | True | 是否只查找元素,为False 时把文本、注释节点也纳入查找范围 |
前面
prev():获取前面的同级节点:此方法返回当前元素前面的某一个同级节点,可指定筛选条件和第几个。prevs():返回当前元素前面全部符合条件的同级节点组成的列表,可用查询语法筛选。before():返回当前元素前面的某一个符合条件的节点,可指定筛选条件和第几个。查找范围不限同级节点,而是整个 DOM 文档。befores():返回当前元素前面全部符合条件的节点组成的列表,可用查询语法筛选。查找范围不限同级节点,而是整个 DOM 文档。参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
locator | str
| '' | 用于筛选节点的查询语法,为int 类型时index 参数无效 |
index | int | 1 | 查询结果中的第几个,从1 开始,可输入负数表示倒数 |
timeout | float | None | 无实际作用 |
ele_only | bool | True | 是否只查找元素,为False 时把文本、注释节点也纳入查找范围 |
# 获取 ele1 前面第一个兄弟元素ele2 = ele1.prev()# 获取 ele1 前面第 3 个兄弟元素ele2 = ele1.prev(3)# 获取 ele1 前面第 3 个 div 兄弟元素ele2 = ele1.prev(3, 'tag:div')# 获取 ele1 前面第一个文本节点的文本txt = ele1.prev(1, 'xpath:text()')
后面
next()
获取后面的同级节点,也叫兄弟节点:nexts():返回当前元素后面全部符合条件的同级节点组成的列表,可用查询语法筛选。after()
:在后面文档中查找节点afters()
:返回当前元素后面符合条件的全部节点组成的列表,可用查询语法筛选。查找范围不限同级节点,而是整个 DOM 文档 page('账号').after('t:input').input('123')page('密码').after('t:input').input('456')
元素信息
与SessionElement共有信息
属性或方法 | 说明 |
---|---|
html | 此属性返回元素的 outerHTML 文本 |
inner_html | 此属性返回元素的 innerHTML 文本 |
tag | 此属性返回元素的标签名 |
text | 此属性返回元素内所有文本组合成的字符串 |
raw_text | 此属性返回元素内原始文本 |
texts() | 此方法返回元素内所有直接子节点的文本,包括元素和文本节点 |
comments | 此属性以列表形式返回元素内的注释 |
attrs | 此属性以字典形式返回元素所有属性及值 |
attr() | 此方法返回元素某个 attribute 属性值 |
link | 此方法返回元素的 href 属性或 src 属性 |
page | 此属性返回元素所在的总控页面对象 |
xpath | 此属性返回当前元素在页面中 xpath 的绝对路径 |
css_path | 此属性返回当前元素在页面中 css selector 的绝对路径 |
状态信息
状态信息藏在states属性中。元素对象.states
states.is_in_viewport
:返回元素是否在视口中,以元素可以接受点击的点为判断。states.is_whole_in_viewport
:返回元素是否整个在视口中。states.is_alive
:返回当前元素是否仍可用。用于判断 d 模式下是否因页面刷新而导致元素失效。states.is_checked
:返回表单单选或多选元素是否选中。states.is_selected
:返回<select>
元素中的项是否选中。states.is_enabled
:以布尔值返回元素是否可用。states.is_displayed
:返回元素是否可见。states.is_covered
:返回元素是否被其它元素覆盖。如被覆盖,返回覆盖元素的 id,否则返回False
states.has_rect
:返回元素是否拥有大小和位置信息,有则返回四个角在页面上的坐标组成的列表,没有则返回False。
大小和位置
📌 rect.size
📌 rect.location
📌 rect.midpoint
📌 rect.click_point
📌 rect.viewport_location
📌 rect.viewport_midpoint
📌 rect.viewport_click_point
📌 rect.screen_location
📌 rect.screen_midpoint
📌 rect.screen_click_point
📌 rect.corners
📌 rect.viewport_corners
📌 rect.viewport_rect
保存元素
[!NOTE] src():返回元素
src
属性所使用的资源。timeout=None:等待资源加载超时时间,为
None
时使用元素所在页面timeout
属性base64_to_bytes= True:为True
时,如果是 base64 数据,转换为bytes
格式返回类型:base64 的可转为bytes
返回,其它的以str
返回。无资源的返回None
。
[!NOTE] save():保存
src()
方法获取到的资源到文件。path[str|Path]=None 文件保存路径,为None时保存到当前文件夹name=[str]=None 文件名称,需包含后缀,为None时从资源 url 获取timeout float None 等待资源加载超时时间,为None时使用元素所在页面timeout属性rename bool True 遇到重名文件时是否自动重命名
import ddddocrcode = page('#randCode_icon').src()ocr = ddddocr.DdddOcr(show_ad=False)res = ocr.classification(code)
ShadowRoot属性
📌 tag
📌 html
📌 inner_html
📌 page
📌 parent_ele
📌 states.is_enabled
📌 states.is_alive
比较元素
元素截图
用于获取验证码人机验证码
元素对象.get_screenshot()
:对元素进行截图。
若元素范围超出视口,需 90 以上版本内核支持。
下面三个参数三选一,优先级:as_bytes
>as_base64
>path
。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
path | str
| None | 保存图片的路径,为None 时保存在当前文件夹,包含文件名的完整路径,name 参数无效。 |
name | str | None | 完整文件名,后缀可选'jpg' 、'jpeg' 、'png' 、'webp' ,为None 时以用 jpg 格式 |
as_bytes | str
| None | 是否以字节形式返回图片,可选'jpg' 、'jpeg' 、'png' 、'webp' 、None 、True 不为 为 |
as_base64 | str
| None | 是否以 base64 形式返回图片,可选'jpg' 、'jpeg' 、'png' 、'webp' 、None 、True 不为 为 |
scroll_to_center | bool | True | 截图前是否滚动到视口中央 |
返回类型 | 说明 |
---|---|
bytes | as_bytes 生效时返回图片字节 |
str | as_bytes 和as_base64 为None 时返回图片完整路径 |
str | as_base64 生效时返回 base64 格式的字符串 |
保存元素
元素交互
点击
输入
input():用于向元素输入文本或组合键,也可用于输入文件路径到上传控件。可选择输入前是否清空元素。参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
vals | Any | False | 文本值或按键组合 对文件上传控件时输入路径字符串或其组成的列表 |
clear | bool | False | 输入前是否清空文本框 |
by_js | bool | False | 是否用 js 方式输入,为True 时不能输入组合键 |
元素的等待
📌 wait.displayed():等待元素从隐藏状态变成显示状态。元素隐藏是指元素在 DOM 内,但处于隐藏状态(即使在视口内且不被遮挡)。父元素隐藏时子元素也是隐藏的。📌 wait.hidden():等待元素从显示状态变成隐藏状态。📌 wait.deleted():等待元素被从 DOM 删除。📌 wait.covered():用于等待元素被其它元素覆盖。📌 wait.not_covered():用于等待元素不被其它元素覆盖。📌 wait.enabled():用于等待元素变为可用状态。📌 wait.disabled():用于等待元素变为不可用状态。📌 wait.stop_moving():用于等待元素运动结束。如果元素没有大小和位置信息,会在超时时抛出NoRectError异常。📌 wait.disable_or_deleted():用于等待元素变为不可用或被删除。📌 wait():此方法用于等待若干秒。 scope为None时,效果与time.sleep()没有区别,等待指定秒数。scope不为None时,获取两个参数之间的一个随机值,等待这个数值的秒数。例子
多线程并发
并发编程-py
当你有多个链接需要打开时,使用多线程并发多开标签页
from concurrent.futures import ThreadPoolExecutorwith ThreadPoolExecutor(max_workers=3) as executor: # 通过executor的 map 获取已经完成的task的值for data in executor.map(get_html, urls): print("get {} page".format(data))
坑
#坑
pyinstaller打包报错
ImportError: DLL load failed while importing _sqlite3: 找不到指定的模块。
python 内置了这个sqlite3.dll模块,而anaconda没有
把sqlite3.dll放到python环境中的DLLs目录下
C:\Users\wenke\.conda\envs\drission\DLLs
在pyinstaller的xxx.spec文件中添加DLLs目录
binaries=[('C:\\Users\\wenke\\.conda\\envs\\drission\\DLLs','.')],
pyinstaller main.spec
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。