mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
246 lines
9.4 KiB
Python
246 lines
9.4 KiB
Python
# -*- coding:utf-8 -*-
|
||
"""
|
||
@Author : g1879
|
||
@Contact : g1879@qq.com
|
||
@File : mix_page.py
|
||
"""
|
||
from typing import Union, List
|
||
from urllib import parse
|
||
|
||
from requests import Response
|
||
from requests_html import HTMLSession
|
||
from selenium.webdriver.chrome.webdriver import WebDriver
|
||
|
||
from .drission import Drission
|
||
from .driver_element import DriverElement
|
||
from .driver_page import DriverPage
|
||
from .session_element import SessionElement
|
||
from .session_page import SessionPage
|
||
|
||
|
||
class Null(object):
|
||
"""避免IDE警告未调用超类初始化函数而引入的无用类"""
|
||
|
||
def __init__(self):
|
||
pass
|
||
|
||
|
||
class MixPage(Null, SessionPage, DriverPage):
|
||
"""MixPage封装了页面操作的常用功能,可在selenium(d模式)和requests(s模式)间无缝切换。
|
||
切换的时候会自动同步cookies,兼顾selenium的易用性和requests的高性能。
|
||
获取信息功能为两种模式共有,操作页面元素功能只有d模式有。调用某种模式独有的功能,会自动切换到该模式。
|
||
这些功能由DriverPage和SessionPage类实现。
|
||
"""
|
||
|
||
def __init__(self, drission: Drission, mode='d', timeout: float = 10):
|
||
"""初始化函数
|
||
:param drission: 整合了driver和session的类
|
||
:param mode: 默认使用selenium的d模式
|
||
"""
|
||
super().__init__()
|
||
self._drission = drission
|
||
self._session = None
|
||
self._driver = None
|
||
self._url = None
|
||
self._response = None
|
||
self.timeout = timeout
|
||
self._url_available = None
|
||
self._mode = mode
|
||
if mode == 's':
|
||
self._session = self._drission.session
|
||
elif mode == 'd':
|
||
self._driver = self._drission.driver
|
||
else:
|
||
raise KeyError("mode must be 'd' or 's'.")
|
||
|
||
@property
|
||
def url(self) -> str:
|
||
"""根据模式获取当前活动的url"""
|
||
if self._mode == 'd':
|
||
return super(SessionPage, self).url
|
||
elif self._mode == 's':
|
||
return self.session_url
|
||
|
||
@property
|
||
def session_url(self) -> str:
|
||
return self._response.url if self._response else None
|
||
|
||
@property
|
||
def mode(self) -> str:
|
||
"""返回当前模式
|
||
:return: 's'或'd'
|
||
"""
|
||
return self._mode
|
||
|
||
def change_mode(self, mode: str = None, go: bool = True) -> None:
|
||
"""切换模式,接收字符串s或d,除此以外的字符串会切换为d模式
|
||
切换时会把当前模式的cookies复制到目标模式
|
||
切换后,如果go是True,调用相应的get函数使访问的页面同步
|
||
:param mode: 模式字符串
|
||
:param go: 是否跳转到原模式的url
|
||
"""
|
||
if mode == self._mode:
|
||
return
|
||
self._mode = 's' if self._mode == 'd' else 'd'
|
||
if self._mode == 'd': # s转d
|
||
self._url = super(SessionPage, self).url
|
||
if self.session_url:
|
||
self.cookies_to_driver(self.session_url)
|
||
if go:
|
||
self.get(self.session_url)
|
||
elif self._mode == 's': # d转s
|
||
self._url = self.session_url
|
||
if self._session is None:
|
||
self._session = self._drission.session
|
||
if self._driver:
|
||
self.cookies_to_session()
|
||
if go:
|
||
self.get(super(SessionPage, self).url)
|
||
|
||
@property
|
||
def drission(self) -> Drission:
|
||
"""返回当前使用的Dirssion对象"""
|
||
return self._drission
|
||
|
||
@property
|
||
def driver(self) -> WebDriver:
|
||
"""返回driver对象,如没有则创建
|
||
每次访问时切换到d模式,主要用于独有函数及外部调用
|
||
:return:selenium的WebDriver对象
|
||
"""
|
||
if self._driver is None:
|
||
self._driver = self._drission.driver
|
||
self.change_mode('d')
|
||
return self._driver
|
||
|
||
@property
|
||
def session(self) -> HTMLSession:
|
||
"""返回session对象,如没有则创建
|
||
每次访问时切换到s模式,主要用于独有函数及外部调用
|
||
:return:requests-html的HTMLSession对象
|
||
"""
|
||
if self._session is None:
|
||
self._session = self._drission.session
|
||
# self.change_mode('s')
|
||
return self._session
|
||
|
||
@property
|
||
def response(self) -> Response:
|
||
"""返回response对象,切换到s模式"""
|
||
self.change_mode('s')
|
||
return self._response
|
||
|
||
@property
|
||
def cookies(self) -> Union[dict, list]:
|
||
"""返回cookies,根据模式获取"""
|
||
if self._mode == 's':
|
||
return super().cookies
|
||
elif self._mode == 'd':
|
||
return super(SessionPage, self).cookies
|
||
|
||
def cookies_to_session(self, copy_user_agent: bool = False) -> None:
|
||
"""从driver复制cookies到session
|
||
:param copy_user_agent : 是否复制user agent信息
|
||
"""
|
||
self._drission.cookies_to_session(copy_user_agent)
|
||
|
||
def cookies_to_driver(self, url=None) -> None:
|
||
"""从session复制cookies到driver,chrome需要指定域才能接收cookies"""
|
||
u = url or self.session_url
|
||
self._drission.cookies_to_driver(u)
|
||
|
||
# ----------------重写SessionPage的函数-----------------------
|
||
|
||
def post(self, url: str, params: dict = None, data: dict = None, go_anyway: bool = False, **kwargs) \
|
||
-> Union[bool, None]:
|
||
"""post前先转换模式,但不跳转"""
|
||
self.change_mode('s', go=False)
|
||
return super().post(url, params, data, go_anyway, **kwargs)
|
||
|
||
# ----------------重写DriverPage的函数-----------------------
|
||
|
||
def chrome_downloading(self, download_path: str = None) -> list:
|
||
"""检查浏览器下载情况,返回正在下载的文件列表
|
||
:param download_path: 下载文件夹路径,默认读取配置信息
|
||
:return: 正在下载的文件列表
|
||
"""
|
||
try:
|
||
path = download_path or self._drission.driver_options['experimental_options']['prefs'][
|
||
'download.default_directory']
|
||
if not path:
|
||
raise KeyError
|
||
except KeyError:
|
||
raise KeyError('Download path not found.')
|
||
|
||
return super().chrome_downloading(path)
|
||
|
||
# ----------------以下为共用函数-----------------------
|
||
|
||
def get(self, url: str, params: dict = None, go_anyway=False, **kwargs) -> Union[bool, None]:
|
||
"""跳转到一个url,跳转前先同步cookies,跳转后判断目标url是否可用"""
|
||
to_url = f'{url}?{parse.urlencode(params)}' if params else url
|
||
if not url or (not go_anyway and self.url == to_url):
|
||
return
|
||
if self._mode == 'd':
|
||
super(SessionPage, self).get(url=to_url, go_anyway=go_anyway)
|
||
if self.session_url == self.url:
|
||
self._url_available = True if self._response and self._response.ok else False
|
||
else:
|
||
self._url_available = self.check_page()
|
||
return self._url_available
|
||
elif self._mode == 's':
|
||
super().get(url=to_url, go_anyway=go_anyway, **kwargs)
|
||
return self._url_available
|
||
|
||
def ele(self, loc_or_ele: Union[tuple, str, DriverElement, SessionElement], mode: str = None, timeout: float = None,
|
||
show_errmsg: bool = False) -> Union[DriverElement, SessionElement]:
|
||
"""查找一个元素,根据模式调用对应的查找函数
|
||
:param loc_or_ele: 页面元素地址
|
||
:param mode: 以某种方式查找元素,可选'single','all','visible'(d模式独有)
|
||
:param timeout: 超时时间
|
||
:param show_errmsg: 是否显示错误信息
|
||
:return: 页面元素对象,s模式下返回Element,d模式下返回WebElement
|
||
"""
|
||
if self._mode == 's':
|
||
return super().ele(loc_or_ele, mode=mode, show_errmsg=show_errmsg)
|
||
elif self._mode == 'd':
|
||
timeout = timeout or self.timeout
|
||
# return super(SessionPage, self).ele(loc_or_ele, mode=mode, timeout=timeout, show_errmsg=show_errmsg)
|
||
return DriverPage.ele(self, loc_or_ele, mode=mode, timeout=timeout, show_errmsg=show_errmsg)
|
||
|
||
def eles(self, loc_or_str: Union[tuple, str], timeout: float = None, show_errmsg: bool = False) \
|
||
-> List[DriverElement]:
|
||
"""查找符合条件的所有元素"""
|
||
if self._mode == 's':
|
||
return super().eles(loc_or_str, show_errmsg)
|
||
elif self._mode == 'd':
|
||
return super(SessionPage, self).eles(loc_or_str, timeout=timeout, show_errmsg=show_errmsg)
|
||
|
||
@property
|
||
def html(self) -> str:
|
||
"""获取页面HTML"""
|
||
if self._mode == 's':
|
||
return super().html
|
||
elif self._mode == 'd':
|
||
return super(SessionPage, self).html
|
||
|
||
@property
|
||
def title(self) -> str:
|
||
"""获取页面title"""
|
||
if self._mode == 's':
|
||
return super().title
|
||
elif self._mode == 'd':
|
||
return super(SessionPage, self).title
|
||
|
||
def close_driver(self) -> None:
|
||
"""关闭driver及浏览器,切换到s模式"""
|
||
self.change_mode('s')
|
||
self._driver = None
|
||
self.drission.close_driver()
|
||
|
||
def close_session(self) -> None:
|
||
"""关闭session,切换到d模式"""
|
||
self.change_mode('d')
|
||
self._session = None
|
||
self.drission.close_session()
|