4.0.3增加DrissionPage.items;修复合并了旧代码的问题;增加get_blob()未完成

This commit is contained in:
g1879 2024-01-18 01:06:50 +08:00
parent 74b7bd80af
commit 4f12493edb
12 changed files with 74 additions and 52 deletions

View File

@ -14,4 +14,4 @@ from ._configs.chromium_options import ChromiumOptions
from ._configs.session_options import SessionOptions from ._configs.session_options import SessionOptions
__all__ = ['ChromiumPage', 'ChromiumOptions', 'SessionOptions', 'SessionPage', 'WebPage', '__version__'] __all__ = ['ChromiumPage', 'ChromiumOptions', 'SessionOptions', 'SessionPage', 'WebPage', '__version__']
__version__ = '4.0.2' __version__ = '4.0.3'

View File

@ -8,6 +8,7 @@
from configparser import RawConfigParser, NoSectionError, NoOptionError from configparser import RawConfigParser, NoSectionError, NoOptionError
from pathlib import Path from pathlib import Path
from pprint import pprint from pprint import pprint
from time import sleep
class OptionsManager(object): class OptionsManager(object):
@ -28,8 +29,9 @@ class OptionsManager(object):
self.ini_path = str(path) self.ini_path = str(path)
if not Path(self.ini_path).exists(): if not Path(self.ini_path).exists():
input('\nini文件不存在。\n如果是打包使用,请查看打包注意事项\nhttps://g1879.gitee.io/drission' print('\nini文件不存在。\n如果是打包使用,请查看打包注意事项\n'
'pagedocs/advance/packaging/') 'https://g1879.gitee.io/drissionpagedocs/advance/packaging/')
sleep(10)
self._conf = RawConfigParser() self._conf = RawConfigParser()
self._conf.read(self.ini_path, encoding='utf-8') self._conf.read(self.ini_path, encoding='utf-8')

View File

@ -12,11 +12,6 @@ from typing import Any
class OptionsManager(object): class OptionsManager(object):
ini_path: str = ... ini_path: str = ...
_conf: RawConfigParser = ... _conf: RawConfigParser = ...
paths: dict = ...
chrome_options: dict = ...
session_options: dict = ...
timeouts: dict = ...
proxies: dict = ...
def __init__(self, path: str = None): ... def __init__(self, path: str = None): ...

View File

@ -19,7 +19,7 @@ from .._base.base import DrissionElement, BaseElement
from .._functions.keys import input_text_or_keys from .._functions.keys import input_text_or_keys
from .._functions.locator import get_loc from .._functions.locator import get_loc
from .._functions.settings import Settings from .._functions.settings import Settings
from .._functions.web import make_absolute_link, get_ele_txt, format_html, is_js_func, offset_scroll from .._functions.web import make_absolute_link, get_ele_txt, format_html, is_js_func, offset_scroll, get_blob
from .._units.clicker import Clicker from .._units.clicker import Clicker
from .._units.rect import ElementRect from .._units.rect import ElementRect
from .._units.scroller import ElementScroller from .._units.scroller import ElementScroller
@ -495,26 +495,9 @@ class ChromiumElement(DrissionElement):
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
if is_blob: if is_blob:
js = """ result = get_blob(self.page, src, base64_to_bytes)
function fetchData(url) { if result:
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {resolve(reader.result);}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url, true);
xhr.send();
});
}
"""
try:
result = self.page.run_js(js, src)
break break
except:
continue
else: else:
src = self.prop('currentSrc') src = self.prop('currentSrc')
@ -534,18 +517,13 @@ class ChromiumElement(DrissionElement):
return None return None
if is_blob: if is_blob:
if base64_to_bytes: return result
from base64 import b64decode
return b64decode(result.split(',', 1)[-1])
else:
return result
if result['base64Encoded'] and base64_to_bytes:
from base64 import b64decode
return b64decode(result['content'])
else: else:
if result['base64Encoded'] and base64_to_bytes: return result['content']
from base64 import b64decode
return b64decode(result['content'])
else:
return result['content']
def save(self, path=None, name=None, timeout=None): def save(self, path=None, name=None, timeout=None):
"""保存图片或其它有src属性的元素的资源 """保存图片或其它有src属性的元素的资源

View File

@ -40,7 +40,7 @@ class SessionElement(DrissionElement):
"""在内部查找元素 """在内部查找元素
ele2 = ele1('@id=ele_id') ele2 = ele1('@id=ele_id')
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串 :param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 不起实际作用用于和DriverElement对应便于无差别调用 :param timeout: 不起实际作用
:return: SessionElement对象或属性文本 :return: SessionElement对象或属性文本
""" """
return self.ele(loc_or_str) return self.ele(loc_or_str)
@ -80,12 +80,13 @@ class SessionElement(DrissionElement):
"""返回未格式化处理的元素内文本""" """返回未格式化处理的元素内文本"""
return str(self._inner_ele.text_content()) return str(self._inner_ele.text_content())
def parent(self, level_or_loc=1): def parent(self, level_or_loc=1, index=1):
"""返回上面某一级父元素,可指定层数或用查询语法定位 """返回上面某一级父元素,可指定层数或用查询语法定位
:param level_or_loc: 第几级父元素或定位符 :param level_or_loc: 第几级父元素或定位符
:param index: 当level_or_loc传入定位符使用此参数选择第几个结果
:return: 上级元素对象 :return: 上级元素对象
""" """
return super().parent(level_or_loc) return super().parent(level_or_loc, index)
def child(self, filter_loc='', index=1, timeout=None, ele_only=True): def child(self, filter_loc='', index=1, timeout=None, ele_only=True):
"""返回当前元素的一个符合条件的直接子元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回当前元素的一个符合条件的直接子元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -95,7 +96,7 @@ class SessionElement(DrissionElement):
:param ele_only: 是否只获取元素为False时把文本注释节点也纳入 :param ele_only: 是否只获取元素为False时把文本注释节点也纳入
:return: 直接子元素或节点文本 :return: 直接子元素或节点文本
""" """
return super().child(index, filter_loc, timeout, ele_only=ele_only) return super().child(filter_loc, index, timeout, ele_only=ele_only)
def prev(self, filter_loc='', index=1, timeout=None, ele_only=True): def prev(self, filter_loc='', index=1, timeout=None, ele_only=True):
"""返回当前元素前面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回当前元素前面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -105,7 +106,7 @@ class SessionElement(DrissionElement):
:param ele_only: 是否只获取元素为False时把文本注释节点也纳入 :param ele_only: 是否只获取元素为False时把文本注释节点也纳入
:return: 同级元素 :return: 同级元素
""" """
return super().prev(index, filter_loc, timeout, ele_only=ele_only) return super().prev(filter_loc, index, timeout, ele_only=ele_only)
def next(self, filter_loc='', index=1, timeout=None, ele_only=True): def next(self, filter_loc='', index=1, timeout=None, ele_only=True):
"""返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -115,7 +116,7 @@ class SessionElement(DrissionElement):
:param ele_only: 是否只获取元素为False时把文本注释节点也纳入 :param ele_only: 是否只获取元素为False时把文本注释节点也纳入
:return: 同级元素 :return: 同级元素
""" """
return super().next(index, filter_loc, timeout, ele_only=ele_only) return super().next(filter_loc, index, timeout, ele_only=ele_only)
def before(self, filter_loc='', index=1, timeout=None, ele_only=True): def before(self, filter_loc='', index=1, timeout=None, ele_only=True):
"""返回文档中当前元素前面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回文档中当前元素前面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -126,7 +127,7 @@ class SessionElement(DrissionElement):
:param ele_only: 是否只获取元素为False时把文本注释节点也纳入 :param ele_only: 是否只获取元素为False时把文本注释节点也纳入
:return: 本元素前面的某个元素或节点 :return: 本元素前面的某个元素或节点
""" """
return super().before(index, filter_loc, timeout, ele_only=ele_only) return super().before(filter_loc, index, timeout, ele_only=ele_only)
def after(self, filter_loc='', index=1, timeout=None, ele_only=True): def after(self, filter_loc='', index=1, timeout=None, ele_only=True):
"""返回文档中此当前元素后面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回文档中此当前元素后面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -137,7 +138,7 @@ class SessionElement(DrissionElement):
:param ele_only: 是否只获取元素为False时把文本注释节点也纳入 :param ele_only: 是否只获取元素为False时把文本注释节点也纳入
:return: 本元素后面的某个元素或节点 :return: 本元素后面的某个元素或节点
""" """
return super().after(index, filter_loc, timeout, ele_only=ele_only) return super().after(filter_loc, index, timeout, ele_only=ele_only)
def children(self, filter_loc='', timeout=0, ele_only=True): def children(self, filter_loc='', timeout=0, ele_only=True):
"""返回当前元素符合条件的直接子元素或节点组成的列表,可用查询语法筛选 """返回当前元素符合条件的直接子元素或节点组成的列表,可用查询语法筛选
@ -231,7 +232,7 @@ class SessionElement(DrissionElement):
def eles(self, loc_or_str, timeout=None): def eles(self, loc_or_str, timeout=None):
"""返回当前元素下级所有符合条件的子元素、属性或节点文本 """返回当前元素下级所有符合条件的子元素、属性或节点文本
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串 :param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 不起实际作用用于和DriverElement对应便于无差别调用 :param timeout: 不起实际作用
:return: SessionElement对象或属性文本组成的列表 :return: SessionElement对象或属性文本组成的列表
""" """
return self._ele(loc_or_str, index=None) return self._ele(loc_or_str, index=None)
@ -327,8 +328,7 @@ def make_session_ele(html_or_ele, loc=None, index=1):
loc = loc[0], loc_str loc = loc[0], loc_str
# ChromiumElement, DriverElement elif the_type.endswith(".ChromiumElement'>"):
elif the_type.endswith((".ChromiumElement'>", ".DriverElement'>")):
loc_str = loc[1] loc_str = loc[1]
if loc[0] == 'xpath' and loc[1].lstrip().startswith('/'): if loc[0] == 'xpath' and loc[1].lstrip().startswith('/'):
loc_str = f'.{loc[1]}' loc_str = f'.{loc[1]}'

View File

@ -215,6 +215,8 @@ def raise_error(result, ignore=None):
r = CookieFormatError(f'cookie格式不正确{result["args"]}') r = CookieFormatError(f'cookie格式不正确{result["args"]}')
elif error == 'Given expression does not evaluate to a function': elif error == 'Given expression does not evaluate to a function':
r = JavaScriptError(f'传入的js无法解析成函数\n{result["args"]["functionDeclaration"]}') r = JavaScriptError(f'传入的js无法解析成函数\n{result["args"]["functionDeclaration"]}')
elif error.endswith("' wasn't found"):
r = RuntimeError(f'你的浏览器可能太旧。\nmethod{result["method"]}\nargs{result["args"]}')
elif result['type'] in ('call_method_error', 'timeout'): elif result['type'] in ('call_method_error', 'timeout'):
from DrissionPage import __version__ from DrissionPage import __version__
from time import process_time from time import process_time

View File

@ -328,3 +328,30 @@ def is_cookie_in_driver(page, cookie):
if cookie['name'] == c['name'] and cookie['value'] == c['value']: if cookie['name'] == c['name'] and cookie['value'] == c['value']:
return True return True
return False return False
def get_blob(page, url, base64_to_bytes=True):
if not url.startswith('blob'):
return None
js = """
function fetchData(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function(){resolve(reader.result);}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url, true);
xhr.send();
});
}
"""
try:
result = page.run_js(js, url)
except:
return None
if base64_to_bytes:
from base64 import b64decode
return b64decode(result.split(',', 1)[-1])

View File

@ -47,3 +47,6 @@ def set_browser_cookies(page: ChromiumBase, cookies: Union[RequestsCookieJar, li
def is_cookie_in_driver(page: ChromiumBase, cookie: dict) -> bool: ... def is_cookie_in_driver(page: ChromiumBase, cookie: dict) -> bool: ...
def get_blob(page: ChromiumBase, url: str, base64_to_bytes: bool = True) -> bytes: ...

View File

@ -6,6 +6,7 @@
@License : BSD 3-Clause. @License : BSD 3-Clause.
""" """
from pathlib import Path from pathlib import Path
from time import sleep
from requests.structures import CaseInsensitiveDict from requests.structures import CaseInsensitiveDict
@ -608,7 +609,11 @@ class WindowSetter(object):
def _get_info(self): def _get_info(self):
"""获取窗口位置及大小信息""" """获取窗口位置及大小信息"""
return self._page.run_cdp('Browser.getWindowForTarget') for _ in range(50):
try:
return self._page.run_cdp('Browser.getWindowForTarget')
except:
sleep(.1)
def _perform(self, bounds): def _perform(self, bounds):
"""执行改变窗口大小操作 """执行改变窗口大小操作

View File

@ -10,6 +10,7 @@ from ._functions.by import By
from ._functions.keys import Keys from ._functions.keys import Keys
from ._functions.settings import Settings from ._functions.settings import Settings
from ._functions.tools import wait_until, configs_to_here from ._functions.tools import wait_until, configs_to_here
from ._functions.web import get_blob
from ._units.actions import Actions from ._units.actions import Actions
__all__ = ['make_session_ele', 'Actions', 'Keys', 'By', 'Settings', 'wait_until', 'configs_to_here'] __all__ = ['make_session_ele', 'Actions', 'Keys', 'By', 'Settings', 'wait_until', 'configs_to_here', 'get_blob']

9
DrissionPage/items.py Normal file
View File

@ -0,0 +1,9 @@
# -*- coding:utf-8 -*-
from ._elements.chromium_element import ChromiumElement, ShadowRoot
from ._elements.none_element import NoneElement
from ._elements.session_element import SessionElement
from ._pages.chromium_frame import ChromiumFrame
from ._pages.chromium_tab import ChromiumTab, WebPageTab
__all__ = ['ChromiumElement', 'ShadowRoot', 'NoneElement', 'SessionElement', 'ChromiumFrame', 'ChromiumTab',
'WebPageTab']

View File

@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
setup( setup(
name="DrissionPage", name="DrissionPage",
version="4.0.2", version="4.0.3",
author="g1879", author="g1879",
author_email="g1879@qq.com", author_email="g1879@qq.com",
description="Python based web automation tool. It can control the browser and send and receive data packets.", description="Python based web automation tool. It can control the browser and send and receive data packets.",