diff --git a/DrissionPage/chrome_element.py b/DrissionPage/chrome_element.py index 703d96e..2cabcf9 100644 --- a/DrissionPage/chrome_element.py +++ b/DrissionPage/chrome_element.py @@ -4,6 +4,7 @@ @Contact : g1879@qq.com @File : chrome_element.py """ +from pathlib import Path from typing import Union, Tuple, List from time import perf_counter @@ -197,6 +198,31 @@ function getElementPagePosition(element){ if 'exceptionDetails' in r: raise SyntaxError(r['result']['description']) + def style(self, style: str, pseudo_ele: str = '') -> str: + """返回元素样式属性值,可获取伪元素属性值 \n + :param style: 样式属性名称 + :param pseudo_ele: 伪元素名称(如有) + :return: 样式属性的值 + """ + if pseudo_ele: + pseudo_ele = f', "{pseudo_ele}"' if pseudo_ele.startswith(':') else f', "::{pseudo_ele}"' + js = f'function(){{return window.getComputedStyle(this{pseudo_ele}).getPropertyValue("{style}");}}' + return self.page.driver.Runtime.callFunctionOn(functionDeclaration=js, objectId=self._obj_id) + + def get_screenshot(self, path: [str, Path] = None, + as_bytes: [bool, str] = None) -> Union[str, bytes]: + """对当前元素截图 \n + :param path: 完整路径,后缀可选'jpg','jpeg','png','webp' + :param as_bytes: 是否已字节形式返回图片,可选'jpg','jpeg','png','webp',生效时path参数无效 + :return: 图片完整路径或字节文本 + """ + left, top = self.location.values() + height, width = self.size.values() + left_top = (left, top) + right_bottom = (left + width, top + height) + return self.page.get_screenshot(path, as_bytes=as_bytes, full_page=False, + left_top=left_top, right_bottom=right_bottom) + def click(self, by_js: bool = False) -> None: """点击元素 \n 尝试点击直到超时,若都失败就改用js点击 \n diff --git a/DrissionPage/chrome_page.py b/DrissionPage/chrome_page.py index a7e7a58..e73d177 100644 --- a/DrissionPage/chrome_page.py +++ b/DrissionPage/chrome_page.py @@ -1,5 +1,5 @@ # -*- coding:utf-8 -*- -from os import sep +from base64 import b64decode from pathlib import Path from time import perf_counter, sleep from typing import Union, Tuple, List @@ -9,7 +9,7 @@ from requests import get as requests_get from json import loads from .base import BasePage -from .common import get_loc, get_usable_path +from .common import get_loc from .drission import connect_chrome from .chrome_element import ChromeElement, ChromeScroll @@ -174,40 +174,59 @@ class ChromePage(BasePage): else: return [ChromeElement(self, node_id=i) for i in nodeIds['nodeIds']] - def screenshot(self, path: str = None, - filename: str = None, - as_bytes: bool = False, - full_page: bool = True) -> Union[str, bytes]: - """截取页面可见范围截图 \n - :param path: 保存路径 - :param filename: 图片文件名,不传入时以页面title命名 - :param as_bytes: 是否已字节形式返回图片,为True时上面两个参数失效 - :param full_page: 是否整页截图 + def get_screenshot(self, path: [str, Path] = None, + as_bytes: [bool, str] = None, + full_page: bool = False, + left_top: Tuple[int, int] = None, + right_bottom: Tuple[int, int] = None) -> Union[str, bytes]: + """对页面进行截图,可对整个网页、可见网页、指定范围截图。对可视范围外截图需要新版浏览器支持 \n + :param path: 完整路径,后缀可选'jpg','jpeg','png','webp' + :param as_bytes: 是否已字节形式返回图片,可选'jpg','jpeg','png','webp',生效时path参数无效 + :param full_page: 是否整页截图,为True截取整个网页,为False截取可视窗口 + :param left_top: 截取范围左上角坐标 + :param right_bottom: 截取范围右下角角坐标 :return: 图片完整路径或字节文本 """ - from base64 import b64decode + if as_bytes: + if as_bytes is True: + pic_type = 'png' + else: + if as_bytes not in ('jpg', 'jpeg', 'png', 'webp'): + raise ValueError("只能接收'jpg', 'jpeg', 'png', 'webp'四种格式。") + pic_type = 'jpeg' if as_bytes == 'jpg' else as_bytes + + else: + if not path: + raise ValueError('保存为文件时必须传入路径。') + path = Path(path) + 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:] + hw = self.size if full_page: vp = {'x': 0, 'y': 0, 'width': hw['width'], 'height': hw['height'], 'scale': 1} - png = self.driver.Page.captureScreenshot(captureBeyondViewport=True, clip=vp)['data'] + png = self.driver.Page.captureScreenshot(format=pic_type, captureBeyondViewport=True, clip=vp)['data'] else: - png = self.driver.Page.captureScreenshot(captureBeyondViewport=True)['data'] + if left_top and right_bottom: + x, y = left_top + w = right_bottom[0] - x + h = right_bottom[1] - y + vp = {'x': x, 'y': y, 'width': w, 'height': h, 'scale': 1} + png = self.driver.Page.captureScreenshot(format=pic_type, captureBeyondViewport=True, clip=vp)['data'] + else: + png = self.driver.Page.captureScreenshot(format=pic_type)['data'] + png = b64decode(png) if as_bytes: return png - from DataRecorder import ByteRecorder - name = filename or self.title - if not name.lower().endswith('.png'): - name = f'{name}.png' - path = Path(path or '.').absolute() - path.mkdir(parents=True, exist_ok=True) - img_path = str(get_usable_path(f'{path}{sep}{name}')) - b = ByteRecorder(img_path) - b.add_data(png) - b.record() - return img_path + path.parent.mkdir(parents=True, exist_ok=True) + with open(path, 'wb')as f: + f.write(png) + return str(path.absolute()) def scroll_to_see(self, loc_or_ele: Union[str, tuple, ChromeElement]) -> None: """滚动页面直到元素可见 \n diff --git a/requirements.txt b/requirements.txt index b76e0c2..cafa535 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,4 @@ lxml cssselect DownloadKit FlowViewer -pychrome -DataRecorder \ No newline at end of file +pychrome \ No newline at end of file