mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
s模式get()使用page_load作为timeout;set_page_load_strategy改用类来表示;修改文档
This commit is contained in:
parent
d8f6487a05
commit
545ce2e2aa
@ -28,6 +28,7 @@ class ChromiumBase(BasePage):
|
||||
self._root_id = None
|
||||
self._debug = False
|
||||
self._debug_recorder = None
|
||||
self.timeouts = Timeout(self)
|
||||
self._connect_browser(address, tab_id)
|
||||
|
||||
def _connect_browser(self, addr_tab_opts=None, tab_id=None):
|
||||
@ -37,7 +38,6 @@ class ChromiumBase(BasePage):
|
||||
:return: None
|
||||
"""
|
||||
self._root_id = None
|
||||
self.timeouts = Timeout(self)
|
||||
self._control_session = Session()
|
||||
self._control_session.keep_alive = False
|
||||
self._first_run = True
|
||||
@ -256,14 +256,10 @@ class ChromiumBase(BasePage):
|
||||
self._scroll = ChromeScroll(self)
|
||||
return self._scroll
|
||||
|
||||
def set_page_load_strategy(self, value):
|
||||
"""设置页面加载策略 \n
|
||||
:param value: 可选'normal', 'eager', 'none'
|
||||
:return: None
|
||||
"""
|
||||
if value not in ('normal', 'eager', 'none'):
|
||||
raise ValueError("只能选择'normal', 'eager', 'none'。")
|
||||
self._page_load_strategy = value
|
||||
@property
|
||||
def set_page_load_strategy(self):
|
||||
"""返回用于设置页面加载策略的对象"""
|
||||
return pageLoadStrategy(self)
|
||||
|
||||
def set_timeouts(self, implicit=None, page_load=None, script=None):
|
||||
"""设置超时时间,单位为秒 \n
|
||||
@ -307,7 +303,7 @@ class ChromiumBase(BasePage):
|
||||
:param retry: 重试次数
|
||||
:param interval: 重试间隔(秒)
|
||||
:param timeout: 连接超时时间
|
||||
:return: 目标url是否可用,返回None表示不确定
|
||||
:return: 目标url是否可用
|
||||
"""
|
||||
self._url_available = self._get(url, show_errmsg, retry, interval, timeout)
|
||||
return self._url_available
|
||||
@ -810,3 +806,34 @@ class Timeout(object):
|
||||
@property
|
||||
def implicit(self):
|
||||
return self.page.timeout
|
||||
|
||||
|
||||
class pageLoadStrategy(object):
|
||||
"""用于设置页面加载策略的类"""
|
||||
|
||||
def __init__(self, page):
|
||||
"""
|
||||
:param page: ChromiumBase对象
|
||||
"""
|
||||
self.page = page
|
||||
|
||||
def __call__(self, value):
|
||||
"""设置加载策略 \n
|
||||
:param value: 可选 'normal', 'eager', 'none'
|
||||
:return: None
|
||||
"""
|
||||
if value.lower() not in ('normal', 'eager', 'none'):
|
||||
raise ValueError("只能选择 'normal', 'eager', 'none'。")
|
||||
self.page._page_load_strategy = value
|
||||
|
||||
def set_normal(self):
|
||||
"""设置页面加载策略为normal"""
|
||||
self.page._page_load_strategy = 'normal'
|
||||
|
||||
def set_eager(self):
|
||||
"""设置页面加载策略为eager"""
|
||||
self.page._page_load_strategy = 'eager'
|
||||
|
||||
def set_none(self):
|
||||
"""设置页面加载策略为none"""
|
||||
self.page._page_load_strategy = 'none'
|
||||
|
@ -101,7 +101,8 @@ class ChromiumBase(BasePage):
|
||||
@property
|
||||
def scroll(self) -> 'ChromeScroll': ...
|
||||
|
||||
def set_page_load_strategy(self, value: str) -> None: ...
|
||||
@property
|
||||
def set_page_load_strategy(self) -> pageLoadStrategy: ...
|
||||
|
||||
def set_timeouts(self, implicit: float = ..., page_load: float = ..., script: float = ...) -> None: ...
|
||||
|
||||
@ -279,3 +280,16 @@ class Timeout(object):
|
||||
|
||||
@property
|
||||
def implicit(self) -> float: ...
|
||||
|
||||
|
||||
class pageLoadStrategy(object):
|
||||
def __init__(self, page: ChromiumBase):
|
||||
self.page: ChromiumBase = ...
|
||||
|
||||
def __call__(self, value: str) -> None: ...
|
||||
|
||||
def set_normal(self) -> None: ...
|
||||
|
||||
def set_eager(self) -> None: ...
|
||||
|
||||
def set_none(self) -> None: ...
|
||||
|
@ -5,7 +5,7 @@ from requests import Session
|
||||
from tldextract import extract
|
||||
|
||||
from .base import BasePage
|
||||
from .chromium_base import ChromiumBase
|
||||
from .chromium_base import ChromiumBase, Timeout
|
||||
from .chromium_page import ChromiumPage
|
||||
from .config import DriverOptions, SessionOptions, cookies_to_tuple
|
||||
from .session_page import SessionPage
|
||||
@ -32,6 +32,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
self._session = None
|
||||
self._tab_obj = None
|
||||
self._is_loading = False
|
||||
self.timeouts = Timeout(self)
|
||||
self._set_session_options(session_or_options)
|
||||
self._set_driver_options(driver_or_options)
|
||||
self._setting_tab_id = tab_id
|
||||
@ -102,9 +103,6 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
if self._session is None:
|
||||
self._set_session(self._session_options)
|
||||
|
||||
# if self._proxy:
|
||||
# self._session.proxies = self._proxy
|
||||
|
||||
return self._session
|
||||
|
||||
@property
|
||||
@ -117,7 +115,6 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
"""返回用于控制浏览器的Tab对象,会先等待页面加载完毕"""
|
||||
while self._is_loading:
|
||||
sleep(.1)
|
||||
# self._wait_loading()
|
||||
return self._driver
|
||||
|
||||
@property
|
||||
@ -150,6 +147,8 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
if self._mode == 'd':
|
||||
return super(SessionPage, self).get(url, show_errmsg, retry, interval, timeout)
|
||||
elif self._mode == 's':
|
||||
if timeout is None:
|
||||
timeout = self.timeouts.page_load if self._has_driver else self.timeout
|
||||
return super().get(url, show_errmsg, retry, interval, timeout, **kwargs)
|
||||
|
||||
def ele(self, loc_or_ele, timeout=None):
|
||||
@ -291,7 +290,6 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
'name': cookie['name'],
|
||||
'domain': cookie['domain']}
|
||||
result_cookies.append(c)
|
||||
# super(WebPage, self)._wait_driver.Network.setCookies(cookies=result_cookies)
|
||||
self._tab_obj.Network.setCookies(cookies=result_cookies)
|
||||
|
||||
# 添加cookie到session
|
||||
|
@ -89,7 +89,8 @@ page = MixPage(mode='s', session_options=so, driver_options=do)
|
||||
|
||||
# 传入`Drission`对象创建
|
||||
|
||||
在入门指南的基本概念一节里,我们讲过`Drission`对象相当于驱动器的角色。事实上,上述两种方式,`MixPage`都会自动创建一个`Drission`对象用于管理与网站或浏览器的连接,我们当然也可以手动创建并传入`MixPage`。
|
||||
在入门指南的基本概念一节里,我们讲过`Drission`对象相当于驱动器的角色。事实上,上述两种方式,`MixPage`都会自动创建一个`Drission`对象用于管理与网站或浏览器的连接,我们当然也可以手动创建并传入`MixPage`
|
||||
。
|
||||
`Drission`一般是不用手动创建的,要手动创建的时候,一般是用于i以下几种情况:
|
||||
|
||||
- 指定使用某个配置文件
|
@ -10,11 +10,9 @@
|
||||
|
||||
由于该工具不依赖 DrissionPage,现已独立发布为一个库,但仍然可以在 DrissionPage 中导入。
|
||||
|
||||
|
||||
|
||||
!> 为了便于维护,该工具用法请异步 [FlowViewer](https://gitee.com/g1879/FlowViewer) 查看。
|
||||
|
||||
#
|
||||
#
|
||||
|
||||
# 简单示例
|
||||
|
@ -1,6 +1,7 @@
|
||||
获取到须要的页面元素后,可以使用元素对象获取元素的信息。
|
||||
|
||||
本库有三种元素对象,分别是`DriverElement`、`ShadowRootElement`、`SessionElement`,前两者是 d 模式下通过浏览器页面元素生成,后者由静态文本生成。`DriverElement`和`SessionElement`的基本属性一致。
|
||||
本库有三种元素对象,分别是`DriverElement`、`ShadowRootElement`、`SessionElement`,前两者是 d 模式下通过浏览器页面元素生成,后者由静态文本生成。`DriverElement`
|
||||
和`SessionElement`的基本属性一致。
|
||||
|
||||
`ShadowRootElement`由于是 shadow dom 元素,属性比较其余两种少,下文单独介绍。
|
||||
|
207
docs/WebPage使用方法/3.1创建页面对象.md
Normal file
207
docs/WebPage使用方法/3.1创建页面对象.md
Normal file
@ -0,0 +1,207 @@
|
||||
在入门指南的快速上手一节,我们已经初步了解如何创建页面对象,本节进一步介绍更多功能。
|
||||
|
||||
# ✔️ `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 文件
|
||||
|
||||
# ✔️ 直接创建
|
||||
|
||||
这种方式代码最简洁,程序会从配置文件中读取配置,自动生成页面对象。可以保持代码简洁。
|
||||
在基本概念一节我们提到过,本库使用配置文件记录常用配置信息,也可以直接把配置写在代码里。
|
||||
?>**Tips:**<br>默认配置文件中,程序使用 9222 端口启动浏览器,浏览器路径为 Chrome。如路径中没找到浏览器执行文件,Windows 系统下程序会在注册表中查找路径,如果还是没找到,则要用下一种方式手动配置路径。
|
||||
|
||||
```python
|
||||
# 默认以 d 模式创建页面对象
|
||||
page = WebPage('d')
|
||||
|
||||
# 指定以 s 模式创建页面对象
|
||||
page = WebPage('s')
|
||||
```
|
||||
|
||||
# ✔️ 通过配置信息创建
|
||||
|
||||
本库有两种管理配置信息的对象,`DriverOptions`和`SessionOptions`,分别对应 d 模式和 s 模式的配置。须要时,可以创建相应的配置对象进行设置。
|
||||
|
||||
## 📍 `DriverOptions`类
|
||||
|
||||
`DriverOptions`用于管理创建浏览器时的配置,内置了常用的配置,并能实现链式操作。详细使用方法见“启动配置”一节。
|
||||
|
||||
初始化参数:
|
||||
|
||||
- read_file:是否从 ini 文件中读取配置信息
|
||||
- ini_path:ini 文件路径,为`None`则读取默认 ini 文件
|
||||
|
||||
!>**注意:**<br>浏览器创建后再修改这个配置是没有效果的。
|
||||
|
||||
```python
|
||||
# 导入 DriverOptions
|
||||
from DrissionPage import WebPage, DriverOptions
|
||||
|
||||
# 创建浏览器配置对象,指定浏览器路径和运行端口
|
||||
do = DriverOptions().set_paths(chrome_path=r'D:\chrome.exe', local_port=9333)
|
||||
# 用该配置创建页面对象
|
||||
page = WebPage(driver_or_options=do)
|
||||
```
|
||||
|
||||
## 📍 `SessionOptions`类
|
||||
|
||||
`SessionOptions`用于管理创建`Session`对象时的配置,内置了常用的配置,并能实现链式操作。详细使用方法见“启动配置”一节。
|
||||
|
||||
初始化参数:
|
||||
|
||||
- read_file:是否从 ini 文件中读取配置信息
|
||||
- ini_path:ini 文件路径,为`None`则读取默认 ini 文件
|
||||
|
||||
!>**注意:**<br> `Session`对象创建后再修改这个配置是没有效果的。
|
||||
|
||||
```python
|
||||
# 导入 SessionOptions
|
||||
from DrissionPage import WebPage, SessionOptions
|
||||
|
||||
proxies = {'http': 'http://127.0.0.1:1080',
|
||||
'https': 'https://127.0.0.1:1080'}
|
||||
|
||||
# 创建配置对象,不从 ini 文件读取,并设置代理信息
|
||||
so = SessionOptions(read_file=False).set_proxies(proxies)
|
||||
# 用该配置创建页面对象(s 模式)
|
||||
page = WebPage(mode='s', session_options=so)
|
||||
```
|
||||
|
||||
d 模式的配置和 s 模式的配置是可以同时使用的,不会互相影响。
|
||||
|
||||
```python
|
||||
page = WebPage(mode='s', session_options=so, driver_options=do)
|
||||
```
|
||||
|
||||
## 📍 使用其它 ini 文件创建
|
||||
|
||||
以上方法是使用默认 ini 文件中保存的配置信息创建对象,你可以保存一个 ini 文件到别的地方,并在创建对象时指定使用它。
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage, DriverOptinos
|
||||
|
||||
do = DriverOptinos(ini_path=r'./config1.ini')
|
||||
page = WebPage(driver_or_options=do)
|
||||
```
|
||||
|
||||
# ✔️ 传递驱动器
|
||||
|
||||
当须要使用多个页面对象共同操作一个页面时,可在对象间传递驱动器。
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page1 = WebPage()
|
||||
driver = page1.driver
|
||||
session = page1.session
|
||||
page2 = WebPage(driver_or_options=driver, session_or_options=session)
|
||||
```
|
||||
|
||||
# ✔️ 接管手动打开的浏览器
|
||||
|
||||
如果须要手动打开浏览器再接管,可以这样做:
|
||||
|
||||
- 右键点击浏览器图标,选择属性
|
||||
|
||||
- 在“目标”路径后面加上` --remote-debugging-port=端口号`(注意最前面有个空格)
|
||||
|
||||
- 点击确定
|
||||
|
||||
- 在程序中的浏览器配置中指定接管该端口浏览器,如下:
|
||||
|
||||
```
|
||||
# 文件快捷方式的目标路径设置
|
||||
D:\chrome.exe --remote-debugging-port=9222
|
||||
```
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage, DriverOptions
|
||||
|
||||
do = DriverOptions().set_paths(local_port=9222)
|
||||
page = WebPage(driver_options=do)
|
||||
```
|
||||
|
||||
?>**Tips:**<br>接管使用 bat 文件打开的浏览器也是一样做法做法。<br>接管浏览器时只有`local_port`、`debugger_address`参数是有效的。
|
||||
|
||||
# ✔️ 多 Chrome 浏览器共存
|
||||
|
||||
如果想要同时操作多个 Chrome 浏览器,或者自己在使用 Chrome 上网,同时控制另外几个跑自动化,就须要给这些被程序控制的浏览器设置单独的端口和用户文件夹,否则会造成冲突。具体用`DriverOptions`对象进行设置,示例如下:
|
||||
|
||||
```python
|
||||
from DrissionPage import DriverOptions
|
||||
|
||||
do1 = DriverOptions().set_paths(local_port=9111, user_data_path=r'D:\data1')
|
||||
do2 = DriverOptions().set_paths(local_port=9222, user_data_path=r'D:\data2')
|
||||
|
||||
page1 = WebPage(driver_or_options=do1)
|
||||
page2 = WebPage(driver_or_options=do2)
|
||||
|
||||
page1.get('https://www.baidu.com')
|
||||
page2.get('http://www.163.com')
|
||||
```
|
||||
|
||||
如果要接管多个手动打开的浏览器,每个浏览器后面的参数都要添加`--remote-debugging-port`和`--user-data-dir`参数。示例如下:
|
||||
|
||||
```
|
||||
# 浏览器1目标设置
|
||||
D:\chrome.exe --remote-debugging-port=9111 --user-data-dir=D:\data1
|
||||
|
||||
# 浏览器2目标设置
|
||||
D:\chrome.exe --remote-debugging-port=9222 --user-data-dir=D:\data2
|
||||
```
|
||||
|
||||
```python
|
||||
from DrissionPage import DriverOptions
|
||||
|
||||
do1 = DriverOptions().set_paths(local_port=9111)
|
||||
do2 = DriverOptions().set_paths(local_port=9222)
|
||||
|
||||
page1 = WebPage(driver_or_options=do1)
|
||||
page2 = WebPage(driver_or_options=do2)
|
||||
```
|
||||
|
||||
?> **Tips:**<br>使用 bat 文件打开浏览器再接管操作是一样的。
|
||||
|
||||
# ✔️ 一些技巧
|
||||
|
||||
事实上,本库默认启动浏览器的方式是先通过程序在 9222(或用户指定的)端口运行一个浏览器进程,然后通过程序接管。这种做法有很多好处:
|
||||
|
||||
## 📍 可重复使用的浏览器对象
|
||||
|
||||
当程序运行完毕,浏览器不会主动关闭,下次再运行的时候可以直接在当前状态下继续运行。于是无须每次打开新的浏览器对象,无须从最开始步骤重新运行整个程序,一些前置条件(如登录)也无须每次运行,大大提高开发效率。
|
||||
|
||||
## 📍 简便的调试方式
|
||||
|
||||
通过重复使用浏览器对象,用户可以把浏览器页面调整到某个状态再用程序接管,对调试某个特定问题效率极高。比如有些通过很多步骤才能到达的页面,如果每次重新运行会花费大量时间,而将页面固定再由程序接管,测试各种细节非常方便快捷。
|
||||
|
||||
## 📍 一行代码传递登录状态到 requests
|
||||
|
||||
本库的一个特点是打通了浏览器和`requests`之间的登录状态,我们可以手动登录浏览器,再用程序接管,然后切换到 s 模式,这时 s 模式的`Session`对象即已活动浏览器的登录信息,无须用`requests`
|
||||
处理登录过程,极大地简化了开发复杂程度。示例:
|
||||
|
||||
```python
|
||||
# 假设已在 9222 端口打开了一个浏览器,并已登录某网站
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage() # 用 d 模式创建页面对象,默认接管 9222 端口
|
||||
page.change_mode() # 切换到 s 模式,即使用 requests 进行操作
|
||||
page.get('某url...') # 即可已登录状态访问
|
||||
```
|
||||
|
||||
使用其它端口号:
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage, DriverOptions
|
||||
|
||||
do = DriverOptions().set_paths(local_port=9333)
|
||||
page = WebPage(driver_option=do)
|
||||
page.change_mode()
|
||||
page.get('某url...')
|
||||
```
|
164
docs/WebPage使用方法/3.2访问网页.md
Normal file
164
docs/WebPage使用方法/3.2访问网页.md
Normal file
@ -0,0 +1,164 @@
|
||||
本节介绍如果访问网页。
|
||||
|
||||
# ✔️ d 模式
|
||||
|
||||
d 模式下使用`get()`方法访问网页。
|
||||
|
||||
## 📍 `get()`方法
|
||||
|
||||
该方法用于跳转到一个网址。
|
||||
当连接失败时,程序默认重试 3 次,每次间隔 2 秒,可以通过参数设置重试次数和间隔。
|
||||
d 模式下根据浏览器的状态,还可以通过重写`check_page()`方法实现自定义检查方式。
|
||||
|
||||
参数:
|
||||
|
||||
- url:目标 url
|
||||
- show_errmsg:是否显示和抛出异常。默认不抛出,连接错误会返回`None`
|
||||
- retry:重试次数,与页面对象的设置一致,默认 3 次
|
||||
- interval:重试间隔(秒),与页面对象的设置一致,默认 2 秒
|
||||
- timeout:连接超时时间(秒)
|
||||
|
||||
返回:`bool`类型,表示是否连接成功
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage()
|
||||
page.get('https://www.baidu.com')
|
||||
```
|
||||
|
||||
## 📍 设置超时时间和重试参数
|
||||
|
||||
网络不稳定的时候访问页面不一定成功,`get()`方法内置了超时和重试功能。通过`retry`、`interval`、`timeout`三个参数进行设置。
|
||||
其中,如不指定`timeout`参数,该参数会使用`WebPage`的`timeouts`属性的`page_load`参数中的值。
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage()
|
||||
page.get('https://www.163.com', retry=1, interval=1, timeout=1.5)
|
||||
```
|
||||
|
||||
## 📍 设置加载策略
|
||||
|
||||
通过设置`WebPage`对象的`page_load_strategy`属性,可设置页面停止加载的时机。页面加载时,在到达超时时间,或达到设定的状态,就会停止,可有效节省采集时间。有以下三种模式:
|
||||
|
||||
- `'normal'`:常规模式,会等待页面加载完毕。
|
||||
|
||||
- `'eager'`:加载完 DOM 即停止加载。
|
||||
|
||||
- `'none'`:完成连接即停止加载。
|
||||
|
||||
默认设置为`'normal'`。
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage()
|
||||
page.set_page_load_strategy.set_eager()
|
||||
```
|
||||
|
||||
# ✔️ s 模式
|
||||
|
||||
s 模式基于 requests,因此可使用 requests 内置的所有请求方式,包括`get()`、`post()`、`head()`、`options()`、`put()`、`patch()`、`delete()`
|
||||
。不过本库目前只对`get()`和`post()`做了封装和优化,其余方式可通过调用`WebPage`内置的`Session`对象使用。
|
||||
|
||||
## 📍 `get()`方法
|
||||
|
||||
`get()`方法使用语法与 requests 的`get()`方法一致,在此基础上增加了重试设置参数。
|
||||
|
||||
参数:
|
||||
|
||||
- url:目标 url
|
||||
- show_errmsg:是否显示和抛出异常,默认不抛出,连接错误会返回 None
|
||||
- retry:重试次数,与页面对象的设置一致,默认 3 次
|
||||
- interval:重试间隔(秒),与页面对象的设置一致,默认 2 秒
|
||||
- timeout:连接超时时间(秒)
|
||||
- **kwargs:连接参数,具体见 requests用法
|
||||
|
||||
返回:`bool`类型,表示是否连接成功,根据`Response`对象的`status_code`参数决定
|
||||
|
||||
s 模式的`**kwargs`参数与 requests 中该参数使用方法一致,但有一个特点,如果该参数中设置了某一项(如`headers`),该项中的每个项会覆盖从配置中读取的同名项,而不会整个覆盖。
|
||||
就是说,如果想继续使用配置中的`headers`信息,而只想修改其中一项,只需要传入该项的值即可。这样可以简化代码逻辑。
|
||||
与 requests 不一样,`get()`方法不返回`Response`对象以获取结果,处理返回结果的方式详见后面章节。
|
||||
|
||||
实用功能:
|
||||
|
||||
- 程序会根据要访问的网址自动在`headers`中加入`Host`和`Referer`项
|
||||
- 程序会自动从返回内容中确定编码,一般情况无须手动设置
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage('s')
|
||||
|
||||
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()`一致。调用时,`WebPage`对象会自动切换到 s 模式。
|
||||
|
||||
参数:
|
||||
|
||||
- url:目标 url
|
||||
- data:提交的数据,可以是`dict`或`str`类型
|
||||
- json:提交的数据,可以是`dict`或`str`类型
|
||||
- show_errmsg:是否显示和抛出异常,默认不抛出,连接错误会返回 None
|
||||
- retry:重试次数,与页面对象的设置一致,默认 3 次
|
||||
- interval:重试间隔(秒),与页面对象的设置一致,默认 2 秒
|
||||
- **kwargs:连接参数,s 模式专用
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage('s')
|
||||
data = {'username': 'xxxxx', 'pwd': 'xxxxx'}
|
||||
|
||||
page.post('http://example.com', data=data)
|
||||
# 或
|
||||
page.post('http://example.com', json=data)
|
||||
```
|
||||
|
||||
`data`参数和`json`参数都可接收`str`和`dict`格式数据,即有以下 4 种传递数据的方式:
|
||||
|
||||
```python
|
||||
# 向 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'})
|
||||
```
|
||||
|
||||
具体使用哪种,按服务器要求而定。
|
||||
|
||||
## 📍 其它请求方式
|
||||
|
||||
本库只针对常用的 get 和 post 方式作了优化,但也可以通过提取页面对象内的`Session`对象以原生 requests 代码方式执行其它请求方式。当然,它们工作在 s 模式。
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage('s')
|
||||
# 获取内置的 Session 对象
|
||||
session = page.session
|
||||
# 以 head 方式发送请求
|
||||
response = session.head('https://www.baidu.com')
|
||||
print(response.headers)
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```shell
|
||||
{'Accept-Ranges': 'bytes', 'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform', 'Connection': 'keep-alive', 'Content-Length': '277', 'Content-Type': 'text/html', 'Date': 'Tue, 04 Jan 2022 06:49:18 GMT', 'Etag': '"575e1f72-115"', 'Last-Modified': 'Mon, 13 Jun 2016 02:50:26 GMT', 'Pragma': 'no-cache', 'Server': 'bfe/1.0.8.18'}
|
||||
```
|
708
docs/WebPage使用方法/3.3查找元素.md
Normal file
708
docs/WebPage使用方法/3.3查找元素.md
Normal file
@ -0,0 +1,708 @@
|
||||
本节介绍如何获取元素对象。
|
||||
|
||||
无论是数据采集还是页面自动化,定位元素都是重中之重的的技能,浏览器开发者工具虽然可以直接复制绝对 xpath 或 css 路径,但这样做一来代码繁琐,可读性低,二来难以应付动态变化的页面。
|
||||
本库提供一套简洁易用的语法,用于快速定位元素,并且内置等待功能、支持链式查找,减少了代码的复杂性。
|
||||
|
||||
定位元素大致分为三种方法:
|
||||
|
||||
- 在页面或元素内查找子元素
|
||||
- 根据 DOM 结构相对定位
|
||||
- 根据页面布局位置相对定位
|
||||
|
||||
d 模式的元素还有专门用于处理 shadow dom 的`shadow_root`属性。获取到的元素可继续用这些方法获取后代元素,使用方法和普通元素一致。
|
||||
|
||||
# ✔️ 示例
|
||||
|
||||
## 📍 简单示例
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<div id="one">
|
||||
<p class="p_cls" name="row1">第一行</p>
|
||||
<p class="p_cls" name="row2">第二行</p>
|
||||
<p class="p_cls">第三行</p>
|
||||
</div>
|
||||
<div id="two">
|
||||
第二个div
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
假设 page 为以上页面的`WebPage`对象,我们可以用这些方法获取其中的元素:
|
||||
|
||||
```python
|
||||
# 获取 id 为 one 的元素
|
||||
div1 = page.ele('#one')
|
||||
|
||||
# 获取 div1 元素内所有 p 元素组成的列表
|
||||
p_eles = div1.eles('tag:p')
|
||||
|
||||
# 获取 name 属性为 row1 的元素
|
||||
p1 = page.ele('@name=row1')
|
||||
|
||||
# 获取 name 属性为 row2 且包含“第二”文本的 p 元素
|
||||
p_ele = page.ele('tag:p@@text():第二@@name=row2')
|
||||
|
||||
# 获取包含“第二个div”文本的元素
|
||||
div2 = page.ele('第二个div')
|
||||
|
||||
# 用 xpath 查找
|
||||
div2 = page.ele('xpath://div[@id="tow"]')
|
||||
|
||||
# 从第一行元素用相对定位获取第三行元素
|
||||
p3 = p1.next(2)
|
||||
|
||||
# 获取 p1 元素的父元素
|
||||
parent = p1.parent()
|
||||
|
||||
# 获取 p1 后面的第一个 div 元素
|
||||
div2 = p1.after(1, 'tag:div')
|
||||
```
|
||||
|
||||
## 📍 实际示例
|
||||
|
||||
复制此代码可直接运行查看结果。
|
||||
|
||||
```python
|
||||
from DrissionPage import WebPage
|
||||
|
||||
page = WebPage('s')
|
||||
page.get('https://gitee.com/explore')
|
||||
|
||||
# 获取包含“全部推荐项目”文本的 ul 元素
|
||||
ul_ele = page.ele('tag:ul@@text():全部推荐项目')
|
||||
|
||||
# 获取该 ul 元素下所有 a 元素
|
||||
titles = ul_ele.eles('tag:a')
|
||||
|
||||
# 遍历列表,打印每个 a 元素的文本
|
||||
for i in titles:
|
||||
print(i.text)
|
||||
|
||||
"""输出:
|
||||
全部推荐项目
|
||||
前沿技术
|
||||
智能硬件
|
||||
IOT/物联网/边缘计算
|
||||
车载应用
|
||||
以下省略……
|
||||
"""
|
||||
```
|
||||
|
||||
# ✔️ 查找元素方法
|
||||
|
||||
以下方法,既可用于在页面中查找元素,也可用于在元素中查找子元素。
|
||||
|
||||
## ele()
|
||||
|
||||
此方法用于查找并返回第一个匹配的元素,d 模式下返回`ChromiumElement`,s 模式下返回`SessionElement`,用 xpath 获取元素属性时,直接返回属性文本。查找不到结果则返回`None`。
|
||||
|
||||
参数:
|
||||
|
||||
- loc_or_str(元素对象拥有):元素的定位信息,可以是 loc 元组,或查询字符串
|
||||
- loc_or_ele(页面对象拥有):元素的定位信息,可以是元素对象,loc 元组,或查询字符串
|
||||
- timeout:查找元素超时时间,默认与元素所在页面等待时间一致,s 模式下无效
|
||||
|
||||
返回:s 模式下返回`SessionElement`,d 模式下返回`DriverElement`,或用 xpath 获取到的属性值
|
||||
|
||||
```python
|
||||
# 在页面内查找元素
|
||||
ele1 = page.ele('search text')
|
||||
|
||||
# 在元素内查找后代元素
|
||||
ele2 = ele1.ele('search text')
|
||||
|
||||
|
||||
# 使用 xpath 获取后代中第一个 div 元素的 class 属性
|
||||
class = ele1.ele('xpath://div/@class')
|
||||
```
|
||||
|
||||
## eles()
|
||||
|
||||
此方法与`ele()`相似,但返回的是匹配到的所有元素组成的列表,用 xpath 获取元素属性时,返回属性文本组成的列表。
|
||||
|
||||
参数:
|
||||
|
||||
- loc_or_str:元素的定位信息,可以是 loc 元组,或查询字符串
|
||||
- timeout:查找元素超时时间,默认与元素所在页面等待时间一致,s 模式下无效
|
||||
|
||||
返回:s 模式下返回`SessionElement`组成的列表,d 模式下返回`DriverElement`组成的列表,或用 xpath 获取到的属性值组成的列表
|
||||
|
||||
```python
|
||||
# 获取 ele 元素内的所有 p 元素
|
||||
p_eles = ele.eles('tag:p')
|
||||
# 打印第一个 p 元素
|
||||
print(p_eles[0])
|
||||
```
|
||||
|
||||
## s_ele()
|
||||
|
||||
此方法用于在一个元素下查找后代元素,以`SessionElement`形式返回结果(xpath 获取属性值时依然是返回`str`),也可以直接将一个元素或页面转换为`SessionElement`版本。
|
||||
|
||||
这是为了 d 模式处理速度的提升,当爬取复杂页面信息而且不须要和元素进行交互时,生成整个页面或者主要容器元素的`SessionElement`,再在其中获取信息,可以将速度提升几个数量级。
|
||||
|
||||
s 模式下这个方法和`ele()`是一样的。
|
||||
|
||||
参数:
|
||||
|
||||
- loc_or_str(元素对象拥有):元素的定位信息,可以是 loc 元组,或查询字符串。为`None`时直接返回当前元素的`SessionElemnet`版本
|
||||
- loc_or_ele(页面对象拥有):元素的定位信息,可以是 loc 元组,或查询字符串。为`None`时直接返回当前页面的 `SessionElemnet`版本
|
||||
|
||||
返回:`SessionElement`,或用 xpath 获取到的属性值
|
||||
|
||||
```python
|
||||
# 获取元素或页面的的 SessionElement 版本
|
||||
ele2 = ele1.s_ele()
|
||||
ele2 = page.s_ele()
|
||||
|
||||
# 在 ele1 元素下查找元素,并以 SessionElemnet 返回
|
||||
ele2 = ele1.s_ele('search text')
|
||||
|
||||
# 在页面下查找元素,并以 SessionElemnet 返回
|
||||
ele = page.s_ele('search text')
|
||||
```
|
||||
|
||||
## s_eles()
|
||||
|
||||
此方法与`s_ele()`相似,但返回的是匹配到的所有元素组成的列表,或属性值组成的列表。
|
||||
|
||||
参数:
|
||||
|
||||
- loc_or_str:元素的定位信息,可以是 loc 元组,或查询字符串(必填)
|
||||
|
||||
返回:`SessionElement`组成的列表,或用 xpath 获取到的属性值组成的列表
|
||||
|
||||
## active_ele
|
||||
|
||||
该属性返回当前页面焦点所在元素。d 模式独有。
|
||||
|
||||
```python
|
||||
ele = page.active_ele
|
||||
```
|
||||
|
||||
## shadow_root
|
||||
|
||||
`DriverElement`元素除了以上方法和属性外,还有`shadow_root`属性,用于获取其内部的 shadow_root 元素。
|
||||
该属性返回的是一个`ShadowRootElement`,类似于`DriverElement`,功能比`DriverElement`少。但也有`ele()`和`eles()`方法,可直接搜索其下的元素,返回 `DriverElement`
|
||||
元素。返回的`DriverElement`和普通的没有区别。
|
||||
|
||||
```python
|
||||
# 获取一个元素下是 shadow root
|
||||
shadow_ele = ele.shadow_root
|
||||
# 获取该 shadow root 下的一个元素
|
||||
ele1 = shadow_ele.ele('search text')
|
||||
# 点击获取到的元素
|
||||
ele1.click()
|
||||
```
|
||||
|
||||
# ✔️ 查找语法
|
||||
|
||||
我们使用一套简洁高效的语法去定位元素,大大简化了定位元素的代码量,增强了功能,也兼容 css selector、xpath、selenium 原生的 loc 元组(s 模式也能用)。d 模式和 s
|
||||
模式定位元素的语法是完全一样的,便于模式切换时平滑过渡。
|
||||
|
||||
**匹配模式** 指字符串是否完全匹配,有以下两种:
|
||||
|
||||
## 📍 精确匹配符`=`
|
||||
|
||||
表示精确匹配,匹配完全符合的文本或属性。
|
||||
|
||||
## 📍 模糊匹配符`:`
|
||||
|
||||
表示模糊匹配,匹配含有某个字符串的文本或属性。
|
||||
|
||||
**关键字** 是出现在定位语句最左边,用于指明该语句以哪种方式去查找元素,有以下这些:
|
||||
|
||||
## 📍 id 匹配符`#`
|
||||
|
||||
表示`id`属性,只在语句最前面且单独使用时生效,可配合`=`或`:`。
|
||||
|
||||
```python
|
||||
# 在页面中查找 id 属性为 ele_id 的元素
|
||||
ele1 = page.ele('#ele_id')
|
||||
|
||||
# 在 ele1 元素内查找 id 属性包含 ele_id 文本的元素
|
||||
ele2 = ele1.ele('#:ele_id')
|
||||
```
|
||||
|
||||
## 📍 class 匹配符`.`
|
||||
|
||||
表示`class`属性,只在语句最前面且单独使用时生效,可配合`=`或`:`。
|
||||
|
||||
```python
|
||||
# 查找 class 属性为 ele_class 的元素
|
||||
ele2 = ele1.ele('.ele_class')
|
||||
|
||||
# 查找 class 属性包含 ele_class 文本的元素
|
||||
ele2 = ele1.ele('.:ele_class')
|
||||
```
|
||||
|
||||
## 📍 单属性匹配符 `@`
|
||||
|
||||
表示某个属性,只匹配一个属性。
|
||||
`@`关键字只有一个简单功能,就是匹配`@`后面的内容,不再对后面的字符串进行解析。因此即使后面的字符串也存在`@`或`@@`,也作为要匹配的内容对待。
|
||||
|
||||
!> **注意:**
|
||||
如果属性中包含特殊字符,如包含`@`,用这个方式不能正确匹配到,须使用 css selector 方式查找。且特殊字符要用`\`转义。
|
||||
|
||||
```python
|
||||
# 查找 name 属性为 ele_name 的元素
|
||||
ele2 = ele1.ele('@name=ele_name')
|
||||
|
||||
# 查找 name 属性包含 ele_name 文本的元素
|
||||
ele2 = ele1.ele('@name:ele_name')
|
||||
|
||||
# 查找有 name 属性的元素
|
||||
ele2 = ele1.ele('@name')
|
||||
|
||||
# 查找没有任何属性的元素
|
||||
ele2 = ele1.ele('@')
|
||||
|
||||
# 查找 emaile 属性为 abc@def.com 的元素,有多个 @ 也不会重复处理
|
||||
ele2 = ele1.ele('@email=abc@def.com')
|
||||
|
||||
# 属性中有特殊字符的情形,匹配abc@def属性等于v的元素
|
||||
ele2 = ele1.ele('css:div[abc\@def="v"]')
|
||||
```
|
||||
|
||||
## 📍 多属性匹配符`@@`
|
||||
|
||||
表示某个属性,多属性匹配时使用,个数不限。还能匹配要忽略的元素,匹配文本时也和`@`不一样。
|
||||
`@@`后跟 - 时,表示 not。如:
|
||||
|
||||
- `@@-name`表示匹配没有`name`属性的元素
|
||||
|
||||
- `@@-name=ele_name`表示匹配`name`属性不为`ele_name`的元素
|
||||
|
||||
如有以下情况,不能使用此方式,须改用 xpath 的方式:
|
||||
|
||||
- 匹配文本或属性中出现`@@`
|
||||
|
||||
- 属性名本身以`-`开头
|
||||
|
||||
!> **注意:**
|
||||
如果属性中包含特殊字符,如包含`@`,用这个方式不能正确匹配到,须使用 css selector 方式查找。且特殊字符要用`\`转义。
|
||||
|
||||
```python
|
||||
# 查找 name 属性为 name 且 class 属性包含 cls 文本的元素
|
||||
ele2 = ele1.ele('@@name=name@@class:cls')
|
||||
|
||||
# 查找没有 class 属性的元素
|
||||
ele2 = ele1.ele('@@-class')
|
||||
|
||||
# 查找 name 属性不包含 ele_name 的元素
|
||||
ele2 = ele1.ele('@@-name:ele_name')
|
||||
```
|
||||
|
||||
## 📍 文本匹配符`text`
|
||||
|
||||
要匹配的文本,查询字符串如开头没有任何关键字,也表示根据传入的文本作模糊查找。
|
||||
如果元素内有多个直接的文本节点,精确查找时可匹配所有文本节点拼成的字符串,模糊查找时可匹配每个文本节点。
|
||||
|
||||
```python
|
||||
# 查找文本为 some text 的元素
|
||||
ele2 = ele1.ele('text=some text')
|
||||
|
||||
# 查找文本包含 some text 的元素
|
||||
ele2 = ele1.ele('text:some text')
|
||||
|
||||
# 与上一行一致
|
||||
ele2 = ele1.ele('some text')
|
||||
```
|
||||
|
||||
?> **Tips:** <br>若要查找的文本包含`text:` ,可下面这样写,即第一个`text:` 为关键字,第二个是要查找的内容:
|
||||
|
||||
```python
|
||||
ele2 = page.ele('text:text:')
|
||||
```
|
||||
|
||||
## 📍 文本匹配符`text()`
|
||||
|
||||
作为查找属性时使用的文本关键字,必须与`@`或`@@`配合使用。
|
||||
与`@`配合和与`@@`配合使用时,`text()`的意义是有差别的。
|
||||
|
||||
`@text()`表示在元素的直接子文本节点中匹配,且多个节点不能合并匹配。 `@@text()`表示在元素内部所有文本中匹配,且会把元素内部所有文本拼成一个总字符串再进行匹配,因此可以模糊匹配元素里面任意文本。
|
||||
|
||||
```python
|
||||
# 查找文本为 some text 的元素
|
||||
ele2 = ele1.ele('@text()=some text')
|
||||
|
||||
# 查找文本包含 some text 的元素
|
||||
ele2 = ele1.ele('@text():some text')
|
||||
|
||||
# 查找文本为 some text 且 class 属性为 cls 的元素
|
||||
ele2 = ele1.ele('@@text()=some text@@class=cls')
|
||||
|
||||
# 查找文本为 some text 且没有任何属性的元素(因第一个 @@ 后为空)
|
||||
ele2 = ele1.ele('@@@@text():some text')
|
||||
|
||||
# 查找直接子文本包含 some text 字符串的元素,和 text 关键字没有区别
|
||||
ele = page.ele('@text():some text')
|
||||
ele = page.ele('text:some text')
|
||||
|
||||
# 查找元素内部包含 some text 字符串的元素
|
||||
ele = page.ele('@@text():some text')
|
||||
```
|
||||
|
||||
## 📍 类型匹配符`tag`
|
||||
|
||||
表示元素的标签,只在语句最前面且单独使用时生效,可与`@`或`@@`配合使用。`tag:`与`tag=`效果一致。
|
||||
|
||||
```python
|
||||
# 定位 div 元素
|
||||
ele2 = ele1.ele('tag:div')
|
||||
|
||||
# 定位 class 属性为 cls 的 div 元素
|
||||
ele2 = ele1.ele('tag:div@class=cls')
|
||||
|
||||
# 定位文本为 text 的 div 元素
|
||||
ele2 = ele1.ele('tag:div@text()=text')
|
||||
|
||||
# 定位 class 属性为 cls 且文本为 text 的 div 元素
|
||||
ele2 = ele1.ele('tag:div@@class=cls@@text()=text')
|
||||
|
||||
# 查找直接文本节点包含 text 字符串的 div 元素
|
||||
ele2 = ele1.ele('tag:div@text():text')
|
||||
|
||||
# 查找内部文本节点包含 text 字符串的 div 元素
|
||||
ele2 = ele1.ele('tag:div@@text():text')
|
||||
```
|
||||
|
||||
?> **Tips:** <br>
|
||||
注意, `tag:div@text():text` 和 `tag:div@@text():text` 是有区别的,前者只在`div`的直接文本节点搜索,后者搜索`div`的整个内部。
|
||||
|
||||
## 📍 css selector 匹配符`css`
|
||||
|
||||
表示用 css selector 方式查找元素。`css:`与`css=`效果一致。
|
||||
|
||||
```python
|
||||
# 查找 div 元素
|
||||
ele2 = ele1.ele('css:.div')
|
||||
|
||||
# 查找 div 子元素元素,这个写法是本库特有,原生不支持
|
||||
ele2 = ele1.ele('css:>div')
|
||||
```
|
||||
|
||||
## 📍 xpath 匹配符`xpath`
|
||||
|
||||
表示用 xpath 方式查找元素。`xpath:`与`xpath=`效果一致。
|
||||
该方法支持完整的 xpath 语法,能使用 xpath 直接获取元素属性,selenium 不支持这种用法。
|
||||
|
||||
```python
|
||||
# 查找 div 元素
|
||||
ele2 = ele1.ele('xpath:.//div')
|
||||
|
||||
# 和上面一行一样,查找元素的后代时,// 前面的 . 可以省略
|
||||
ele2 = ele1.ele('xpath://div')
|
||||
|
||||
# 获取 div 元素的 class 属性,返回字符串
|
||||
txt = ele1.ele('xpath://div/@class')
|
||||
```
|
||||
|
||||
?> **Tips:** <br>
|
||||
查找元素的后代时,selenium 原生代码要求 xpath 前面必须加`.`,否则会变成在全个页面中查找。笔者觉得这个设计是画蛇添足,既然已经通过元素查找了,自然应该只查找这个元素内部的元素。所以,用 xpath
|
||||
在元素下查找时,最前面`//`或`/`前面的`.`可以省略。
|
||||
|
||||
## 📍 selenium 的 loc 元组
|
||||
|
||||
查找方法能直接接收 selenium 原生定位元组进行查找,s 模式下也支持这种写法。
|
||||
|
||||
```python
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
# 查找 id 为 ele_id 的元素
|
||||
loc1 = (By.ID, 'ele_id')
|
||||
ele = page.ele(loc1)
|
||||
|
||||
# 按 xpath 查找
|
||||
loc2 = (By.XPATH, '//div[@class="ele_class"]'
|
||||
ele = page.ele(loc2)
|
||||
```
|
||||
|
||||
# ✔️ 等待
|
||||
|
||||
d 模式下所有查找元素操作都自带等待,默认为跟随元素所在页面`timeout`属性(默认 10 秒),也可以在每次查找时单独设置,单独设置的等待时间不会改变页面原来设置。
|
||||
|
||||
```python
|
||||
# 页面初始化时设置查找元素超时时间为 15 秒
|
||||
page = MixPage(timeout=15)
|
||||
# 设置查找元素超时时间为 5 秒
|
||||
page.timeout = 5
|
||||
|
||||
# 使用页面超时时间来查找元素(5 秒)
|
||||
ele1 = page.ele('some text')
|
||||
# 为这次查找页面独立设置等待时间(1 秒)
|
||||
ele1 = page.ele('some text', timeout=1)
|
||||
# 查找后代元素,使用页面超时时间(5 秒)
|
||||
ele2 = ele1.ele('some text')
|
||||
# 查找后代元素,使用单独设置的超时时间(1 秒)
|
||||
ele2 = ele1.ele('some text', timeout=1)
|
||||
```
|
||||
|
||||
# ✔️ 相对定位
|
||||
|
||||
以下方法可以以某元素为基准,在 DOM 中按照条件获取其兄弟元素、祖先元素、文档前后元素。
|
||||
除获取元素外,还能通过 xpath 获取任意节点内容,如文本节点、注释节点。这在处理元素和文本节点混排的时候非常有用。
|
||||
|
||||
## parent()
|
||||
|
||||
此方法获取当前元素某一级父元素,可指定筛选条件或层数。
|
||||
|
||||
参数:
|
||||
|
||||
- level_or_loc:第几级父元素,或定位符
|
||||
|
||||
返回:
|
||||
|
||||
```python
|
||||
# 获取 ele1 的第二层父元素
|
||||
ele2 = ele1.parent(2)
|
||||
|
||||
# 获取 ele1 父元素中 id 为 id1 的元素
|
||||
ele2 = ele1.parent('#id1')
|
||||
```
|
||||
|
||||
## next()
|
||||
|
||||
此方法返回当前元素后面的某一个兄弟元素,可指定筛选条件和第几个。
|
||||
|
||||
参数:
|
||||
|
||||
- index:查询结果中的第几个
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素后面某个兄弟元素或节点文本
|
||||
|
||||
```python
|
||||
# 获取 ele1 后面第一个兄弟元素
|
||||
ele2 = ele1.next()
|
||||
|
||||
# 获取 ele1 后面第 3 个兄弟元素
|
||||
ele2 = ele1.next(3)
|
||||
|
||||
# 获取 ele1 后面第 3 个 div 兄弟元素
|
||||
ele2 = ele1.next(3, 'tag:div')
|
||||
|
||||
# 获取 ele1 后面第一个文本节点的文本
|
||||
txt = ele1.next(1, 'xpath:text()')
|
||||
```
|
||||
|
||||
## nexts()
|
||||
|
||||
此方法返回后面全部符合条件的兄弟元素或节点组成的列表,可用查询语法筛选。
|
||||
|
||||
参数:
|
||||
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素前面符合条件的兄弟元素或节点文本组成的列表
|
||||
|
||||
```python
|
||||
# 获取 ele1 后面所有兄弟元素
|
||||
eles = ele1.nexts()
|
||||
|
||||
# 获取 ele1 后面所有 div 兄弟元素
|
||||
divs = ele1.nexts('tag:div')
|
||||
|
||||
# 获取 ele1 后面的所有文本节点
|
||||
txts = ele1.nexts('xpath:text()')
|
||||
```
|
||||
|
||||
## prev()
|
||||
|
||||
此方法返回当前元素前面的某一个兄弟元素,可指定筛选条件和第几个。
|
||||
|
||||
参数:
|
||||
|
||||
- index:查询结果中的第几个
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素前面某个兄弟元素或节点文本
|
||||
|
||||
```python
|
||||
# 获取 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()')
|
||||
```
|
||||
|
||||
## prevs()
|
||||
|
||||
此方法返回前面全部符合条件的兄弟元素或节点组成的列表,可用查询语法筛选。
|
||||
|
||||
参数:
|
||||
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素前面符合条件的兄弟元素或节点文本组成的列表
|
||||
|
||||
```python
|
||||
# 获取 ele1 前面所有兄弟元素
|
||||
eles = ele1.prevs()
|
||||
|
||||
# 获取 ele1 前面所有 div 兄弟元素
|
||||
divs = ele1.prevs('tag:div')
|
||||
```
|
||||
|
||||
## after()
|
||||
|
||||
此方法返回当前元素后面的某一个元素,可指定筛选条件和第几个。这个方法查找范围不局限在兄弟元素间,而是整个 DOM 文档。
|
||||
|
||||
参数:
|
||||
|
||||
- index:查询结果中的第几个
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素后面某个元素或节点
|
||||
|
||||
```python
|
||||
# 获取 ele1 后面第 3 个元素
|
||||
ele2 = ele1.after(3)
|
||||
|
||||
# 获取 ele1 后面第 3 个 div 元素
|
||||
ele2 = ele1.after(3, 'tag:div')
|
||||
|
||||
# 获取 ele1 后面第一个文本节点的文本
|
||||
txt = ele1.after(1, 'xpath:text()')
|
||||
```
|
||||
|
||||
## afters()
|
||||
|
||||
此方法返回后面符合条件的全部元素或节点组成的列表,可用查询语法筛选。这个方法查找范围不局限在兄弟元素间,而是整个 DOM 文档。
|
||||
|
||||
参数:
|
||||
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素后面符合条件的元素或节点组成的列表
|
||||
|
||||
```python
|
||||
# 获取 ele1 后所有元素
|
||||
eles = ele1.afters()
|
||||
|
||||
# 获取 ele1 前面所有 div 元素
|
||||
divs = ele1.afters('tag:div')
|
||||
```
|
||||
|
||||
## before()
|
||||
|
||||
此方法返回当前元素前面的某一个元素,可指定筛选条件和第几个。这个方法查找范围不局限在兄弟元素间,而是整个 DOM 文档。
|
||||
|
||||
参数:
|
||||
|
||||
- index:查询结果中的第几个
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素前面某个元素或节点
|
||||
|
||||
```python
|
||||
# 获取 ele1 前面第 3 个元素
|
||||
ele2 = ele1.before(3)
|
||||
|
||||
# 获取 ele1 前面第 3 个 div 元素
|
||||
ele2 = ele1.before(3, 'tag:div')
|
||||
|
||||
# 获取 ele1 前面第一个文本节点的文本
|
||||
txt = ele1.before(1, 'xpath:text()')
|
||||
```
|
||||
|
||||
## befores()
|
||||
|
||||
此方法返回前面全部符合条件的元素或节点组成的列表,可用查询语法筛选。这个方法查找范围不局限在兄弟元素间,而是整个 DOM 文档。
|
||||
|
||||
参数:
|
||||
|
||||
- filter_loc:用于筛选元素的查询语法
|
||||
- timeout:查找元素的超时时间
|
||||
|
||||
返回:本元素前面符合条件的元素或节点组成的列表
|
||||
|
||||
```python
|
||||
# 获取 ele1 前面所有元素
|
||||
eles = ele1.befores()
|
||||
|
||||
# 获取 ele1 前面所有 div 元素
|
||||
divs = ele1.befores('tag:div')
|
||||
```
|
||||
|
||||
# ✔️ `ShadowRootElement`相关查找
|
||||
|
||||
本库把 shadow-root 也作为元素对象看待,是为`ShadowRootElement`对象。对`ShadowRootElement`对象可与普通元素一样查找下级元素和 DOM 内相对定位,但不能用页面布局相对定位。
|
||||
对`ShadowRootElement`对象进行相对定位时,把它看作其父对象内部的第一个对象,其余定位逻辑与普通对象一致。
|
||||
|
||||
!> **注意:** <br>
|
||||
如果`ShadowRootElement`元素的下级元素中有其它`ShadowRootElement`元素,那这些下级`ShadowRootElement`
|
||||
元素内部是无法直接通过定位语句查找到的,只能先定位到其父元素,再用`shadow-root`属性获取。
|
||||
|
||||
```python
|
||||
# 获取一个 shadow-root 元素
|
||||
sr_ele = page.ele('#app').shadow_root
|
||||
|
||||
# 在该元素下查找下级元素
|
||||
ele1 = sr_ele.ele('tag:div')
|
||||
|
||||
# 用相对定位获取其它元素
|
||||
ele1 = sr_ele.parent(2)
|
||||
ele1 = sr_ele.next(1, 'tag:div')
|
||||
ele1 = sr_ele.after(1, 'tag:div')
|
||||
eles = sr_ele.nexts('tag:div')
|
||||
|
||||
# 定位下级元素中的 shadow+-root 元素
|
||||
sr_ele2 = sr_ele.ele('tag:div').shadow_root
|
||||
```
|
||||
|
||||
# ✔️ 简化写法
|
||||
|
||||
为进一步精简代码,对语法进行了精简
|
||||
|
||||
- 定位语法都有其简化形式。
|
||||
- 页面和元素对象都实现了`__call__()`方法,可直接调用。
|
||||
- 所有查找方法都支持链式操作
|
||||
|
||||
示例:
|
||||
|
||||
```python
|
||||
# 定位到页面中 id 为 table_id 的元素,然后获取它的所有 tr 元素
|
||||
eles = page('#table_id').eles('t:tr')
|
||||
|
||||
# 定位到 class 为 cls 的元素,然后在它里面查找文本为 text 的元素
|
||||
ele2 = ele1('.cls1')('tx=text')
|
||||
|
||||
# 获取 ele1 的 shadow_root 元素,再在里面查找 class 属性为 cls 的元素
|
||||
ele2 = ele1.sr('.cls')
|
||||
|
||||
# 按xpath 查找元素
|
||||
ele2 = ele1('x://div[@class="ele_class"]')
|
||||
```
|
||||
|
||||
简化写法对应列表
|
||||
|
||||
| 原写法 | 简化写法 |
|
||||
|:-----------:|:----:|
|
||||
| text | tx |
|
||||
| text() | tx() |
|
||||
| tag | t |
|
||||
| xpath | x |
|
||||
| css | c |
|
||||
| shadow_root | sr |
|
||||
|
||||
# Tips
|
||||
|
||||
- 从一个`DriverElement`元素获取到的`SessionElement`版本,依然能够使用相对定位方法定位祖先或兄弟元素。
|
||||
- `SessionElement`和`SessionPage`的`ele()`和`eles()`方法也有`timeout`参数,但它是不生效的,仅用于保持与 d 模式元素书写一致,便于无差别的调用。
|
||||
- 定位语句内容与关键字重复时,请使用 xpath 或 css selector 代替。
|
@ -1,48 +1,54 @@
|
||||
* [⭐️ 简介](README.md)
|
||||
* [⭐️ 1 简介](README.md)
|
||||
|
||||
* [🧭 入门指南](#)
|
||||
|
||||
* [🔥 基本概念](入门指南\基本概念.md)
|
||||
* [👍 快速上手](入门指南\快速上手.md)
|
||||
* [🍀 特性演示](#)
|
||||
* [🌿 与 requests 对比](入门指南\特性演示\与requests代码对比.md)
|
||||
* [🌿 与 selenium 对比](入门指南\特性演示\与selenium代码对比.md)
|
||||
* [🌿 模式切换](入门指南\特性演示\模式切换.md)
|
||||
* [🌿 获取并打印元素属性](入门指南\特性演示\获取并打印元素属性.md)
|
||||
* [🌿 下载文件](入门指南\特性演示\下载文件.md)
|
||||
* [🧭 2 入门指南](#)
|
||||
|
||||
* [🛠 使用方法](#)
|
||||
|
||||
* [🔨 创建页面对象](使用方法\创建页面对象.md)
|
||||
* [🔨 访问网页](使用方法\访问网页.md)
|
||||
* [🔨 查找页面元素](使用方法\查找页面元素.md)
|
||||
* [🔨 获取元素信息](使用方法\获取元素信息.md)
|
||||
* [🔨 元素操作](使用方法\元素操作.md)
|
||||
* [🔨 获取网页信息](使用方法\获取网页信息.md)
|
||||
* [🔨 页面操作](使用方法\页面操作.md)
|
||||
* [🔨 启动配置](#)
|
||||
* [🔧 概述](使用方法\启动配置\概述.md)
|
||||
* [🔧 Chrome 启动配置](使用方法\启动配置\Chrome启动配置.md)
|
||||
* [🔧 Session 启动配置](使用方法\启动配置\Session启动配置.md)
|
||||
* [🔧 使用配置文件](使用方法\启动配置\使用配置文件.md)
|
||||
* [🔨 下载文件](使用方法\下载文件.md)
|
||||
* [🔨 监听浏览器网络数据](使用方法\监听浏览器网络数据.md)
|
||||
* [🔨 cookies 的使用](使用方法\cookies的使用.md)
|
||||
* [🔨 Drission 对象](使用方法\Drission对象.md)
|
||||
* [🔨 对接 selenium 及 requests 代码](使用方法\对接selenium及requests代码.md)
|
||||
* [🔨 使用其它系统或浏览器](使用方法\使用其它系统或浏览器.md)
|
||||
* [🔨 DriverPage 和 SessionPage](使用方法\DriverPage和SessionPage.md)
|
||||
* [🔨 打包程序](使用方法\打包程序.md)
|
||||
* [🔥 2.1 基本概念](入门指南\基本概念.md)
|
||||
* [👍 2.2 快速上手](入门指南\快速上手.md)
|
||||
* [🍀 2.3 特性演示](#)
|
||||
* [🌿 与 requests 对比](入门指南\特性演示\与requests代码对比.md)
|
||||
* [🌿 与 selenium 对比](入门指南\特性演示\与selenium代码对比.md)
|
||||
* [🌿 模式切换](入门指南\特性演示\模式切换.md)
|
||||
* [🌿 获取并打印元素属性](入门指南\特性演示\获取并打印元素属性.md)
|
||||
* [🌿 下载文件](入门指南\特性演示\下载文件.md)
|
||||
|
||||
* [💖 实用示例](#)
|
||||
|
||||
* [🧡 自动登录码云](实用示例\自动登录码云.md)
|
||||
* [🧡 获取各国疫情排名](实用示例\获取各国疫情排名.md)
|
||||
* [🧡 下载星巴克产品图片](实用示例\下载星巴克产品图片.md)
|
||||
* [🧡 同时操作多个浏览器](实用示例\同时操作多个浏览器.md)
|
||||
* [🛠 3 WebPage 使用方法](#)
|
||||
|
||||
* [⚡️ Tips大集合](Tips大集合.md)
|
||||
* [🔨 3.1 创建页面对象](WebPage使用方法\3.1创建页面对象.md)
|
||||
* [🔨 3.2 访问网页](WebPage使用方法\3.2访问网页.md)
|
||||
* [🔨 3.3 查找元素](WebPage使用方法\3.3查找元素.md)
|
||||
|
||||
* [🎯️ 版本历史](版本历史.md)
|
||||
* [🛠 4 MixPage 使用方法](#)
|
||||
|
||||
* [🔨 4.1 创建页面对象](MixPage使用方法\创建页面对象.md)
|
||||
* [🔨 4.2 访问网页](MixPage使用方法\访问网页.md)
|
||||
* [🔨 4.3 查找页面元素](MixPage使用方法\查找页面元素.md)
|
||||
* [🔨 4.4 获取元素信息](MixPage使用方法\获取元素信息.md)
|
||||
* [🔨 4.5 元素操作](MixPage使用方法\元素操作.md)
|
||||
* [🔨 4.6 获取网页信息](MixPage使用方法\获取网页信息.md)
|
||||
* [🔨 4.7 页面操作](MixPage使用方法\页面操作.md)
|
||||
* [🔨 4.8 启动配置](#)
|
||||
* [🔧 概述](MixPage使用方法\启动配置\概述.md)
|
||||
* [🔧 Chrome 启动配置](MixPage使用方法\启动配置\Chrome启动配置.md)
|
||||
* [🔧 Session 启动配置](MixPage使用方法\启动配置\Session启动配置.md)
|
||||
* [🔧 使用配置文件](MixPage使用方法\启动配置\使用配置文件.md)
|
||||
* [🔨 4.9 下载文件](MixPage使用方法\下载文件.md)
|
||||
* [🔨 4.10 监听浏览器网络数据](MixPage使用方法\监听浏览器网络数据.md)
|
||||
* [🔨 4.11 cookies 的使用](MixPage使用方法\cookies的使用.md)
|
||||
* [🔨 4.12 Drission 对象](MixPage使用方法\Drission对象.md)
|
||||
* [🔨 4.13 对接 selenium 及 requests 代码](MixPage使用方法\对接selenium及requests代码.md)
|
||||
* [🔨 4.14 使用其它系统或浏览器](MixPage使用方法\使用其它系统或浏览器.md)
|
||||
* [🔨 4.15 DriverPage 和 SessionPage](MixPage使用方法\DriverPage和SessionPage.md)
|
||||
* [🔨 4.16 打包程序](MixPage使用方法\打包程序.md)
|
||||
|
||||
* [💖 5 实用示例](#)
|
||||
|
||||
* [🧡 自动登录码云](实用示例\自动登录码云.md)
|
||||
* [🧡 获取各国疫情排名](实用示例\获取各国疫情排名.md)
|
||||
* [🧡 下载星巴克产品图片](实用示例\下载星巴克产品图片.md)
|
||||
* [🧡 同时操作多个浏览器](实用示例\同时操作多个浏览器.md)
|
||||
|
||||
* [⚡️ 6 Tips大集合](Tips大集合.md)
|
||||
|
||||
* [🎯️ 7 版本历史](版本历史.md)
|
||||
|
||||
* [💐 鸣谢](鸣谢.md)
|
||||
|
2
setup.py
2
setup.py
@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
|
||||
|
||||
setup(
|
||||
name="DrissionPage",
|
||||
version="3.0.22",
|
||||
version="3.0.23",
|
||||
author="g1879",
|
||||
author_email="g1879@qq.com",
|
||||
description="A module that integrates selenium and requests session, encapsulates common page operations.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user