DrissionPage模块
# 网页自动化
# 介绍
网页自动化,即通过程序让浏览器自动实现平时需要我们手动才能完成的任务,模拟人工执行重复性任务。
# 方式
网页自动化的方式通常如下两种:
- 直接向服务器发送数据包,获取需要的数据。
例如Urllib、Requests等模块就用于实现该方式。
优点是轻量级、速度快、便于多线程、分布式部署。
缺点是当数据包构成复杂,或者碰到加密时,开发难度直线上升。
- 控制浏览器跟网页进行交互。
例如Selenium、Playwright等模块就是用于实现该方式。
# DrissionPage介绍
# 介绍
DrissionPage是一个基于Python的网页自动化模块,它将两种网页自动化方式进行了整合,既能控制浏览器,又能收发数据包。兼顾浏览器自动化的便利性和Requests的高效率性。
用于操作浏览器的对象叫Driver,用于管理连接会话的对象叫Session,因此二者合一的名称即是Drission,而Page表示以页面为单位使用。
支持Chromium内核浏览器(如Chrome和Edge)、electron应用。
文档地址:https://drissionpage.cn/browser_control/intro
# 主要对象
# 浏览器对象
Chromium:浏览器对象。
浏览器类用于连接浏览器、管理标签页及其它和浏览器总体有关的操作。
浏览器类相当于总管,它可以作为浏览器入口,使用它产生Tab对象去操控每个标签页。
# Page对象
ChromiumPage:能管理浏览器本身的页面对象。
ChromiumPage将浏览器对象和第一个标签页对象进行封装,用于控制浏览器。
ChromiumPage和Chromium的区别是它生成的Tab对象是ChromiumTab,不能切换模式。
WebPage:整合浏览器控制和收发数据包于一体的页面对象。
其自身及其产生的Tab对象可切换模式,既可控制浏览器,也可收发数据包。
SessionPage:用于收发数据包的页面对象。
SessionPage将requests和lxml进行封装,用于收发数据包。它把网络连接和结果解析封装成页面。操作逻辑和其它页面一致。
# Tab对象
MixTab:浏览器标签页对象。
由Chromium对象产生,一个对象控制一个实际的标签页。
ChromiumTab:浏览器标签页对象。
由ChromiumPage对象产生,和MixTab对象的区别是不可切换收发数据包模式。
# Element对象
ChromiumElement:浏览器元素对象。
SessionElement:静态元素对象。
ChromiumFrame:<iframe>元素对象,兼有标签页对象和元素特性。
ShadowRoot:shadow-root元素对象。
# 安装与导入
# 安装
pip install DrissionPage
# 导入路径
# from DrissionPage import ****:浏览器类、配置类、页面类
# from DrissionPage.errors import ****:异常
# from DrissionPage.common import ****:辅助工具
# from DrissionPage.items import ****:衍生对象,用于类型判断
2
3
4
5
6
7
8
# 基本逻辑
操作浏览器的基本逻辑有以下步骤:
- 创建浏览器对象,启动或接管浏览器。
- 获取一个Tab对象。
- 使用Tab对象获取标签页内需要的元素对象。
- 使用元素对象进行交互。
# 浏览器启动配置
**ChromiumOptions**类用于管理浏览器的初始化配置,可以手动指定配置,或从配置文件中读取配置来进行初始化。
浏览器启动后,再修改该配置没有任何效果。接管已打开的浏览器时,启动配置也是无效的。
但是可以对标签页进行临时的配置修改。
设置优先级:Tab对象设置 > Chromium对象设置 > Settings设置。
# 创建配置
类的初始化参数
read_file:是否从ini文件中读取配置信息,默认为True,为False则用默认配置创建。ini_path:指定ini文件路径,默认为None,表示则读取内置ini文件。
# 浏览器启动配置类
from DrissionPage import ChromiumOptions
# 创建浏览器配置对象
co = ChromiumOptions()
2
3
4
5
# 修改配置
# 配置对象支持链式操作,例如co.no_imgs(True).save()
# 设置浏览器可执行文件路径
co.set_browser_path("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe")
# 设置下载文件保存路径
co.set_download_path("path")
# 保存配置项到一个ini文件,传入None则保存到当前读取的配置文件
co.save("path")
# 设置用户文件夹路径,用于存储浏览器的使用痕迹、设置选项等,一般不需要指定
co.set_user_data_path("path")
# 保存配置项到固定的默认ini文件
co.save_to_default()
# 设置是否禁止加载图片
co.no_imgs(True)
# 设置是否静音
co.mute(True)
# 设置是否禁用JavaScript
co.no_js(True)
# 设置是否使用无痕模式启动
co.incognito(True)
# 设置是否使用无界面模式(无头模式)启动
co.headless(True)
# 设置是否使用全新环境启动浏览器
co.new_env(True)
# 设置是否忽略证书错误
co.ignore_certificate_errors(True)
# 设置是否自动分配端口,可以指定端口号范围
# 每个端口对应一个浏览器,设置该参数后,在创建浏览器对象时只会启动新的浏览器
co.auto_port(True)
# 是否仅连接已有浏览器,如连接浏览器失败会抛出异常,不会启动新浏览器
co.existing_only(True)
# 设置默认超时时间/页面加载超时时间/JS运行超时时间,单位为秒
# co.set_timeouts(base, page_load, script)
co.set_timeouts(base=10)
# 设置页面连接超时时的重试次数和重试间隔(秒)
co.set_retry(3, 5)
# 设置浏览器地址,支持IP:PORT格式和WS连接格式。
co.set_address("127.0.0.1:9333")
# 设置浏览器代理,该设置在浏览器启动时一次性设置,设置后不能修改,set_proxy("协议://ip:port")
co.set_proxy("http://localhost:1080")
# 设置User-Agent
co.set_user_agent(user_agent='Mozilla/5.0 (Macintos.....')
# 设置网页加载策略,无论设置哪种策略,加载时间都不会超过页面加载超时时间
# 加载策略是指强制页面停止加载的时机,如加载完DOM即停止,则不会加载图片资源,以提高自动化效率
# normal:阻塞进程,等待所有资源下载完成(默认)
# eager:DOM就绪即停止加载
# none:网页连接成功即停止加载
co.set_load_mode("normal")
# 设置浏览器内核启动参数,控制浏览器行为和初始状态co.set_argument("arg", "value")
# 带值的参数传入属性值,没有值的参数传入None,如果传入False表示删除该参数
# 例如无沙盒模式参数
co.set_argument("--no-sandbox")
# 删除浏览器内核启动参数,传入参数名即可
co.remove_argument("arg")
# 清空浏览器内核启动参数
co.clear_arguments()
# Chromium浏览器支持多用户配置,我们可以选择使用的用户配置,默认为Default
set_user("Default")
# 设置用户配置文件里的指定配置项set_pref("arg", "value")
# 隐藏是否保存密码的提示
co.set_pref("credentials_enable_service", False)
# 在当前配置对象中删除一个配置项,只能删该对象内配置的配置项
co.remove_pref("arg")
# 在用户配置文件删除一个配置项,可以删用户配置文件中存在的配置项
co.remove_pref_from_file("arg")
# 在当前配置对象中清空配置项
co.clear_prefs()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# 使用配置
# 创建浏览器对象时指定配置对象即可
browser = Chromium(co)
2
# 浏览器连接
**Chromium**类用于连接和管理浏览器,标签页的开关和获取、整体运行参数配置、浏览器信息获取都由它进行。
同一进程中每个浏览器只能有一个Chromium对象,对同一个浏览器重复使用Chromium()获取的都是同一个对象。
在使用无头模式时需注意程序关闭后其实浏览器进程还在,只是看不见。
类的初始化参数:
addr_or_opts:浏览器启动配置或接管信息。如果传入IP:端口、浏览器WS地址、端口会按地址启动或接管浏览器。
如果传入配置对象会按其配置启动或接管浏览器。
如果为None会使用默认配置文件配置启动或接管浏览器。
# 直接连接浏览器
# 导入浏览器类
from DrissionPage import Chromium
# 使用默认配置,创建浏览器对象
browser = Chromium()
2
3
4
5
创建Chromium对象时会在指定端口启动浏览器,或接管该端口已有浏览器。
默认情况下,程序使用9222端口,浏览器可执行文件路径为"chrome"。
如路径中没找到浏览器可执行文件,Windows系统下程序会在注册表中查找路径,如果都没有则需要手动配置浏览器路径。
# 指定端口或地址连接浏览器
from DrissionPage import Chromium
# 接管9333端口的浏览器,如该端口空闲,启动一个浏览器
browser = Chromium(9333)
# 与上一行效果一样
browser = Chromium('127.0.0.1:9333')
# 指定ws连接
browser = Chromium('ws://127.0.0.1:8987/devtools/browser/3e590fc5-4587-47e1-8756-cf6784f2fef3')
2
3
4
5
6
7
8
9
10
按端口号或地址接管指定端口浏览器,若端口空闲,则使用默认配置在该端口启动一个浏览器。
# 按配置文件连接浏览器
from DrissionPage import Chromium, ChromiumOptions
# 创建启动配置对象
co = ChromiumOptions()
# 设置浏览器路径
co.set_browser_path("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe")
# 指定启动配置创建浏览器对象,启动或接管浏览器
browser = Chromium(co)
2
3
4
5
6
7
8
9
10
# 浏览器对象
# 获取标签页
# latest_tab
返回最新的标签页对象或ID。
控制本地浏览器时,返回最后激活的标签页。
控制远程浏览器时,返回最后创建的标签页。
browser = Chromium()
# 单例模式下返回标签页对象,非单例模式时返回标签页ID
tab = browser.latest_tab
2
3
4
# get_tab()
获取匹配到的第一个标签页对象或标签页ID。
id_or_num为None时,条件查找参数才有效。
browser = Chromium()
# 获取列表中第一个标签页的对象
tab1 = browser.get_tab(1)
# 获取指定ID的标签页对象
tab2 = browser.get_tab('5399F4ADFE3A27503FFAA56390344EE5')
# 获取第一个url中带DrissionPage.cn的标签页对象
tab3 = browser.get_tab(url='DrissionPage.cn')
2
3
4
5
6
7
8
id_or_num:指定标签页ID或序号获取标签页对象,序号是激活顺序。
title:条件查找,模糊匹配title文本,默认为None,表示匹配所有。
url:条件查找,模糊匹配url文本,默认为None,表示匹配所有。
tab_type:条件查找,标签页类型,可用列表输入多个,如page(默认)、iframe等。
as_id:是否返回标签页ID而非对象,默认为False。
# get_tabs()
获取匹配到的所有标签页对象或标签页ID,会用列表包含并返回。
browser = Chromium()
# 获取所有url中带DrissionPage.cn的标签页对象
tabs = browser.get_tabs(url='DrissionPage.cn')
2
3
4
title:条件查找,模糊匹配title文本,默认为None,表示匹配所有。
url:条件查找,模糊匹配url文本,默认为None,表示匹配所有。
tab_type:条件查找,标签页类型,可用列表输入多个,如page(默认)、iframe等。
as_id:是否返回标签页ID而非对象,默认为False。
# 操作标签页
# new_tab()
新建标签页并返回标签页对象。
browser = Chromium()
# 新建标签页并跳转到指定URL
tab = browser.new_tab(url='https://www.baidu.com')
2
3
4
url:新建标签页时跳转的目标网址,默认为None,表示新建空白标签页。
new_window:是否在新窗口打开标签页,隐身模式下无效,默认为False。
background:是否不激活新标签页,隐身模式和访客模式及new_window为True时无效,默认为False。
new_context:是否创建独立环境,隐身模式和访客模式下无效,默认为False。
# activate_tab()
使一个标签页显示到前端,可传入标签页对象、标签页ID、标签页序号。
browser = Chromium()
# 使第一个标签页显示到前面
tab = browser.activate_tab(1)
2
3
4
# close_tabs()
关闭标签页,可指定多个,也可关闭指定标签页以外的标签页。
browser = Chromium()
# 关闭单个标签页
browser.close_tabs(browser.get_tab(1))
# 关闭多个标签页
browser.close_tabs([browser.get_tab(i) for i in range(3)])
# 关闭除指定标签页之外的所有标签页
browser.close_tabs(browser.get_tab(1), True)
2
3
4
5
6
7
8
tabs_or_ids:标签页对象或标签页ID,多个可用列表或元组传入。
others:是否关闭指定标签页之外的,默认为False。
# 浏览器信息
browser = Chromium()
# 返回浏览器默认下载路径
browser.download_path
# 返回浏览器进程PID
browser.process_id
# 返回浏览器是否仍可用
browser.states.is_alive
# 返回浏览器是否接管的,而非本程序创建的
browser.states.is_existed
# 返回浏览器是否无头模式
browser.states.is_headless
# 返回浏览器是否无痕模式
browser.states.is_incognito
# 返回浏览器所有域名的Cookies
# all_info参数:是否返回所有内容,默认False,只返回name、value、domain
browser.cookies(False)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 浏览器操作
browser = Chromium()
# 设置一个或多个cookie,需要带上domain属性
# 支持CookieJar、Cookie、list、tuple、str、dict等多种格式
browser.set.cookies({"name": "test", "value": "test", "domain": "test.cn"})
# 阻塞直到新标签页出现,可指定超时时间
browser.wait.new_tab()
# 阻塞直到浏览器一个下载任务开始,可指定超时时间
browser.wait.download_begin()
# 阻塞直到浏览器所有下载任务完成,可指定超时时间
browser.wait.downloads_done()
# 清除浏览器所有的Cookies
browser.set.cookies.clear()
# 清除浏览器缓存
browser.clear_cache()
# 关闭浏览器
browser.quit()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 标签页对象
# 标签页设置
tab = browser.latest_tab
# 单独设置页面的加载模式为normal
tab.set.load_mode.normal()
# 单独设置页面的加载模式为eager
tab.set.load_mode.eager()
# 单独设置页面的加载模式为none
tab.set.load_mode.none()
2
3
4
5
6
7
8
9
10
# 标签页模式
MixTab和WebPage有两种模式,d模式用于控制浏览器,s模式用于通过requests收发数据包。两种模式共用同一套API,但共用的API其操作对象不同。
每个标签页对象创建时都处于d模式。
d模式下
ele()方法的查找对象是浏览器的标签页,s模式下是requests的结果。因此s模式下要控制浏览器,只能调用d模式独有的功能。另外切换模式前已获取的元素对象仍可继续操作。
使用tab.change_mode()方法可以进行切换,模式切换的时候会同步登录信息。
切换到s模式后,如不再需要浏览器,可以用
close()或quit()方法关闭标签页或浏览器。标签页对象可继续用于收发数据包。
tab = browser.latest_tab
# 默认是d模式
tab.get('http://DrissionPage.cn')
# 返回当前模式字符串"d"或"s"
tab.mode
# 切换模式
# mode:传入's'或'd'可以切换到指定模式,为None则切换到另一个模式
# go:切换时是否跳转到原模式的URL,默认为True
# copy_cookies:切换时是否复制Cookies,默认为True
tab.change_mode()
2
3
4
5
6
7
8
9
10
11
12
13
# 标签页请求
# get()
使标签页跳转到指定网址。
返回布尔类型,以表示是否成功访问。
tab = browser.latest_tab
tab.get("https://www.baidu.com")
2
3
| 参数名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| url | str | 必填 | 目标URL,可指向本地文件路径。 |
| show_errmsg | bool | False | 连接出错时是否显示和抛出异常。 |
| retry | int | None | 重试次数,为None时使用页面参数,默认3。 |
| interval | float | None | 重试间隔(秒),为None时使用页面参数,默认2。 |
| timeout | float | None | 加载超时时间(秒) |
s模式参数
| 参数名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| params | dict | None | url 请求参数。 |
| data | dict str | None | 携带的数据。 |
| json | dict str | None | 要发送的 JSON 数据,会自动设置 Content-Type 为'application/json'。 |
| headers | dict | None | 请求头。 |
| cookies | dict CookieJar | None | cookies 信息。 |
| files | Any | None | 要上传的文件,可以是一个字典,其中键是文件名,值是文件对象或文件路径。 |
| auth | Any | None | 身份认证信息。 |
| allow_redirects | bool | True | 是否允许重定向。 |
| proxies | dict | None | 代理信息。 |
| hooks | Any | None | 回调方法。 |
| stream | bool | None | 是否使用流式传输。 |
| verify | bool str | None | 是否验证 SSL 证书。 |
| cert | str Tuple[str, str] | None | SSL 客户端证书文件的路径(.pem 格式),或('cert', 'key')元组。 |
# post()
使用内置的Session对象以POST方式发送请求。
返回请求结果的
Response对象。因为
post()是使用requests的post()方法发送请求,所以参数和用法与requests一致。
参数同上面get()方法的参数完全一致,且不区分s模式。
# 标签页信息
tab = browser.latest_tab
# 返回当前页面html文本
tab.html
# 把页面内容解析成json
tab.json
# 返回当前页面title文本
tab.title
# 返回当前页面UserAgent信息
tab.user_agent
# 返回当前访问的URL
tab.url
# 返回当前标签页的ID
tab.tab_id
# 返回页面是否正在加载状态
tab.states.is_loading
# 返回页面当前加载状态
# connecting: 网页连接中
# loading:表示文档还在加载中
# interactive:DOM 已加载,但资源未加载完成
# complete:所有内容已完成加载
tab.states.ready_state
# 返回页面是否存在弹出框
tab.states.has_alert
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 标签页操作
tab = browser.latest_tab
# 在浏览历史中后退若干步,默认为1步
tab.back(1)
# 在浏览历史中前进若干步,默认为1步
tab.forward(1)
# 刷新当前页面
tab.refresh()
# 强制停止当前页面加载
tab.stop_loading()
# 关闭与页面连接,然后重建一个新连接,断开连接可释放内存
tab.reconnect()
# 关闭标签页
tab.close()
# 阻塞直到页面进入加载状态
tab.wait.load_start()
# 阻塞直到页面文档加载完成
tab.wait.doc_loaded()
# 阻塞直到指定元素被加载到DOM,成功则返回
# 可指定元素对象或定位符,可用列表等待多个
tab.wait.eles_loaded("#test")
# 阻塞直到指定元素已加载并变成显示状态
# 可指定元素对象或定位符,可用列表等待多个
tab.wait.ele_displayed("#test")
# 阻塞直到指定元素已加载变成隐藏状态
# 可指定元素对象或定位符,可用列表等待多个
tab.wait.ele_hidden("#test")
# 阻塞直到一指定元素从DOM中被删除
# 可指定元素对象或定位符,可用列表等待多个
tab.wait.ele_deleted("#test")
# 阻塞直到标题变成包含或不包含指定文本
# text:用于识别的文本
# exclude:是否排除,默认为False
tab.wait.title_change("test")
# 阻塞直到URL变成包含或不包含指定文本
# text:用于识别的文本
# exclude:是否排除,默认为False
tab.wait.url_change("test")
# 等待弹出框被关闭
tab.wait.alert_closed()
# 对页面或元素进行截图,可对整个网页、可见网页、指定范围截图
# 还可指定截图保存到本地、返回bytes、返回base64
tab.get_screenshot(path='./tmp/', name='pic.jpg', full_page=True)
# 把当前页面保存为文件,同时返回保存的内容
# 如果path和name参数都为None,则只返回内容
tab.save("path", "name")
# 忽略指定URL的连接
# 可使用元组或列表传入多个,可用*通配符,传入None时清空已设置的项
tab.blocked_urls('*.css*')
# 设置标签页Cookie
tab.set.cookies()
# 清除标签页所有Cookies
tab.set.cookies.clear()
# 删除标签页指定cookie
tab.set.cookies.remove()
# 清除标签页缓存
tab.clear_cache()
# 使窗口最大化
tab.set.window.max()
# 使窗口最小化
tab.set.window.mini()
# 使窗口切换到全屏模式
tab.set.window.full()
# 设置窗口大小到指定大小,整数类型
tab.set.window.size(宽度, 高度)
# 设置窗口位置
tab.set.window.location(水平位置, 垂直位置)
# 隐藏当前浏览器窗口
tab.set.window.hide()
# 显示当前浏览器窗口
tab. set.window.show()
# 向下滚动若干像素
tab.scroll.down(滚动像素)
# 向上滚动若干像素
tab.scroll.up(滚动像素)
# 滚动页面到顶部位置
tab.scroll.to_top()
# 滚动页面到垂直居中位置
scroll.to_half()
# 滚动页面到底部位置
tab.scroll.to_bottom()
# 滚动页面指定位置
tab.scroll.to_location(水平位置, 垂直位置)
# 滚动页面直到元素可见
# loc_or_ele:元素的定位信息,可以是元素、定位符
# center:是否尽量滚动到页面正中,默认为None,表示如果被遮挡则滚动到页面正中
tab.scroll.to_see(None)
# 是否开启平滑滚动,建议用此方法为网页关闭平滑滚动,默认True
tab.set.scroll.smooth(True)
# 处理提示框
# accept:True表示确认(默认),False表示取消,None不会按按钮但依然返回文本值
# send:处理prompt提示框时输入指定文本
# timeout:等待提示框出现的超时时间(秒),为None时使用页面整体超时时间
# next_one:是否处理下一个出现的弹窗,为True时timeout参数无效
tab.handle_alert()
# 设置自动处理TAB的确认框
# on_off:是否开启,默认True
# accept:True表示确认(默认),False表示取消
tab.set.auto_handle_alert()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# 动作链
动作链可以在浏览器上完成一系列交互行为,如鼠标移动、鼠标点击、键盘输入等,浏览器页面对象都支持使用动作链。
这些操作皆为模拟,真正的鼠标不会移动,因此可以多个标签页同时操作。
相关链接:https://drissionpage.cn/browser_control/actions
# 查找元素
# 定位符介绍
DrissionPage提供一套简洁易用的语法,用于快速定位元素,并且内置等待功能、支持链式查找,减少了代码的复杂性。
同时也兼容CSS选择器、Xpath和Selenium原生的loc元组。
# 函数方法
.ele():根据条件定位元素,返回匹配到的第一个元素对象。
.eles():根据条件定位元素,用列表返回匹配到的所有元素对象。
DrissionPage中所有页面对象和元素对象,都可以链式的在自己内部查找元素。元素对象还能以自己为基准,相对定位其它元素。
# 即可在Tab标签页对象中查找,也可以在Ele元素对象中查找。
tab.ele().ele()...
2
# 匹配符号
@单属性匹配符
单个@在只以一个属性作为匹配条件时使用,以'@'开头,后面跟属性名称。
# 例如查找包含id属性的元素
e = tab.ele("@id")
2
@@多属性与匹配符
当需要多个条件同时来确定一个元素时,每个属性用'@@'开头。
# 例如查找class为test并且文本为"hello"的元素
e = tab.ele("@@class=test@@text()=hello")
2
@|多属性或匹配符
当需要以或关系条件查找元素时,每个属性用'@|'开头。
# 例如查找id为one或two的元素
e = tab.ele("@|id=one@|id=two")
2
@!否定匹配符
当需要通过条件否定排除元素时,可以使用'@!'匹配符。
可与
@@和@|混合使用。
# 获取第一个ID不等于one的元素
ele = tab.ele("@!id=one")
# 匹配class等于test并且id不等于one的元素
tab.ele("@@class=test@!id=one")
2
3
4
5
注意
@@和@|不能同时出现的查找语句中,即一个查找语句只能是与关系或者或关系。
如果匹配文本或属性中出现@@、@|、@!等字符串时,不能使用多属性匹配,需改用xpath的方式。
# 匹配模式
匹配模式指某个查询中匹配条件的方式,有精确匹配、模糊匹配、匹配开头、匹配结尾四种。
=精确匹配
:模糊匹配
^匹配开头
$匹配结尾
# 使用方法
# 通过元素名定位,只有语句放在条件最前面时生效
# "tag:标签名"、"tag=标签名"、"@tag()=标签名"效果一致
e = tab.ele("tag:div")
# 通过元素ID定位,"@id=元素ID"
# 可以简写为"#ID",但只在语句最前面且单独使用时生效
e = tab.ele("#one")
# 通过元素属性定位,"@属性名"、"@属性名=值"
e = tab.ele("@name")
e = tab.ele("@name=hello")
# 通过元素文本定位,"@text()=文本"
# 可简写为"文本"、"text:文本"、"text=文本",但只语句在最前面且单独使用时生效
e = tab.ele("我是文本")
# 通过CSS选择器来匹配
# "css=语法"与"css:语法"效果一致
e = tab.ele("css=.div")
# 通过xpath匹配
# "xpath=语法"与"xpath:语法"效果一致
e = tab.ele('xpath://div')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 元素对象
# 元素相对定位
DrissionPage支持按照条件获取元素对象的直接子节点、同级节点、祖先元素、文档前后节点等。
# 获取父级节点
# 可以指定第几级父节点,或者用定位符在祖先节点中进行筛选
e.parent(3) # 获取第三个父级标签
e.parent("tag:p") # 获取父级第一个p标签
e.parent("tag:p", 3) # 获取父级第三个p标签
# 获取直接子节点
# 可以指定第几级子节点,或者用定位符在子节点中进行筛选
e.child("tag:p")
# 获取所有符合条件的子节点
e.children("tag:p")
# 返回当前元素前面或后面的某一个同级节点
# 可以指定第几个元素,或者用定位符在前面或后面同级节点中进行筛选
e.prev("tag:p")
e.next("tag:p")
# 获取当前元素前面或后面所有符合条件的同级节点
e.prevs("tag:p")
e.nexts("tag:p")
# 返回当前元素前面或后面的某一个节点(不限同级)
e.before("tag:p")
e.after("tag:p")
# 获取当前元素前面或后面所有符合条件的节点(不限同级)
e.befores("tag:p")
e.afters("tag:p")
# 前面是基于DOM的相对定位方式,DrissionPage还支持基于视觉相对定位,但需要在浏览器模式下才支持
# 获取当前元素上下左右的可见元素,可用像素距离或者定位符来筛选
e.north(30) # 上
e.south(30) # 下
e.west(30) # 左
e.east(30) # 右
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 元素交互
# 左键点击元素,可选择模拟点击或JS点击,可简化为e.click()
# by_js:为None时,如果元素被遮挡用JS点击,否则用模拟点击。为True时用JS点击,为False时被遮挡也会强制模拟点击(默认)
e.click()
e.click.left()
# 右键点击元素
e.click.right()
# 中键点击元素,默认返回新出现的Tab对象
e.click.middle()
# 多次左键点击元素,可指定次数,默认2次
e.click.multi()
# 带偏移量点击元素,偏移量相对于元素左上角坐标
# x,y:相对元素左上角坐标的x和y轴偏移量,向下向右为正
# button:要点击的键,传入'left'、'right'、'middle'、'back'、'forward'
# count:点击次数
e.click.at(50, -50) # 点击元素右上方 50*50 的位置
e.click.at(offset_x=50) # 点击元素上中部,x相对左上角向右偏移50,y保持在元素中点
# 用于点击文件选择框元素,并把指定的文件路径添加到网页
e.click.to_upload("文件路径")
# 点击元素并等待新Tab对象返回
e.click.for_new_tab()
# 用于清空元素文本
# by_js:是否用JS方式清空,默认为False
# 模拟按键方式会自动输入ctrl-a-del组合键来清除文本框,JS方式则直接把元素value属性设置为空
e.clear()
# 向元素输入文本或组合键,也可用于输入文件路径到上传控件
# vals:文本值或按键组合
# clear:输入前是否清空文本框,默认为False
# by_js:是否用JS方式输入,为True时不能输入组合键,默认为False
e.input("hello")
# 使用组合键或要传入特殊按键时,要导入按键类Keys
from DrissionPage.common import Keys
e.input(Keys.CTRL_A) # 常用组合键
e.input((Keys.CTRL, 'a', Keys.DEL)) # 自定义组合键
# 使元素获取焦点
e.focus()
# 拖拽元素到相对于当前的一个新位置,坐标向下向右为正,可以设置速度
# e.drag(x, y, 拖动用时(秒))
e.drag(50, 50, 1) # # 拖动当前元素到距离50*50的位置,用时1秒
# 拖拽元素到另一个元素上或一个网页坐标上
# e.drag_to(另一个元素对象或网页坐标元组, 拖动用时(秒))
e1.drag_to(e2) # 把e1拖拽到e2上
e1.drag_to((50, 50)) # 把e1拖拽到网页50,50的位置
# 模拟鼠标悬停在元素上,默认停留在元素中心
# 可接受偏移量,偏移量相对于元素左上角坐标,向下向右为正
e.hover(x, y)
# 设置元素属性
e.set.attr("name", "value")
# 删除元素属性
e.remove_attr("name")
# 设置元素value值
e.set.value("value")
# 选中或取消选中元素
# uncheck:是否取消选中,默认为False
# by_js:是否用JS方式选择,默认为False
e.check()
# 元素滚动
e.scroll.to_top() # 滚动到顶部
e.scroll.to_bottom() # 滚动到底部
e.scroll.to_leftmost() # 滚动到最左边
e.scroll.to_rightmost() # 滚动到最右边
e.scroll.up() # 向上滚动 200 像素
e.scroll.down(200) # 向下滚动 200 像素
e.scroll.to_location(100, 300) # 滚动到指定位置
e.scroll.to_see() # 滚动页面使自己可见
# 按文本/Value属性/序号/定位符/元素对象来选择列表项,传入列表可选择多项
e.select.by_text("male") # 按文本,可简写为select()
e.select.by_value("male") # 按Value值
e.select.by_index(3) # 按序号
select.by_locator("#optone") # 按定位符
e.select.by_option(optele) # 按元素对象
# 按文本/Value属性/序号/元素对象来取消选择列表项,传入列表可取消选择多项
e.select.cancel_by_text("male") # 按文本
e.select.cancel_by_value("male") # 按Value值
e.select.cancel_by_index(3) # 按序号
e.select.cancel_by_locator("#optone") # 按定位符
e.select.cancel_by_option(optele) # 按元素对象
# 全选所有项,多选列表才有效
e.select.all()
# 取消所有项选中状态,多选列表才有效
e.select.clear()
# 反选,多选列表才有效
e.select.invert()
# 返回当前列表元素所有选项元素对象
e.select.options
# 返回当前元素选中的选项(单选列表)
e.select.selected_option
# 当前元素所有选中的选项(多选列表)
e.select.selected_options
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 元素信息
# 返回元素的标签名
e.tag
# 返回元素的HTML文本
e.html
# 返回元素内所有文本组合成的字符串
e.text
# 返回元素内未经处理的原始文本
e.raw_text
# 返回元素内所有直接子节点的文本,包括元素和文本节点
e.texts()
# 以列表形式返回元素内的注释
e.comments
# 以字典形式返回元素所有属性及值
e.attrs
# 返回元素指定属性名的值
e.attr("name")
# 返回元素的Value值
e.value
# 返回元素href属性或src属性的值,没有则返回None
e.link
# 以元组形式返回元素左上角在整个页面中的坐标
e.rect.location
# 以元组形式返回click()元素点击点在整个页面中的坐标,位于元素中上部
e.rect.click_point
# 以布尔值方式返回元素是否在视口中可被点击
e.states.is_in_viewport
# 以布尔值方式返回元素是否整个显示在视口中
e.states.is_whole_in_viewport
# 返回元素是否可被模拟点击,从是否有大小、是否可用、是否显示、是否响应点击判断,不判断是否被遮挡
states.is_clickable
# 以布尔值形式返回当前元素是否仍可用,用于判断d模式下是否因页面刷新而导致元素失效
e.states.is_alive
# 以布尔值返回表单单选或多选元素是否选中
e.states.is_checked
# 以布尔值返回Select元素中的项是否选中
e.states.is_selected
# 以布尔值返回元素是否可见
e.states.is_displayed
# 返回当前元素在页面中Xpath的绝对路径
e.xpath
# 返回当前元素在页面中CSS选择器的绝对路径
e.css_path
# 元素列表批量获取信息
# 通过eles()返回的列表,可以调用get属性的方法来批量获取指定信息
eles('tag:a').get.texts()
eles('tag:a').get.attrs()
eles('tag:a').get.links()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 使用例子
# 自动注册某网站
import time
import random
from DrissionPage import Chromium, ChromiumOptions
# 创建启动配置对象
co = ChromiumOptions()
# 设置浏览器路径
co.set_browser_path("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe")
# 设置总是打开新浏览器
co.auto_port()
# 设置无痕模式
co.incognito()
# 启动连接浏览器
browser = Chromium(co)
# 跳转到三毛机场注册网址
tab = browser.latest_tab
tab.get("https://g-1.smjcdh.top/#/register")
# 点击进入按钮
tab.ele("#setCookieBtn").click()
print(f"正在进入注册网址...")
# 随机邮箱、密码
email = "".join([str(random.randint(0, 9)) for i in range(10)]) + "@qq.com"
passwd = "qwe" + "".join([str(random.randint(0, 9)) for i in range(6)])
print(f"生成账号密码:{email}----{passwd}")
# 输入邮箱、密码
tab.ele("@placeholder=邮箱").input(email)
[i.input(passwd) for i in tab.eles("@|placeholder=密码@|placeholder=再次输入密码")]
# 点击注册,有验证所以需要模拟动作链
time.sleep(random.randint(1, 2))
regist_ele = tab.ele("@@class=n-button__content@@text():注册").click()
# 判断是否注册成功
if tab.ele(".=n-message__content").text == "注册成功":
print("注册成功!")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 自动爬取京东商品信息
import re
import time
from urllib.parse import quote
from DrissionPage import Chromium, ChromiumOptions
keyword = "椅子"
search_url = f"https://search.jd.com/Search?keyword=" + quote(keyword)
# 创建启动配置对象
co = ChromiumOptions()
# 设置浏览器路径
co.set_browser_path("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe")
# 启动连接浏览器
browser = Chromium(co)
# 跳转到京东进行登录
tab = browser.latest_tab
def log(text):
print(f'[{time.strftime("%Y-%m-%d %H:%M:%S")}] {text}')
def login():
tab.get("https://www.jd.com/")
# 等待1秒如果没有跳转到登录页面,并且未登录则点击登录按钮
time.sleep(1)
if tab.title == "京东-欢迎登录":
log("已自动跳转到登录界面,等待用户登录")
elif tab.ele("@class=link-login", timeout=0):
tab.ele("@class=link-login").click()
log("未自动跳转到登录界面,已点击打开登录框并等待用户登录")
# 等待5分钟用户登录
if tab.wait.eles_loaded("@class=nickname", timeout=300):
log("用户已登录")
else:
log("用户登录超时,请重新运行程序")
quit()
def jump_scroll(page_num):
# 判断是否已在检索页面检索,不在则跳转
if not tab.url.startswith(search_url):
tab.get(search_url)
log("已跳转到检索页面")
# 如果未按销量排序,则单击按销量进行排序
sort_ele = tab.eles("@@class^_sort-tag-inner").filter_one.text("销量").parent()
if "_sort-tag-button__active" not in sort_ele.attr("class"):
sort_ele.click()
log("已按销量进行排序")
# 跳转到指定页数
tab.ele("@class^_pagination_toPageNum").ele("tag=input").input(str(page_num) + "\n")
log(f"已转到第 {page_num} 页")
# 等待加载
time.sleep(0.2)
tab.wait.eles_loaded("@class^_goodsContainer")
# 滚动直到能看到分页器
tab.set.scroll.smooth(True)
pagele = tab.ele("@class^_pagiContainer")
log("正在进行滚动...")
while not pagele.states.is_whole_in_viewport:
tab.scroll.down(800)
log("滚动完毕!")
def scrapy_page_data():
log("开始爬取数据...")
# 获取商品信息
card_eles = tab.ele("@class^_goodsContainer").children("@_card^")
for i in card_eles:
title = i.ele("@class^_goods_title").ele("@title").text
selling_point = set(re.split("[\n|]", i.ele("@class^_goods_title").next().text))
volume = [v.attr("title") for v in i.ele("@class^_goods_volume").eles("@title")]
shop_name = i.ele("@class^_shopFloor").text
data = {"title": title, "selling_point": list(selling_point), "volume": volume, "shop_name": shop_name}
print(data)
if __name__ == "__main__":
login()
for page in range(3):
jump_scroll(page + 1)
scrapy_page_data()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91