修改ChromiumFrame,未完成;str_to_loc()修改tx=xxxx的语法,用text()替代.

This commit is contained in:
g1879 2023-01-03 17:56:46 +08:00
parent 6fedd57677
commit 51cb918b32
7 changed files with 365 additions and 21 deletions

View File

@ -1251,7 +1251,7 @@ def run_script(page_or_ele, script, as_expr=False, timeout=None, args=None, not_
:param script: js文本
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: 超时时间
:param args: 参数按顺序在js文本中对应argument[0]argument[2]...
:param args: 参数按顺序在js文本中对应argument[0]argument[1]...
:param not_change: 执行时是否切换页面对象模式
:return: js执行结果
"""

View File

@ -13,6 +13,7 @@ from .chromium_element import ChromiumElement
class ChromiumFrame(ChromiumBase):
def __init__(self, page, ele):
self.page = page
self.address = self.page.address
node = page.run_cdp('DOM.describeNode', nodeId=ele.node_id, not_change=True)['node']
self.frame_id = node['frameId']
self._backend_id = ele.backend_id
@ -42,20 +43,23 @@ 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 _reload(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():
print('-111')
self._is_diff_domain = False
self.doc_ele = ChromiumElement(self.page, backend_id=node['contentDocument']['backendNodeId'])
super().__init__(self.address, self.page.tab_id, self.page.timeout)
print('+111')
else:
print('-222')
self._is_diff_domain = True
super().__init__(self.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)
print('+222')
def _get_new_document(self):
"""刷新cdp使用的document数据"""
@ -156,7 +160,11 @@ class ChromiumFrame(ChromiumBase):
@property
def title(self):
"""返回页面title"""
return self.ele('t:title').text
while True:
try:
return self.ele('t:title').text
except:
self._reload()
@property
def cookies(self):
@ -251,7 +259,7 @@ class ChromiumFrame(ChromiumBase):
"""运行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 self.doc_ele.run_script(script, as_expr=as_expr, *args)

View File

@ -28,6 +28,8 @@ class ChromiumFrame(ChromiumBase):
def __repr__(self) -> str: ...
def _reload(self) -> None: ...
def _get_new_document(self) -> None: ...
def _onFrameAttached(self, **kwargs): ...

View File

@ -113,8 +113,8 @@ def get_loc(loc: Union[tuple, str], translate_css: bool = False) -> tuple:
def str_to_loc(loc: str) -> tuple:
"""处理元素查找语句 \n
查找方式属性tag name及属性文本xpathcss selectoridclass \n
"""处理元素查找语句 \n
查找方式属性tag name及属性文本xpathcss selectoridclass \n
@表示属性.表示class#表示id=表示精确匹配,:表示模糊匹配,无控制字符串时默认搜索该字符串 \n
"""
loc_by = 'xpath'
@ -159,7 +159,7 @@ def str_to_loc(loc: str) -> tuple:
# 根据文本查找
elif loc.startswith('text='):
loc_str = f'//*[.={_make_search_str(loc[5:])}]'
loc_str = f'//*[text()={_make_search_str(loc[5:])}]'
elif loc.startswith('text:') and loc != 'text:':
loc_str = f'//*/text()[contains(., {_make_search_str(loc[5:])})]/..'

View File

@ -164,4 +164,79 @@ page.to_tab('0B300BEA6F1F1F4D5DE406872B79B1AD')
## 📍 获取标签页对象
# 未完待续
可以用`WebPage``ChromiumPage``get_tab()`方法获取标签页对象,然后可以使用这个对象对标签页进行操作。
`get_tab()`
**参数:**
- `tab_id`:要获取的标签页 id`None`时获取当前标签页
**返回:**`ChromiumTab`对象
```python
tab = page.get_tab() # 获取当前标签页对象
```
## 📍 使用标签页对象
每个`ChromiumTab`对象控制一个浏览器标签页,方法和直接使用`ChromiumPage`一致,只比`ChromiumPage`少了控制标签页功能。
```python
tab.get('https://www.baidu.com') # 使用标签页对象
```
## 📍 同时控制多标签页示例
下面的例子演示多个线程控制多个标签页进行内容采集。
```python
from threading import Thread
from DrissionPage import ChromiumPage
def 采集(tab):
# 采集 4 页
for _ in range(4):
# 获取某页所有库名称并打印
for i in tab.eles('.title project-namespace-path'):
print(i.text)
# 点击翻页
tab('@rel=next').click()
# 等待页面进入加载
tab.wait_loading()
if __name__ == '__main__':
# 新建页面对象
page = ChromiumPage()
# 第一个标签页访问网址
page.get('https://gitee.com/explore/ai')
# 获取第一个标签页对象
tab1 = page.get_tab()
# 新建一个标签页并访问另一个网址
page.new_tab('https://gitee.com/explore/machine-learning')
# 获取第二个标签页对象
tab2 = page.get_tab()
# 多线程同时处理多个页面
Thread(target=采集, args=(tab1,)).start()
Thread(target=采集, args=(tab2,)).start()
```
输出:
```console
MindSpore/mindspore
PaddlePaddle/Paddle
MindSpore/docs
scruel/Notes-ML-AndrewNg
MindSpore/graphengine
inspur-inna/inna1.0
MindSpore/course
MindSpore/community
后面省略。。。
```

View File

@ -0,0 +1,258 @@
`<iframe>`元素是一种特殊的元素,它既是元素,也是页面,因此独立一个章节对其进行介绍。
与 selenium 不同DrissionPage 无需切入切出即可处理`<iframe>`元素。因此可实现跨级元素查找、元素内部单独跳转、同时操作`<iframe>`内外元素、多线程控制多个`<iframe>`等操作,功能更灵活,逻辑更清晰。
我们使用菜鸟教程在线编辑器来演示:
[菜鸟教程在线编辑器 (runoob.com)](https://www.runoob.com/try/try.php?filename=tryhtml_iframe)
源代码框内容要作一点调整,然后按“点击运行”:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<iframe id="sss" src="https://www.runoob.com">
<p>您的浏览器不支持 iframe 标签。</p>
</iframe>
</body>
</html>
```
`F12`,可以看到网页右侧是一个两层`<iframe>`,一个 id 是`'iframeResult'``<iframe>`里面有一个 id 是`'sss'``<iframe>`。最里层的`<iframe>`页面指向 https://www.runoob.com。
# ✔ 获取`<iframe>`对象
现在我们获取最里层`<iframe>`对象。方法和直接获取元素一样:
```python
iframe = page('#sss')
print(iframe.html)
```
输出:
```console
<iframe id="sss" src="https://www.runoob.com"><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>菜鸟教程 - 学的不仅是技术,更是梦想!</title>
<meta name="robots" content="max-image-preview:large">
下面省略。。。
```
这个`ChromiumFrame`对象既是页面也是元素,下面演示其功能。
# ✔ 查找`<iframe>`内元素
从刚才获取元素对象看出,我们并不须要先切入 id 为`'iframeResult'``<iframe>`,就可以获取到里面的元素。所以我们获取元素也并不一定要先获取到`ChromiumFrame`对象。
## 📍 在`<iframe>`内查找
使用我们刚才获取到的元素,可以在里面查找元素:
```python
ele = iframe('首页')
print(ele)
# 输出:<ChromiumElement a href='https://www.runoob.com/' data-id='index' title='菜鸟教程' class='current'>
```
## 📍 页面跨`<iframe>`查找
如果`<iframe>`元素的网址和主页面是同域的,我们可以直接用页面对象查找`<iframe>`内部元素,而无需先获取`ChromiumFrame`对象:
```python
ele = page('首页')
print(ele)
# 输出:<ChromiumElement a href='https://www.runoob.com/' data-id='index' title='菜鸟教程' class='current'>
```
只要是同域名的,无论跨多少曾`<iframe>`都能用页面对象直接获取。
## 📍 与 selenium 对比
`WebPage`
```python
from DrissionPage import WebPage
page = WebPage()
ele = page('首页')
```
`MixPage`(基于 selenium
```python
from DrissionPage import MixPage
page = MixPage()
page.to_frame('#iframeResult')
page.to_frame('#sss')
ele = page('首页')
page.to_frame.main()
```
可见,原来的逻辑要切入切出,比较繁琐。
# ✔ `ChromiumFrame`的元素特征
正如上面所说,`ChromiumFrame`既是元素也是页面,这里说一下其元素方面的用法。
## 📍 `tab_id`
此属性返回`<iframe>`元素所在标签页的 id。
## 📍 `tag`
此属性返回元素名称。
## 📍 `html`
此属性返回整个`<iframe>`元素的 outerHTML 文本。
## 📍 `inner_html`
此属性返回 innerHTML 文本。
## 📍 `attrs`
此属性以`dict`形式返回元素所有 attribute 属性。
## 📍 `size`
此属性以`tuple`形式返回元素大小。
## 📍 `location`
此属性以`tuple`形式返回元素在主页面中的位置。
## 📍 `is_displayed`
此属性返回元素是否可见。
## 📍 `xpath`
此属性返回元素在其页面上的 xpath 路径。
## 📍 `css_path`
此属性返回元素在其页面上的 css selector 路径。
## 📍 `attr()`
此方法用于一个获取元素 attribute 属性。
**参数:**
- `attr`:属性名
**返回:** 属性值文本,没有该属性返回`None`
## 📍 `set_attr()`
此方法用于设置元素的 attribute 属性。
**参数:**
- `attr`:属性名
**返回:**`None`
## 📍 `remove_attr()`
此方法用于删除元素的 attribute 属性。
**参数:**
- `attr`:属性名
**返回:**`None`
## 📍 相对定位
相对定位方法与普通元素一致,详见获取元素章节。
- `parent()`:返回上面某一级父元素。
- `prev()`:返回前面的一个兄弟元素。
- `next()`:返回后面的一个兄弟元素。
- `before()`:返回当前元素前面的一个元素。
- `after()`:返回当前元素后面的一个元素。
- `prevs()`:返回前面全部兄弟元素或节点组成的列表。
- `nexts()`:返回后面全部兄弟元素或节点组成的列表。
- `befores()`:返回当前元素后面符合条件的全部兄弟元素或节点组成的列表。
# ✔ `ChromiumFrame`的页面特征
## 📍 `url`
此属性返回页面当前 url。
## 📍 `title`
此属性返回页面当前 title 文本。
## 📍 `cookies`
此属性返回页面当前 cookies 内容。
## 📍 `get()`
此方法用于实现`<iframe>`页面跳转。
```python
iframe.get('https://www.runoob.com/css3/css3-tutorial.html')
```
## 📍 `refresh()`
此方法用于刷新页面。
```python
iframe.refresh()
```
## 📍 `ready_state`
此属性为页面加载状态。
## 📍 `is_loading`
此属性返回页面是否正在加载。
## 📍 `active_ele`
此属性返回页面中焦点所在元素。
## 📍 `frame_size`
此属性以`tuple`形式返回页面大小。
## 📍 `run_script()`
此方法用于在`<iframe>`内执行 js 脚本。
**参数:**
- `script`js文本
- `as_expr`:是否作为表达式运行,为`True``args`无效
- `*args`:参数,按顺序在 js 文本中对应 argument[0]、argument[1]...
**返回:** 运行的结果

View File

@ -21,6 +21,7 @@
* [🔨 3.6 获取网页信息](WebPage使用方法\3.6获取网页信息.md)
* [🔨 3.7 页面操作](WebPage使用方法\3.7页面操作.md)
* [🔨 3.8 标签页操作](WebPage使用方法\3.8标签页操作.md)
* [🔨 3.9 iframe操作](WebPage使用方法\3.9iframe操作.md)
* [🛠 4 MixPage 使用方法](#)