diff --git a/DrissionPage/chromium_base.py b/DrissionPage/chromium_base.py index 70b4cf7..93b5c8a 100644 --- a/DrissionPage/chromium_base.py +++ b/DrissionPage/chromium_base.py @@ -5,7 +5,7 @@ """ from base64 import b64decode from json import loads, JSONDecodeError -from os import sep +from os.path import sep from pathlib import Path from threading import Thread from time import perf_counter, sleep, time @@ -768,10 +768,11 @@ class ChromiumBase(BasePage): ''' return {i['key']: i['val'] for i in self.run_js_loaded(js)} - def get_screenshot(self, path=None, as_bytes=None, as_base64=None, + def get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None, full_page=False, left_top=None, right_bottom=None): """对页面进行截图,可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持 - :param path: 完整路径,后缀可选 'jpg','jpeg','png','webp' + :param path: 保存路径 + :param name: 完整文件名,后缀可选 'jpg','jpeg','png','webp' :param as_bytes: 是否以字节形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数和as_base64参数无效 :param as_base64: 是否以base64字符串形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数无效 :param full_page: 是否整页截图,为True截取整个网页,为False截取可视窗口 @@ -779,7 +780,7 @@ class ChromiumBase(BasePage): :param right_bottom: 截取范围右下角角坐标 :return: 图片完整路径或字节文本 """ - return self._get_screenshot(path=path, as_bytes=as_bytes, as_base64=as_base64, + return self._get_screenshot(path=path, name=name, as_bytes=as_bytes, as_base64=as_base64, full_page=full_page, left_top=left_top, right_bottom=right_bottom) def clear_cache(self, session_storage=True, local_storage=True, cache=True, cookies=True): @@ -843,10 +844,11 @@ class ChromiumBase(BasePage): return True - def _get_screenshot(self, path=None, as_bytes=None, as_base64=None, + def _get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None, full_page=False, left_top=None, right_bottom=None, ele=None): """对页面进行截图,可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持 - :param path: 完整路径,后缀可选 'jpg','jpeg','png','webp' + :param path: 保存路径 + :param name: 完整文件名,后缀可选 'jpg','jpeg','png','webp' :param as_bytes: 是否以字节形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数和as_base64参数无效 :param as_base64: 是否以base64字符串形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数无效 :param full_page: 是否整页截图,为True截取整个网页,为False截取可视窗口 @@ -860,7 +862,7 @@ class ChromiumBase(BasePage): pic_type = 'png' else: if as_bytes not in ('jpg', 'jpeg', 'png', 'webp'): - raise ValueError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") + raise TypeError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") pic_type = 'jpeg' if as_bytes == 'jpg' else as_bytes elif as_base64: @@ -868,16 +870,18 @@ class ChromiumBase(BasePage): pic_type = 'png' else: if as_base64 not in ('jpg', 'jpeg', 'png', 'webp'): - raise ValueError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") + raise TypeError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") pic_type = 'jpeg' if as_base64 == 'jpg' else as_base64 else: + if not name: + name = f'{self.title}.jpg' if not path: - path = f'{self.title}.jpg' - path = get_usable_path(path) + path = '.' + if not name.endswith(('.jpg', '.jpeg', '.png', '.webp')): + name = f'{name}.jpg' + path = get_usable_path(f'{path}{sep}{name}') pic_type = path.suffix.lower() - if pic_type not in ('.jpg', '.jpeg', '.png', '.webp'): - raise TypeError(f'不支持的文件格式:{pic_type}。') pic_type = 'jpeg' if pic_type == '.jpg' else pic_type[1:] width, height = self.size @@ -1099,8 +1103,7 @@ class Screencast(object): """非节俭模式运行方法""" self._running = True while self._enable: - p = self._path / f'{time()}.jpg' - self._page.get_screenshot(path=p) + self._page.get_screenshot(path=self._path, name=f'{time()}.jpg') sleep(.04) self._running = False diff --git a/DrissionPage/chromium_base.pyi b/DrissionPage/chromium_base.pyi index ac9ff03..050880b 100644 --- a/DrissionPage/chromium_base.pyi +++ b/DrissionPage/chromium_base.pyi @@ -198,13 +198,13 @@ class ChromiumBase(BasePage): def get_local_storage(self, item: str = None) -> Union[str, dict, None]: ... - def get_screenshot(self, path: [str, Path] = None, + def get_screenshot(self, path: [str, Path] = None, name: str = None, as_bytes: [bool, str] = None, as_base64: [bool, str] = None, full_page: bool = False, left_top: Tuple[int, int] = None, right_bottom: Tuple[int, int] = None) -> Union[str, bytes]: ... - def _get_screenshot(self, path: [str, Path] = None, + def _get_screenshot(self, path: [str, Path] = None, name: str = None, as_bytes: [bool, str] = None, as_base64: [bool, str] = None, full_page: bool = False, left_top: Tuple[int, int] = None, diff --git a/DrissionPage/chromium_element.py b/DrissionPage/chromium_element.py index ca70063..376a91d 100644 --- a/DrissionPage/chromium_element.py +++ b/DrissionPage/chromium_element.py @@ -3,8 +3,7 @@ @Author : g1879 @Contact : g1879@qq.com """ -from os import sep -from os.path import basename +from os.path import basename, sep from pathlib import Path from time import perf_counter, sleep @@ -12,7 +11,7 @@ from .base import DrissionElement, BaseElement from .commons.constants import FRAME_ELEMENT, NoneElement, Settings from .commons.keys import keys_to_typing, keyDescriptionForString, keyDefinitions from .commons.locator import get_loc -from .commons.tools import make_valid_name +from .commons.tools import get_usable_path from .commons.web import make_absolute_link, get_ele_txt, format_html, is_js_func, location_in_viewport, offset_scroll from .errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError, ElementNotFoundError, \ CDPError, NoResourceError, CanNotClickError @@ -481,50 +480,53 @@ class ChromiumElement(DrissionElement): else: return result['content'] - def save(self, path=None, rename=None, timeout=None): + def save(self, path=None, name=None, timeout=None): """保存图片或其它有src属性的元素的资源 :param path: 文件保存路径,为None时保存到当前文件夹 - :param rename: 文件名称,为None时从资源url获取 + :param name: 文件名称,为None时从资源url获取 :param timeout: 等待资源加载的超时时间 - :return: None + :return: 返回保存路径 """ data = self.get_src(timeout=timeout) if not data: raise NoResourceError path = path or '.' - rename = rename or basename(self.prop('currentSrc')) - rename = make_valid_name(rename) + name = name or basename(self.prop('currentSrc')) + path = get_usable_path(f'{path}{sep}{name}').absolute() write_type = 'wb' if isinstance(data, bytes) else 'w' - Path(path).mkdir(parents=True, exist_ok=True) - with open(f'{path}{sep}{rename}', write_type) as f: + with open(path, write_type) as f: f.write(data) - def get_screenshot(self, path=None, as_bytes=None, as_base64=None): + return str(path) + + def get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None, scroll_to_center=False): """对当前元素截图,可保存到文件,或以字节方式返回 - :param path: 完整路径,后缀可选 'jpg','jpeg','png','webp' + :param path: 文件保存路径 + :param name: 完整文件名,后缀可选 'jpg','jpeg','png','webp' :param as_bytes: 是否以字节形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数和as_base64参数无效 :param as_base64: 是否以base64字符串形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数无效 + :param scroll_to_center: 截图前是否滚动到视口中央 :return: 图片完整路径或字节文本 """ if self.tag == 'img': # 等待图片加载完成 - js = ('return this.complete && typeof this.naturalWidth != "undefined" ' - '&& this.naturalWidth > 0 && typeof this.naturalHeight != "undefined" ' - '&& this.naturalHeight > 0') + js = ('return this.complete && typeof this.naturalWidth != "undefined" && this.naturalWidth > 0 ' + '&& typeof this.naturalHeight != "undefined" && this.naturalHeight > 0') end_time = perf_counter() + self.page.timeout while not self.run_js(js) and perf_counter() < end_time: sleep(.1) - # self.scroll.to_see(center=True) - # sleep(1) + if scroll_to_center: + self.scroll.to_see(center=True) + left, top = self.location width, height = self.size left_top = (left, top) right_bottom = (left + width, top + height) - if not path: - path = f'{self.tag}.jpg' - return self.page._get_screenshot(path, as_bytes=as_bytes, as_base64=as_base64, full_page=False, + if not name: + name = f'{self.tag}.jpg' + return self.page._get_screenshot(path, name, as_bytes=as_bytes, as_base64=as_base64, full_page=False, left_top=left_top, right_bottom=right_bottom, ele=self) def input(self, vals, clear=True, by_js=False): diff --git a/DrissionPage/chromium_element.pyi b/DrissionPage/chromium_element.pyi index da4654f..58fac20 100644 --- a/DrissionPage/chromium_element.pyi +++ b/DrissionPage/chromium_element.pyi @@ -180,10 +180,10 @@ class ChromiumElement(DrissionElement): def get_src(self, timeout: float = None, base64_to_bytes: bool = True) -> Union[bytes, str, None]: ... - def save(self, path: [str, bool] = None, rename: str = None, timeout: float = None) -> None: ... + def save(self, path: [str, bool] = None, name: str = None, timeout: float = None) -> str: ... - def get_screenshot(self, path: [str, Path] = None, as_bytes: [bool, str] = None, - as_base64: [bool, str] = None) -> Union[str, bytes]: ... + def get_screenshot(self, path: [str, Path] = None, name: str = None, as_bytes: [bool, str] = None, + as_base64: [bool, str] = None, scroll_to_center: bool = False) -> Union[str, bytes]: ... def input(self, vals: Any, clear: bool = True, by_js: bool = False) -> None: ... diff --git a/DrissionPage/chromium_frame.py b/DrissionPage/chromium_frame.py index e4ed12a..9d136d3 100644 --- a/DrissionPage/chromium_frame.py +++ b/DrissionPage/chromium_frame.py @@ -4,6 +4,7 @@ @Contact : g1879@qq.com """ from copy import copy +from os.path import sep from re import search from threading import Thread from time import sleep, perf_counter @@ -492,19 +493,21 @@ class ChromiumFrame(ChromiumBase): self._check_ok() return self.frame_ele.afters(filter_loc, timeout, ele_only=ele_only) - def get_screenshot(self, path=None, as_bytes=None, as_base64=None): + def get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None): """对页面进行截图,可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持 - :param path: 完整路径,后缀可选 'jpg','jpeg','png','webp' + :param path: 文件保存路径 + :param name: 完整文件名,后缀可选 'jpg','jpeg','png','webp' :param as_bytes: 是否以字节形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数和as_base64参数无效 :param as_base64: 是否以base64字符串形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数无效 :return: 图片完整路径或字节文本 """ - return self.frame_ele.get_screenshot(path=path, as_bytes=as_bytes, as_base64=as_base64) + return self.frame_ele.get_screenshot(path=path, name=name, as_bytes=as_bytes, as_base64=as_base64) - def _get_screenshot(self, path=None, as_bytes: [bool, str] = None, as_base64: [bool, str] = None, + def _get_screenshot(self, path=None, name=None, as_bytes: [bool, str] = None, as_base64: [bool, str] = None, full_page=False, left_top=None, right_bottom=None, ele=None): - """实现对元素截图 - :param path: 完整路径,后缀可选 'jpg','jpeg','png','webp' + """实现截图 + :param path: 文件保存路径 + :param name: 完整文件名,后缀可选 'jpg','jpeg','png','webp' :param as_bytes: 是否以字节形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数和as_base64参数无效 :param as_base64: 是否以base64字符串形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数无效 :param full_page: 是否整页截图,为True截取整个网页,为False截取可视窗口 @@ -514,7 +517,7 @@ class ChromiumFrame(ChromiumBase): :return: 图片完整路径或字节文本 """ if not self._is_diff_domain: - return super().get_screenshot(path=path, as_bytes=as_bytes, as_base64=as_base64, + return super().get_screenshot(path=path, name=name, as_bytes=as_bytes, as_base64=as_base64, full_page=full_page, left_top=left_top, right_bottom=right_bottom) if as_bytes: @@ -522,7 +525,7 @@ class ChromiumFrame(ChromiumBase): pic_type = 'png' else: if as_bytes not in ('jpg', 'jpeg', 'png', 'webp'): - raise ValueError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") + raise TypeError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") pic_type = 'jpeg' if as_bytes == 'jpg' else as_bytes elif as_base64: @@ -530,16 +533,18 @@ class ChromiumFrame(ChromiumBase): pic_type = 'png' else: if as_base64 not in ('jpg', 'jpeg', 'png', 'webp'): - raise ValueError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") + raise TypeError("只能接收 'jpg', 'jpeg', 'png', 'webp' 四种格式。") pic_type = 'jpeg' if as_base64 == 'jpg' else as_base64 else: if not path: - path = f'{self.title}.jpg' - path = get_usable_path(path) + path = '.' + if not name: + name = f'{self.title}.jpg' + if not name.endswith(('.jpg', '.jpeg', '.png', '.webp')): + name = f'{name}.jpg' + path = get_usable_path(f'{path}{sep}{name}') pic_type = path.suffix.lower() - if pic_type not in ('.jpg', '.jpeg', '.png', '.webp'): - raise TypeError(f'不支持的文件格式:{pic_type}。') pic_type = 'jpeg' if pic_type == '.jpg' else pic_type[1:] self.frame_ele.scroll.to_see(center=True) @@ -562,7 +567,7 @@ class ChromiumFrame(ChromiumBase): new_ele.scroll.to_see(True) top = int(self.frame_ele.style('border-top').split('px')[0]) left = int(self.frame_ele.style('border-left').split('px')[0]) - r = self._target_page.get_screenshot(path=path, as_bytes=as_bytes, as_base64=as_base64, + r = self._target_page.get_screenshot(path=path, name=name, as_bytes=as_bytes, as_base64=as_base64, left_top=(cx + left, cy + top), right_bottom=(cx + w + left, cy + h + top)) self._target_page.remove_ele(new_ele) return r diff --git a/DrissionPage/chromium_frame.pyi b/DrissionPage/chromium_frame.pyi index e310dc6..3bf2f12 100644 --- a/DrissionPage/chromium_frame.pyi +++ b/DrissionPage/chromium_frame.pyi @@ -174,11 +174,11 @@ class ChromiumFrame(ChromiumBase): timeout: float = None, ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ... - def get_screenshot(self, path: [str, Path] = None, + def get_screenshot(self, path: [str, Path] = None, name: str = None, as_bytes: [bool, str] = None, as_base64: [bool, str] = None) -> Union[str, bytes]: ... - def _get_screenshot(self, path: [str, Path] = None, + def _get_screenshot(self, path: [str, Path] = None, name: str = None, as_bytes: [bool, str] = None, as_base64: [bool, str] = None, full_page: bool = False, left_top: Tuple[int, int] = None,