3.0.27优化命名;增加set_main_tab();修改文档

This commit is contained in:
g1879 2023-01-02 23:03:50 +08:00
parent b00ebcb881
commit 6fedd57677
16 changed files with 1115 additions and 111 deletions

View File

@ -257,7 +257,7 @@ class ChromiumBase(BasePage):
@property
def page_load_strategy(self):
"""返回页面加载策略"""
"""返回页面加载策略有3种'none''normal''eager'"""
return self._page_load_strategy
@property
@ -292,7 +292,7 @@ class ChromiumBase(BasePage):
"""运行javascript代码 \n
:param script: js文本
:param as_expr: 是否作为表达式运行为True时args无效
:param args: 参数按顺序在js文本中对应argument[0]argument[2]...
:param args: 参数按顺序在js文本中对应argument[0]argument[1]...
:return: 运行的结果
"""
return run_script(self, script, as_expr, self.timeouts.script, args)
@ -301,7 +301,7 @@ class ChromiumBase(BasePage):
"""以异步方式执行js代码 \n
:param script: js文本
:param as_expr: 是否作为表达式运行为True时args无效
:param args: 参数按顺序在js文本中对应argument[0]argument[2]...
:param args: 参数按顺序在js文本中对应argument[0]argument[1]...
:return: None
"""
from threading import Thread
@ -664,7 +664,7 @@ class PageLoadStrategy(object):
"""
:param page: ChromiumBase对象
"""
self.page = page
self._page = page
def __call__(self, value):
"""设置加载策略 \n
@ -673,16 +673,16 @@ class PageLoadStrategy(object):
"""
if value.lower() not in ('normal', 'eager', 'none'):
raise ValueError("只能选择 'normal', 'eager', 'none'")
self.page._page_load_strategy = value
self._page._page_load_strategy = value
def normal(self):
"""设置页面加载策略为normal"""
self.page._page_load_strategy = 'normal'
self._page._page_load_strategy = 'normal'
def eager(self):
"""设置页面加载策略为eager"""
self.page._page_load_strategy = 'eager'
self._page._page_load_strategy = 'eager'
def none(self):
"""设置页面加载策略为none"""
self.page._page_load_strategy = 'none'
self._page._page_load_strategy = 'none'

View File

@ -199,7 +199,7 @@ class Timeout(object):
class PageLoadStrategy(object):
def __init__(self, page: ChromiumBase):
self.page: ChromiumBase = ...
self._page: ChromiumBase = ...
def __call__(self, value: str) -> None: ...

View File

@ -28,9 +28,6 @@ class ChromiumFrame(ChromiumBase):
obj_id = super().run_script('document;', as_expr=True)['objectId']
self.doc_ele = ChromiumElement(self, obj_id=obj_id)
self._tab_obj.Page.FrameAttached = self._onFrameAttached
self._tab_obj.Page.FrameDetached = self._onFrameDetached
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele2 = ele1('@id=ele_id') \n
@ -45,6 +42,21 @@ class ChromiumFrame(ChromiumBase):
attrs = [f"{attr}='{attrs[attr]}'" for attr in attrs]
return f'<ChromiumFrame {self.frame_ele.tag} {" ".join(attrs)}>'
# def _reload_document(self):
# self._frame_ele = ChromiumElement(self.page, backend_id=self._backend_id)
# node = self.page.run_cdp('DOM.describeNode', nodeId=self._frame_ele.node_id, not_change=True)['node']
#
# if self._is_inner_frame():
# self._is_diff_domain = False
# self.doc_ele = ChromiumElement(self.page, backend_id=node['contentDocument']['backendNodeId'])
# super().__init__(self.page.address, self.page.tab_id, self.page.timeout)
# else:
# self._is_diff_domain = True
# self._tab_obj.stop()
# super().__init__(self.page.address, self.frame_id, self.page.timeout)
# obj_id = super().run_script('document;', as_expr=True)['objectId']
# self.doc_ele = ChromiumElement(self, obj_id=obj_id)
def _get_new_document(self):
"""刷新cdp使用的document数据"""
if not self._is_reading:
@ -55,10 +67,11 @@ class ChromiumFrame(ChromiumBase):
while True:
try:
if self._is_inner_frame():
if self._is_diff_domain is False:
node = self.page.run_cdp('DOM.describeNode',
backendNodeId=self.backend_id, not_change=True)['node']
self.doc_ele = ChromiumElement(self.page, backend_id=node['contentDocument']['backendNodeId'])
else:
b_id = self._tab_obj.DOM.getDocument()['root']['backendNodeId']
self.doc_ele = ChromiumElement(self, backend_id=b_id)
@ -91,14 +104,6 @@ class ChromiumFrame(ChromiumBase):
print('页面停止加载 FrameStoppedLoading')
self._get_new_document()
def _onFrameAttached(self, **kwargs):
if self._debug:
print(f'FrameAttached{[kwargs]}')
def _onFrameDetached(self, **kwargs):
if self._debug:
print(f'FrameDetached{[kwargs]}')
@property
def tab_id(self):
"""返回当前标签页id"""
@ -204,9 +209,17 @@ class ChromiumFrame(ChromiumBase):
def ready_state(self):
"""返回当前页面加载状态,'loading' 'interactive' 'complete'"""
if self._is_diff_domain:
return super().ready_state
try:
return super().ready_state
except:
return 'complete'
else:
return self.doc_ele.run_script('return this.readyState;')
while True:
try:
return self.doc_ele.run_script('return this.readyState;')
except:
pass
def refresh(self):
"""刷新frame页面"""

View File

@ -75,7 +75,7 @@ class ChromiumPage(ChromiumBase):
self._init_page(tab_id)
self._get_document()
self._first_run = False
self.main_tab: str = self.tab_id
self._main_tab = self.tab_id
def _init_page(self, tab_id=None):
"""新建页面、页面刷新、切换标签页后要进行的cdp参数初始化
@ -100,10 +100,14 @@ class ChromiumPage(ChromiumBase):
@property
def tabs(self):
"""返回所有标签页id"""
"""返回所有标签页id组成的列表"""
tabs = self.run_cdp('Target.getTargets', filter=[{'type': "page"}])['targetInfos']
return [i['targetId'] for i in tabs]
@property
def main_tab(self):
return self._main_tab
@property
def process_id(self):
"""返回浏览器进程id"""
@ -116,7 +120,7 @@ class ChromiumPage(ChromiumBase):
def set_window(self):
"""返回用于设置窗口大小的对象"""
if not hasattr(self, '_window_setter'):
self._window_setter = WindowSizeSetter(self)
self._window_setter = WindowSetter(self)
return self._window_setter
def get_tab(self, tab_id=None):
@ -184,7 +188,7 @@ class ChromiumPage(ChromiumBase):
self._control_session.get(f'http://{self.address}/json/activate/{self.tab_id}')
def new_tab(self, url=None, switch_to=True):
"""新建并定位到一个标签页,该标签页在最后面 \n
"""新建一个标签页,该标签页在最后面 \n
:param url: 新标签页跳转到的网址
:param switch_to: 新建标签页后是否把焦点移过去
:return: None
@ -207,9 +211,16 @@ class ChromiumPage(ChromiumBase):
else:
self._control_session.get(f'http://{self.address}/json/new')
def set_main_tab(self, tab_id=None):
"""设置主tab \n
:param tab_id: 标签页id不传入则设置当前tab
:return: None
"""
self._main_tab = tab_id or self.tab_id
def to_main_tab(self):
"""跳转到主标签页"""
self.to_tab(self.main_tab)
self.to_tab(self._main_tab)
def to_tab(self, tab_id=None, activate=True):
"""跳转到标签页 \n
@ -228,7 +239,7 @@ class ChromiumPage(ChromiumBase):
"""
tabs = self.tabs
if not tab_id:
tab_id = self.main_tab
tab_id = self._main_tab
if tab_id not in tabs:
tab_id = tabs[0]
@ -273,8 +284,8 @@ class ChromiumPage(ChromiumBase):
while len(self.tabs) != end_len:
sleep(.1)
if self.main_tab in tabs:
self.main_tab = self.tabs[0]
if self._main_tab in tabs:
self._main_tab = self.tabs[0]
self.to_tab()
@ -350,7 +361,7 @@ class Alert(object):
self.response_text = None
class WindowSizeSetter(object):
class WindowSetter(object):
"""用于设置窗口大小的类"""
def __init__(self, page):
@ -373,7 +384,7 @@ class WindowSizeSetter(object):
"""设置窗口为常规模式"""
self._perform({'windowState': 'normal'})
def new_size(self, width=None, height=None):
def size(self, width=None, height=None):
"""设置窗口大小 \n
:param width: 窗口宽度
:param height: 窗口高度
@ -385,7 +396,7 @@ class WindowSizeSetter(object):
height = height or info['height']
self._perform({'width': width, 'height': height})
def to_location(self, x=None, y=None):
def location(self, x=None, y=None):
"""设置窗口在屏幕中的位置,相对左上角坐标 \n
:param x: 距离顶部距离
:param y: 距离左边距离

View File

@ -21,8 +21,8 @@ class ChromiumPage(ChromiumBase):
timeout: float = ...):
self.options: DriverOptions = ...
self.process: popen = ...
self._window_setter: WindowSizeSetter = ...
self.main_tab: str = ...
self._window_setter: WindowSetter = ...
self._main_tab: str = ...
self._alert: Alert = ...
def _connect_browser(self,
@ -39,11 +39,14 @@ class ChromiumPage(ChromiumBase):
@property
def tabs(self) -> List[str]: ...
@property
def main_tab(self) -> str: ...
@property
def process_id(self) -> Union[None, int]: ...
@property
def set_window(self) -> 'WindowSizeSetter': ...
def set_window(self) -> 'WindowSetter': ...
def get_tab(self, tab_id: str = ...) -> ChromiumTab: ...
@ -91,7 +94,7 @@ class Alert(object):
self.response_text: str = ...
class WindowSizeSetter(object):
class WindowSetter(object):
def __init__(self, page: ChromiumPage):
self.driver: ChromiumDriver = ...
@ -105,9 +108,9 @@ class WindowSizeSetter(object):
def normal(self) -> None: ...
def new_size(self, width: int = ..., height: int = ...) -> None: ...
def size(self, width: int = ..., height: int = ...) -> None: ...
def to_location(self, x: int = ..., y: int = ...) -> None: ...
def location(self, x: int = ..., y: int = ...) -> None: ...
def _get_info(self) -> dict: ...

View File

@ -198,10 +198,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return super(SessionPage, self).s_eles(loc_or_str)
def change_mode(self, mode=None, go=True, copy_cookies=True):
"""切换模式,接收's''d',除此以外的字符串会切换为 d 模式 \n
切换时会把当前模式的cookies复制到目标模式 \n
切换后如果go是True调用相应的get函数使访问的页面同步 \n
注意s转d时若浏览器当前网址域名和s模式不一样必须会跳转 \n
"""切换模式,接收's''d',除此以外的字符串会切换为 d 模式 \n
如copy_cookies为True切换时会把当前模式的cookies复制到目标模式 \n
切换后如果go是True调用相应的get函数使访问的页面同步 \n
:param mode: 模式字符串
:param go: 是否跳转到原模式的url
:param copy_cookies: 是否复制cookies到目标模式
@ -283,6 +282,12 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return cookies
def set_cookies(self, cookies, set_session=False, set_driver=False):
"""添加cookies信息到浏览器或session对象 \n
:param cookies: 可以接收`CookieJar``list``tuple``str``dict`格式的`cookies`
:param set_session: 是否设置到Session对象
:param set_driver: 是否设置到浏览器
:return: None
"""
# 添加cookie到driver
if set_driver:
cookies = cookies_to_tuple(cookies)

View File

@ -1,15 +1,49 @@
在入门指南的快速上手一节,我们已经初步了解如何创建页面对象,本节进一步介绍更多功能。
# ✔️ `WebPage`
常用的页面对象有 3 种:
- `WebPage`:整合 d 模式和 s 模式于一体的页面对象
- `ChromiumPage`:单纯用于操作浏览器的页面对象
- `SessionPage`:单纯用于收发数据包的页面对象
这 3 种页面对象的使用逻辑是一致的,使用时可根据实际须要选择使用。
# ✔️ 三种页面对象
## 📍 `WebPage`
`WebPage`对象封装了常用的网页操作,并实现在浏览器和 requests 两种模式之间的切换。
初始化参数:
**初始化参数:**
- mode初始化时模式`'d'``'s'`,默认为`'d'`
- timeout超时时间s 模式时为连接时间d 模式时为查找元素、处理弹出框、输入文本等超时时间
- driver_or_options`Tab`对象或`DriverOptions`对象,为`None`时使用 ini 文件配置,为`False`时不读取 ini 文件
- session_or_options`Session`对象或`SessionOptions`对象,为`None`时使用 ini 文件配置,为`False`时不读取 ini 文件
- `mode`:初始化时模式,`'d'``'s'`,默认为`'d'`
- `timeout`超时时间s 模式时为连接时间d 模式时为查找元素、处理弹出框、输入文本等超时时间
- `driver_or_options``ChromiumDriver`对象或`DriverOptions`对象,为`None`时使用 ini 文件配置,为`False`时不读取 ini 文件
- `session_or_options``Session`对象或`SessionOptions`对象,为`None`时使用 ini 文件配置,为`False`时不读取 ini 文件
## 📍 `ChromiumPage`
`ChroumiumPage`对象纯粹用于操作浏览器,不能切换模式。一个该对象对应的是浏览器上一个标签页。
**初始化参数:**
- `addr_driver_opts`:浏览器信息,可以是 '地址:端口'字符串、`ChromiumDriver`对象,或`DriverOptions`对象
- `tab_id`要控制的标签页id不指定默认为激活的
- `timeout`:总体超时时间
## 📍 `SessionPage`
`SessionPage`对象纯粹用于收发数据包,不能切换模式,产生的元素对象为`SessionElement`
**初始化参数:**
- `session_or_options``Session`对象或`SessionOptions`对象
- `timeout`:连接超时时间
# ✔️ 直接创建
@ -23,6 +57,12 @@ page = WebPage('d')
# 指定以 s 模式创建页面对象
page = WebPage('s')
# 用 ChroumiumPage 创建页面对象
page = ChromiumPage()
# 用 SessionPage 创建页面对象
page = SessionPage()
```
# ✔️ 通过配置信息创建
@ -50,6 +90,15 @@ do = DriverOptions().set_paths(chrome_path=r'D:\chrome.exe', local_port=9333)
page = WebPage(driver_or_options=do)
```
用 ChroumiumPage 创建页面对象
```python
page = ChromiumPage(addr_driver_opts=do)
# 也可以直接把要控制的浏览器地址写在参数里
page = ChromiumPage(addr_driver_opts='127.0.0.1:9333')
```
## 📍 `SessionOptions`
`SessionOptions`用于管理创建`Session`对象时的配置,内置了常用的配置,并能实现链式操作。详细使用方法见“启动配置”一节。
@ -74,6 +123,12 @@ so = SessionOptions(read_file=False).set_proxies(proxies)
page = WebPage(mode='s', session_or_options=so)
```
用 SessionPage 创建页面对象
```python
page = SessionPage(session_or_options=so)
```
d 模式的配置和 s 模式的配置是可以同时使用的,不会互相影响。
```python

View File

@ -10,15 +10,15 @@ d 模式下使用`get()`方法访问网页。
当连接失败时,程序默认重试 3 次,每次间隔 2 秒,可以通过参数设置重试次数和间隔。
d 模式下根据浏览器的状态,还可以通过重写`check_page()`方法实现自定义检查方式。
参数:
**参数:**
- url目标 url
- show_errmsg是否显示和抛出异常。默认不抛出连接错误会返回`None`
- retry重试次数与页面对象的设置一致默认 3 次
- interval重试间隔与页面对象的设置一致默认 2 秒
- timeout连接超时时间
- `url`:目标 url
- `show_errmsg`:是否显示和抛出异常。默认不抛出,连接错误会返回`None`
- `retry`:重试次数,与页面对象的设置一致,默认 3 次
- `interval`:重试间隔(秒),与页面对象的设置一致,默认 2 秒
- `timeout`:连接超时时间(秒)
返回:`bool`类型,表示是否连接成功
**返回:**`bool`类型,表示是否连接成功
```python
from DrissionPage import WebPage
@ -69,12 +69,12 @@ s 模式基于 requests因此可使用 requests 内置的所有请求方式
参数:
- url目标 url
- show_errmsg是否显示和抛出异常默认不抛出连接错误会返回 None
- retry重试次数与页面对象的设置一致默认 3 次
- interval重试间隔与页面对象的设置一致默认 2 秒
- timeout连接超时时间
- **kwargs连接参数具体见 requests用法
- `url`:目标 url
- `show_errmsg`:是否显示和抛出异常,默认不抛出,连接错误会返回`None`
- `retry`:重试次数,与页面对象的设置一致,默认 3 次
- `interval`:重试间隔(秒),与页面对象的设置一致,默认 2 秒
- `timeout`:连接超时时间(秒)
- `**kwargs`:连接参数,具体见 requests 用法
返回:`bool`类型,表示是否连接成功,根据`Response`对象的`status_code`参数决定
@ -107,13 +107,13 @@ page.get(url, headers=headers, cookies=cookies, proxies=proxies)
参数:
- url目标 url
- data提交的数据可以是`dict``str`类型
- json提交的数据可以是`dict``str`类型
- show_errmsg是否显示和抛出异常默认不抛出连接错误会返回 None
- retry重试次数与页面对象的设置一致默认 3 次
- interval重试间隔与页面对象的设置一致默认 2 秒
- **kwargs连接参数s 模式专
- `url`:目标 url
- `data`:提交的数据,可以是`dict``str`类型
- `json`:提交的数据,可以是`dict``str`类型
- `show_errmsg`:是否显示和抛出异常,默认不抛出,连接错误会返回`None`
- `retry`:重试次数,与页面对象的设置一致,默认 3 次
- `interval`:重试间隔(秒),与页面对象的设置一致,默认 2 秒
- `**kwargs`:连接参数,具体见 requests 用
```python
from DrissionPage import WebPage

View File

@ -1,12 +1,12 @@
获取到须要的页面元素后,可以使用元素对象获取元素的信息。
`WebPage`生成的元素对象有四种:
`WebPage`常用的元素对象有四种:
- `ChromiumElement`:浏览器一般元素
- `ChromiumShadowRootElement`shadow-root 元素
- `ChromiumFrame`s 模式产生的元素
- `ChromiumFrame`专门用于操作`<iframe>`元素的对象
- `SessionElement`s 模式的元素,或前 3 者转换而成的静态元素

View File

@ -299,9 +299,9 @@ ele.remove_attr('href')
**参数:**
- `script`js 文本
- `script`js 脚本文本
- `as_expr`:是否作为表达式运行,为`True``args`参数无效
- `*args`:传入 js 的参数按顺序在js文本中对应argument[0]、argument[1]...
- `*args`:传入 js 的参数按顺序在js文本中对应`argument[0]``argument[1]`...
**返回:** js 执行的结果
@ -317,13 +317,7 @@ height = ele.run_script('return this.offsetHeight;')
## 📍 `run_async_script()`
此方法用于以异步方式执行js代码代码中用`this`表示元素自己。
**参数:**
- `script`js 文本
- `as_expr`:是否作为表达式运行,为`True``args`参数无效
- `*args`:传入 js 的参数按顺序在js文本中对应argument[0]、argument[1]...
此方法用于以异步方式执行 js 代码,代码中用`this`表示元素自己。
**返回:**`None`
@ -334,18 +328,18 @@ height = ele.run_script('return this.offsetHeight;')
此属性用于以某种方式滚动元素中的滚动条。
调用此属性返回一个`ChromiumScroll`对象,调用该对象的方法实现各种方式的滚动。
| 方法 | 参数说明 | 功能 |
|:-----------------:|:------:|:----------------:|
| to_top() | 无 | 滚动到顶端,水平位置不变 |
| to_bottom() | 无 | 滚动到底端,水平位置不变 |
| to_half() | 无 | 滚动到垂直中间位置,水平位置不变 |
| to_rightmost() | 无 | 滚动到最右边,垂直位置不变 |
| to_leftmost() | 无 | 滚动到最左边,垂直位置不变 |
| to_location(x, y) | 滚动条坐标值 | 滚动到指定位置 |
| up(pixel) | 滚动的像素 | 向上滚动若干像素,水平位置不变 |
| down(pixel) | 滚动的像素 | 向下滚动若干像素,水平位置不变 |
| right(pixel) | 滚动的像素 | 向左滚动若干像素,垂直位置不变 |
| left(pixel) | 滚动的像素 | 向右滚动若干像素,垂直位置不变 |
| 方法 | 参数说明 | 功能 |
|:-------------------:|:------:|:----------------:|
| `to_top()` | 无 | 滚动到顶端,水平位置不变 |
| `to_bottom()` | 无 | 滚动到底端,水平位置不变 |
| `to_half()` | 无 | 滚动到垂直中间位置,水平位置不变 |
| `to_rightmost()` | 无 | 滚动到最右边,垂直位置不变 |
| `to_leftmost()` | 无 | 滚动到最左边,垂直位置不变 |
| `to_location(x, y)` | 滚动条坐标值 | 滚动到指定位置 |
| `up(pixel)` | 滚动的像素 | 向上滚动若干像素,水平位置不变 |
| `down(pixel)` | 滚动的像素 | 向下滚动若干像素,水平位置不变 |
| `right(pixel)` | 滚动的像素 | 向左滚动若干像素,垂直位置不变 |
| `left(pixel)` | 滚动的像素 | 向右滚动若干像素,垂直位置不变 |
```python
# 滚动到底部
@ -389,16 +383,16 @@ ele.select('text1') # 选中文本为 'text1' 的项目
## 📍 方法
| 方法 | 参数说明 | 功能 |
|:-------------------------------:|:-------:|:--------------:|
| by_text(text, timeout) | 文本,超时时间 | 根据文本选择项 |
| by_value(value, timeout) | 项值,超时时间 | 根据值选择项 |
| by_index(index, timeout) | 序号,超时时间 | 根据序号选择项0开始 |
| cancel_by_text(text, timeout) | 文本,超时时间 | 根据文本取消选择(多选列表) |
| cancel_by_value(value, timeout) | 项值,超时时间 | 根据项值取消选择(多选列表) |
| cancel_by_index(index, timeout) | 序号,超时时间 | 根据序号取消选择(多选列表) |
| invert() | 无 | 反选(多选列表) |
| clear() | 无 | 清空列表(多选列表) |
| 方法 | 参数说明 | 功能 |
|:---------------------------------:|:-------:|:--------------:|
| `by_text(text, timeout)` | 文本,超时时间 | 根据文本选择项 |
| `by_value(value, timeout)` | 项值,超时时间 | 根据值选择项 |
| `by_index(index, timeout)` | 序号,超时时间 | 根据序号选择项0开始 |
| `cancel_by_text(text, timeout)` | 文本,超时时间 | 根据文本取消选择(多选列表) |
| `cancel_by_value(value, timeout)` | 项值,超时时间 | 根据项值取消选择(多选列表) |
| `cancel_by_index(index, timeout)` | 序号,超时时间 | 根据序号取消选择(多选列表) |
| `invert()` | 无 | 反选(多选列表) |
| `clear()` | 无 | 清空列表(多选列表) |
```python
ele.select.by_text('text1') # 和 ele.select('text1') 一样
@ -415,12 +409,12 @@ ele.clear() # 清空
## 📍 属性
| 属性 | 说明 |
| ---------------- | --------------------- |
| is_multi | 返回是否多选表单 |
| options | 返回所有选项元素组成的列表 |
| selected_option | 返回第一个被选中的option元素 |
| selected_options | 返回所有被选中的option元素组成的列表 |
| 属性 | 说明 |
| ------------------ | --------------------- |
| `is_multi` | 返回是否多选表单 |
| `options` | 返回所有选项元素组成的列表 |
| `selected_option` | 返回第一个被选中的option元素 |
| `selected_options` | 返回所有被选中的option元素组成的列表 |
## 📍 多选

View File

@ -0,0 +1,224 @@
页面对象共有以下几种:
- `WebPage`:可在 s 和 d 模式之间切换,整合两种模式
- `ChromiumPage`:单纯用于操作浏览器,工作于 d 模式
- `ChromiumTab`:浏览器标签页对象,用于支持同时操作个多标签页
- `ChromiumFrame``<iframe>`元素对象,专门用于操作该元素
- `SessionPage`:单纯用于收发数据包,工作于 s 模式
各种页面对象使用方法是一致的,以下用`WebPage`按两种模式介绍。d 模式包含 s模式所有属性。
`ChromiumTab``ChromiumFrame`具体用法将在后面章节单独介绍。
# ✔️ 两种模式共有属性
## 📍 `url`
此属性返回当前访问的 url。
## 📍 `mode`
此属性返回当前页面对象的模式,`'s'``'d'`
## 📍 `cookies`
此属性以`dict`方式返回当前页面所使用的 cookies。
## 📍 `get_cookies()`
此方法获取 cookies 并以 cookie 组成的`list`形式返回。
**参数:**
- `as_dict`:是否以字典方式返回,为`False`返回 cookie 组成的`list`
- `all_domains`:是否返回所有域的 cookies只有 s 模式下生效
**返回:** cookies 信息
```python
from DrissionPage import WebPage
p = WebPage('s')
p.get('http://www.baidu.com')
p.get('http://gitee.com')
for i in p.get_cookies(as_dict=False, all_domains=True):
print(i)
```
输出:
```
{'domain': '.baidu.com', 'domain_specified': True, ......}
......
{'domain': 'gitee.com', 'domain_specified': False, ......}
......
```
## 📍 `html`
此属性返回当前页面 html 文本。
## 📍 `json`
此属性把请求内容解析成 json。
比如请求接口时,返回内容是 json 格式,那就可以用这个属性获取。
事实上,用 html 属性获取也是可以的,不过 html 属性没有对文本进行解析。
## 📍 `title`
此属性返回当前页面`title`文本。
## 📍 `timeout`
s 模式下,此属性代表网络请求超时时间。
d 模式下,此属性为元素查找、点击、处理提示框等操作的超时时间。
默认为 10可对其赋值。
```python
# 创建 MixPage 对象时指定
page = WebPage(timeout=5)
# 修改 timeout
page.timeout = 20
```
## 📍 `retry_times`
此参数为网络连接失败时的重试次数。默认为 3可对其赋值。
```python
# 修改重试次数
page.retry_times = 5
```
## 📍 `retry_interval`
此参数为网络连接失败时的重试等待间隔秒数。默认为 2可对其赋值。
```python
# 修改重试等待间隔时间
page.retry_interval = 1.5
```
## 📍 `url_available`
此属性以布尔值返回当前链接是否可用。
# ✔️ s 模式独有属性
## 📍 `session`
此属性返回当前页面对象使用的`Session`对象。
## 📍 `response`
此属性为 s 模式请求网站后生成的`Response`对象,本库没实现的功能可直接获取此属性调用 requests 库的原生功能。
```python
# 打印连接状态
r = page.response
print(r.status_code)
```
# ✔️ d 模式独有属性
## 📍 `tab_id`
此属性返回当前标签页的 id。
## 📍 `driver`
此属性返回当前页面对象使用的`ChromiumDriver`对象。
## 📍 `process_id`
此属性返回浏览器进程 id。
## 📍 `is_loading`
此属性返回页面是否正在加载状态。
## 📍 `ready_state`
此属性返回页面当前加载状态,有 3 种:`'loading'``'interactive'``'complete'`
## 📍 `page_load_strategy`
此属性返回页面加载策略,有 3 种:`'none'``'normal'``'eager'`
## 📍 `size`
此属性以`tuple`返回页面尺寸。格式:(宽度, 高度)。
## 📍 `timeouts`
此属性以字典方式返回三种超时时间。
`'implicit'`用于元素查找、点击重试、输入文本重试、处理弹出框重试等;
`'page_load'`用于等待页面加载;
`'script'`用于等待脚本执行。
```python
print(page.timeouts)
```
输出:
```
{'implicit': 10, 'pageLoad': 30.0, 'script': 30.0}
```
## 📍 `tabs_count`
此属性返回当前浏览器标签页数量。
## 📍 `tabs`
此属性以列表形式返回当前浏览器所有标签页 id。
## 📍 `get_screenshot()`
此方法用于对页面进行截图可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持。
**参数:**
- `path`:保存图片的完整路径,后缀可选`'jpg'``'jpeg'``'png'``'webp'`
- `as_bytes`:是否已字节形式返回图片,可选`'jpg'``'jpeg'``'png'``'webp'``None``True`
- `full_page`:是否整页截图,为`True`截取整个网页,为`False`截取可视窗口
- `left_top`:截取范围左上角坐标
- `right_bottom`:截取范围右下角角坐标
**返回:** 图片完整路径或字节文本
```python
# 对整页截图并保存
page.get_screenshot(path='D:\\page.png', full_page=True)
```
## 📍 `get_session_storage()`
此方法用于获取 sessionStorage 信息,可获取全部或单个项。
**参数:**
- `item`:要获取的项,不设置则返回全部
**返回:** sessionStorage 一个或所有项内容
## 📍 `get_local_storage()`
此方法用于获取 localStorage 信息,可获取全部或单个项。
**参数:**
- `item`:要获取的项,不设置则返回全部
**返回:** localStorage 一个或所有项内容

View File

@ -0,0 +1,529 @@
本节介绍`WebPage`对象可以使用的方法,有些方法是两种模式共有的,有些只有某种模式可以使用。当调用独有方法时,会自动切换到该模式。如调用`post()`方法时,会先切换到 s 模式,并同步登录信息。
# ✔️ 页面跳转
## 📍 `get()`
此方法用于跳转到一个 url两种模式都支持详细用法见“使用方法 -> 访问网页”章节。
**参数:**
- `url`:目标 url
- `show_errmsg`:是否显示和抛出异常,默认不抛出,连接错误会返回 `None`
- `retry`:重试次数,与页面对象的设置一致,默认 3 次
- `interval`:重试间隔(秒),与页面对象的设置一致,默认 2 秒
- `timeout`:连接超时时间(秒)
- `**kwargs`s 模式用到的连接参数,具体见 requests 用法
**返回:**`bool`类型,表示是否连接成功
```python
page.get('https://www.baidu.com')
```
## 📍 `post()`
此方法用于以 post 方式访问 url仅 s 模式支持。具体用法见“使用方法 -> 访问网页”章节。
参数:
- `url`:目标 url
- `data`:提交的数据,可以是`dict``str`类型
- `json`:提交的数据,可以是`dict``str`类型
- `show_errmsg`:是否显示和抛出异常,默认不抛出,连接错误会返回`None`
- `retry`:重试次数,与页面对象的设置一致,默认 3 次
- `interval`:重试间隔(秒),与页面对象的设置一致,默认 2 秒
- `**kwargs`:连接参数,具体见 requests 用法
返回:**`bool`类型,表示是否连接成功
```python
page.post('https://xxxxxx', data=data)
```
## 📍 `back()`
此方法用于在浏览历史中后退若干步d 模式独有。
**参数:**
- `steps`:后退步数
**返回:**`None`
```python
page.back(2) # 后退两个网页
```
## 📍 `forward()`
此方法用于在浏览历史中前进若干步d 模式独有。
**参数:**
- `steps`:前进步数
**返回:**`None`
```python
page.forward(2) # 前进两步
```
## 📍 `refresh()`
此方法用于刷新当前页面d 模式独有。
**参数:**
- `ignore_cache`:刷新时是否忽略缓存
**返回:**`None`
```python
page.refresh() # 刷新页面
```
## 📍 `stop_loading()`
此方法用于强制当前页面加载d 模式独有。
参数:无
返回:`None`
## 📍 `wait_loading()`
此方法用于等待页面进入加载状态d 模式独有。
我们经常会通过点击页面元素进入下一个网页,并立刻获取新页面的元素。但若跳转前的页面拥有和跳转后页面相同定位符的元素,会导致过早获取元素,跳转后失效的问题。使用此方法,会阻塞程序,等待页面开始加载后再继续,从而避免上述问题。
**参数:**
- `timeout`:超时时间
**返回:** 等待结束时是否进入加载状态
```python
ele.click() # 点击某个元素
page.wait_loading() # 等待页面进入加载状态
# 执行在新页面的操作
```
# ✔️切换页面模式
## 📍 `change_mode()`
此方法是`WebPage`用于切换模式的方法。
切换后默认在目标模式重新跳转到原模式所在 url。
参数:
- `mode`:目标模式字符串,`'s'``'d'`,默认转换到另一种
- `go`:转换后是否跳转到原模式所在 url
- `copy_cookies`是否复制cookies到目标模式
返回:`None`
以下例子演示用浏览器登录 gitee 网站,再切换到 s 模式。可见 s 模式依然处于登录状态。
```python
from DrissionPage import WebPage
# 创建页面对象,默认 d 模式
page = WebPage()
# 访问个人中心页面(未登录,重定向到登录页面)
page.get('https://gitee.com/profile')
# 打印当前模式和登录前的 title
print('当前模式:', page.mode)
print('登录前title', page.title, '\n')
# 使用 d 模式输入账号密码登录
page.ele('#user_login').input('your_user_name')
page.ele('#user_password').input('your_password\n')
page.wait_loading()
# 切换到 session 模式
page.change_mode()
# 打印当前模式和登录后的 title
print('当前模式:', page.mode)
print('登录后title', page.title)
```
输出:
```
当前模式d
登录前title 登录 - Gitee.com
当前模式s
登录后title 个人资料 - 码云 Gitee.com
```
# ✔️ 执行脚本或命令
## 📍 `run_script()`
此方法用于执行 js 脚本d 模式独有。
**参数:**
- `script`js 脚本文本
- `as_expr`:是否作为表达式运行,为`True``args`参数无效
- `*args`传入的参数按顺序在js文本中对应`argument[0]``argument[1]`...
**返回:** 脚本执行结果
```python
# 用传入参数的方式执行 js 脚本显示弹出框显示 Hello world!
page.run_script('alert(arguments[0]+arguments[1]);', 'Hello', ' world!')
```
## 📍 `run_async_script()`
此方法用于以异步方式执行 js 代码d 模式独有。
**参数:**
- `script`js 文本
- `as_expr`:是否作为表达式运行,为`True``args`参数无效
- `*args`:传入 js 的参数按顺序在js文本中对应`argument[0]``argument[1]`...
**返回:**`None`
## 📍 `run_cdp()`
此方法用于执行 Chrome DevTools Protocol 语句d 模式独有。cdp
用法详见[Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)。
**参数:**
- `cmd`:协议项目
- `**cmd_args`:项目参数
**返回:** 该语句返回的值
```python
# 停止页面加载
page.run_cdp('Page.stopLoading')
```
# ✔️ cookies 及缓存
## 📍 `set_cookies()`
此方法用于对浏览器或`Session`对象设置 cookies两种模式都支持。
可以接收`CookieJar``list``tuple``str``dict`格式的 cookies。
**参数:**
- `cookies`cookies 信息
- `set_session`:是否设置到`Session`对象
- `set_driver`:是否设置到浏览器
**返回:**`None`
```python
cookies = {'name': 'abc'}
page.set_cookies(cookies, set_session=True, set_driver=True)
```
## 📍 `cookies_to_session()`
此方法用于从浏览器复制 cookies 到`Session`对象。不会触发模式切换。
**参数:**
- `copy_user_agent`:是否同时复制 user agent 信息
**返回:**`None`
```python
page.cookies_to_session()
```
## 📍 `cookies_to_driver()`
此方法用于从`Session`对象复制 cookies 到浏览器。不会触发模式切换。
**参数:** 无
**返回:**`None`
## 📍 `set_session_storage()`
此方法用于设置或删除某项 sessionStorage 信息d 模式独有。
**参数:**
- `item`:要设置的项
- `value`:项的值,设置为`False`时,删除该项
**返回:**`None`
```python
page.set_session_storage(item='abc', value='123')
```
## 📍 `set_local_storage()`
此方法用于设置或删除某项 localStorage 信息d 模式独有。
**参数:**
- `item`:要设置的项
- `value`:项的值,设置为`False`时,删除该项
**返回:**`None`
## 📍 `clear_cache()`
此方法用于清除缓存可选要清除的项d 模式独有。
**参数:**
- `session_storage`:是否清除 sessionstorage
- `local_storage`:是否清除 localStorage
- `cache`:是否清除 cache
- `cookies`:是否清除 cookies
**返回:**`None`
```python
page.clear_cache(cookies=False) # 除了 cookies其它都清除
```
# ✔️ 各种设置
## 📍 `set_timeouts()`
此方法用于设置三种超时时间,单位为秒。可单独设置,为`None`表示不改变原来设置。
**参数:**
- `implicit`:查找元素超时时间
- `page_load`:页面加载超时时间
- `lscript`:脚本运行超时时间
**返回:**`None`
```python
page.set_timeouts(implicit=10, page_load=30)
```
## 📍 `set_page_load_strategy`
此属性用于设置页面加载策略d 模式独有。
页面加载策略有三种:
- `normal`:等待页面完全加载完成,为默认状态
- `eager`:等待文档加载完成就结束,不等待资源加载
- `none`:页面连接完成就结束
```python
page.set_page_load_strategy.eager()
```
## 📍 `set_ua_to_tab()`
此方法用于为浏览器当前标签页设置 user agent只在当前 tab 有效d 模式独有。
**参数:**
- `ua`user agent 字符串
**返回:**`None`
# ✔️ 窗口管理
## 📍 调整大小和位置
`set_window`属性返回一个`WindowSetter`对象用于执行改变窗口的各种方法d 模式独有。
| 方法 | 参数 | 说明 |
| --------------------- | ---- | ---- |
| `maximized()` | 无 | 最大化 |
| `minimized()` | 无 | 最小化 |
| `fullscreen()` | 无 | 全屏 |
| `normal()` | 无 | 常规 |
| `size(width, height)` | 宽,高 | 设置大小 |
| `location(x, y)` | 屏幕坐标 | 设置位置 |
```python
# 窗口最大化
page.set_window.maximized()
# 窗口全屏,即 F11
page.set_window.fullscreen()
# 恢复普通窗口
page.set_window.normal()
# 设置窗口大小
page.set_window.size(500, 500)
# 设置窗口位置
page.set_window.location(200, 200)
```
## 📍 隐藏和显示窗口
`hide_browser()``show_browser()`方法用于随时隐藏和显示浏览器窗口d 模式独有。
与 headless 模式不一样,这两个方法是直接隐藏和显示浏览器进程。在任务栏上也会消失。
只支持 Windows 系统,并且必须已安装 pypiwin32 库才可使用。
`hide_browser()`
**参数:** 无
返回:`None`
`show_browser()`
**参数:** 无
返回:`None`
```python
page.hide_browser()
```
**注意:**
- 浏览器隐藏后并没有关闭,下次运行程序还会接管已隐藏的浏览器
- 浏览器隐藏后,如果有新建标签页,会自行显示出来
# ✔️ 滚动页面
## 📍 `scroll`
此属性用于以某种方式滚动页面d 模式独有。
调用此属性返回一个`Scroll`对象,调用该对象方法实现各种方式的滚动。
| 方法 | 参数说明 | 功能 |
| ------------------- | ------ | ---------------- |
| `to_top()` | 无 | 滚动到顶端,水平位置不变 |
| `to_bottom()` | 无 | 滚动到底端,水平位置不变 |
| `to_half()` | 无 | 滚动到垂直中间位置,水平位置不变 |
| `to_rightmost()` | 无 | 滚动到最右边,垂直位置不变 |
| `to_leftmost()` | 无 | 滚动到最左边,垂直位置不变 |
| `to_location(x, y)` | 滚动条坐标值 | 滚动到指定位置 |
| `up(pixel)` | 滚动的像素 | 向上滚动若干像素,水平位置不变 |
| `down(pixel)` | 滚动的像素 | 向下滚动若干像素,水平位置不变 |
| `right(pixel)` | 滚动的像素 | 向左滚动若干像素,垂直位置不变 |
| `left(pixel)` | 滚动的像素 | 向右滚动若干像素,垂直位置不变 |
```python
# 页面滚动到底部
page.scroll.to_bottom()
# 页面滚动到最右边
page.scroll.to_rightmost()
# 页面向下滚动 200 像素
page.scroll.down(200)
# 滚动到指定位置
page.scroll.to_location(100, 300)
```
## 📍 `scroll_to_see()`
此方法用于滚动页面直到元素可见d 模式独有。
**参数:**
- `loc_or_ele`:元素的定位信息,可以是元素、定位符
**返回:**`None`
```python
# 滚动到某个已获取到的元素
ele = page.ele('tag:div')
page.scroll_to_see(ele)
# 滚动到按定位符查找到的元素
page.scroll_to_see('tag:div')
```
# ✔️ 处理弹出消息
## 📍 `handle_alert()`
此方法 用于处理提示框d 模式独有。
它能够设置等待时间,等待提示框出现才进行处理,若超时没等到提示框,返回`None`
它可只获取提示框文本而不处理提示框。
**参数:**
- `accept``True`表示确认,`False`表示取消,其它值不会按按钮但依然返回文本值
- `send`:处理 prompt 提示框时可输入文本
- `timeout`:等待提示框出现的超时时间
**返回:** 提示框内容文本,未等到提示框则返回`None`
```python
# 确认提示框并获取提示框文本
txt = page.handle_alert()
# 点击取消
page.handle_alert(accept=False)
# 给 prompt 提示框输入文本并点击确定
paeg.handle_alert(accept=True, send='some text')
# 不处理提示框,只获取提示框文本
txt = page.handle_alert(accept=None)
```
# ✔️ 关闭
## 📍 `close_driver()`
此方法用于关闭`WebPage`控制的浏览器,并切换到 s 模式。
**参数:** 无
**返回:**`None`
```python
page.close_driver()
```
## 📍 `close_session()`
此方法用于关闭`WebPage`控制的`Session`对象,并切换到 d 模式。
**参数:** 无
**返回:`**None`
```python
page.close_session()
```
## 📍`quit()`
此方法用于退出浏览器并且关闭 Session 对象。彻底关闭`WebPage`对象。
**参数:** 无
**返回:`**None`
```python
page.quit()
```

View File

@ -0,0 +1,167 @@
本节介绍对浏览器标签页的管理及使用技巧。
与 selenium 不同,`WebPage`能够用多个标签页对象同时操作多个标签页,而无须切入切出,并且,标签页无须在激活状态也可以控制。因此能够实现一些非常灵活的使用方式。
比如多线程分别独立控制标签页,或一个总标签页,控制多个从标签页,或者配合插件实现浏览器随时更换代理等。
`WebPage``ChromiumPage`对象为浏览器标签页总管,可以控制标签页的增删。`ChromiumTab`对象为独立的标签页对象,可控制每个标签页内的操作。
# ✔️ 标签页总览
## 📍 `tabs_count`
此属性返回标签页数量。
```python
print(page.tabs_count)
# 输出2
```
## 📍 `tabs`
此属性以`list`方式返回所有标签页 id。
```python
print(page.tabs)
# 输出:['0B300BEA6F1F1F4D5DE406872B79B1AD', 'B838E91F38121B32940B47E8AC59D015']
```
# ✔️ 新建标签页
## 📍 `new_tab()`
该方法用于新建一个标签页,该标签页在最后面。
**参数:**
- `url`:新标签页跳转到的网址,不传入则新建空标签页
- `switch_to`:新建标签页后是否把焦点移过去,默认为跳转
**返回:**`None`
```python
page.new_tab(url='https://www.baidu.com')
```
# ✔️ 关闭标签页
## 📍 `close_tabs()`
此方法用于关闭指定的标签页,可关闭多个。默认关闭当前的。
如果被关闭的标签页包含当前页,会跳转到剩下的第一个页面,但未必是视觉上第一个。
**参数:**
- `tab_ids`:要关闭的标签页 id可传入 id 组成的列表或元组,为`None`时关闭当前页
- `others`:是否关闭指定标签页之外的
返回:`None`
```python
# 关闭当前标签页
page.close_tabs()
# 关闭第1、3个标签页
tabs = page.tabs
page.close_tabs(tab_ids=(tabs[0], tabs[2]))
```
## 📍 `close_other_tabs()`
此方法用于关闭传入的标签页以外标签页,默认保留当前页。可传入多个。
如果被关闭的标签页包含当前页,会跳转到剩下的第一个页面,但未必是视觉上第一个。
**参数:**
- `tab_ids`:要保留的标签页 id可传入 id 组成的列表或元组,为`None`时保存当前页
**返回:**`None`
```python
# 关闭除当前标签页外的所有标签页
page.close_other_tabs()
# 关闭除第一个以外的标签页
page.close_other_tabs(page.tab[0])
# 关闭除 id 为 aaaaa 和 bbbbb 以外的标签页
reserve_list = ('aaaaa', 'bbbbb')
page.close_other_tabs(reserve_list)
```
# ✔️ 切换标签页
## 📍 `main_tab`
日常使用时,经常会用一个标签页作为主标签页,产生众多临时标签页去进行操作。因此我们可以为每个`WebPage``ChromiumPage`对象设置一个标签页为主标签页,方便随时切换。
默认接管浏览器时活动标签页则为主标签页。
```python
print(page.main_tab)
# 输出:'0B300BEA6F1F1F4D5DE406872B79B1AD'
```
## 📍 `set_main_tab()`
此方法用于设置某个标签页为主标签页。
**参数:**
- `tab_id`:要设置的标签页 id不传入则设置当前标签页为主
**返回:**`None`
```python
# 指定一个标签页为主标签页
page.set_main_tab(tab_id='0B300BEA6F1F1F4D5DE406872B79B1AD')
# 设置当前控制的标签页为主标签页
```
## 📍`to_main_tab()`
此方法用于把焦点定位到主标签页,使当前对象控制目标改为主标签页。
```python
page.to_main_tab()
```
## 📍 `to_tab()`
此方法把焦点定位到某个标签页,使当前对象控制目标改为该标签页。
**参数:**
- `tab_id`:标签页 id默认切换到主标签页
- `activate`:切换后是否变为活动状态
**返回:**`None`
```python
# 跳转到主标签页
page.to_tab()
# 跳转到第一个标签页
page.to_tab(page.tabs[0])
# 跳转到 id 为该字符串的标签页
page.to_tab('0B300BEA6F1F1F4D5DE406872B79B1AD')
```
## 📍 `to_front()`
此方法用于激活当前标签页使其处于最前面。标签页无须在活动状态程序也能操控。
**参数:** 无
**返回:**`None`
# ✔️ 多标签页协同
## 📍 获取标签页对象
# 未完待续

View File

@ -18,6 +18,9 @@
* [🔨 3.3 查找元素](WebPage使用方法\3.3查找元素.md)
* [🔨 3.4 获取元素信息](WebPage使用方法\3.4获取元素信息.md)
* [🔨 3.5 元素操作](WebPage使用方法\3.5元素操作.md)
* [🔨 3.6 获取网页信息](WebPage使用方法\3.6获取网页信息.md)
* [🔨 3.7 页面操作](WebPage使用方法\3.7页面操作.md)
* [🔨 3.8 标签页操作](WebPage使用方法\3.8标签页操作.md)
* [🛠 4 MixPage 使用方法](#)

View File

@ -1,4 +1,4 @@
# v3.0.26
# v3.0.27
- 各种大小、位置信息从`dict`改为用`tuple`返回

View File

@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
setup(
name="DrissionPage",
version="3.0.26",
version="3.0.27",
author="g1879",
author_email="g1879@qq.com",
description="A module that integrates selenium and requests session, encapsulates common page operations.",