forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauto-nav.py
197 lines (175 loc) · 7.18 KB
/
auto-nav.py
1
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
This script runs Chrome and automatically navigates through the given list of
URLs the specified number of times.
Usage: vpython3 auto-nav.py <chrome dir> <number of navigations> <url> <url> ...
Optional flags:
* --interval <seconds>, -i <seconds>: specify a number of seconds to wait
between navigations, e.g., -i=5
* --start_prompt, -s: start Chrome, then wait for the user to press Enter before
starting auto-navigation
* --exit-prompt, -e: after auto-navigation, wait for the user to press Enter
before shutting down chrome.exe
* --idlewakeups_dir: Windows only; specify the directory containing
idlewakeups.exe to print measurements taken by IdleWakeups,
e.g., --idlewakeups_dir=tools/win/IdleWakeups/x64/Debug
Optional flags to chrome.exe, example:
-- --user-data-dir=temp --disable-features=SomeFeature
Note: must be at end of command, following options terminator "--". The options
terminator stops command-line options from being interpreted as options for this
script, which would cause an unrecognized-argument error.
"""
# [VPYTHON:BEGIN]
# python_version: "3.8"
# wheel: <
# name: "infra/python/wheels/selenium-py2_py3"
# version: "version:3.14.0"
# >
# wheel: <
# name: "infra/python/wheels/urllib3-py2_py3"
# version: "version:1.24.3"
# >
# wheel: <
# name: "infra/python/wheels/psutil/${vpython_platform}"
# version: "version:5.7.2"
# >
# [VPYTHON:END]
import argparse
import os
import subprocess
import sys
import time
import urllib
try:
import psutil
from selenium import webdriver
except ImportError:
print('Error importing required modules. Run with vpython3 instead of python.')
sys.exit(1)
DEFAULT_INTERVAL = 1
EXIT_CODE_ERROR = 1
# Splits list |positional_args| into two lists: |urls| and |chrome_args|, where
# arguments starting with '-' are treated as chrome args, and the rest as URLs.
def ParsePositionalArgs(positional_args):
urls, chrome_args = [], []
for arg in positional_args:
if arg.startswith('-'):
chrome_args.append(arg)
else:
urls.append(arg)
return [urls, chrome_args]
# Returns an object containing the arguments parsed from this script's command
# line.
def ParseArgs():
# Customize usage and help to include options to be passed to chrome.exe.
usage_text = '''%(prog)s [-h] [--interval INTERVAL] [--wait]
[--idlewakeups_dir IDLEWAKEUPS_DIR]
chrome_dir num_navigations url [url ...]
[-- --chrome_option ...]'''
additional_help_text = '''optional arguments to chrome.exe, example:
-- --enable-features=MyFeature --browser-startup-dialog
Must be at end of command, following the options
terminator "--"'''
parser = argparse.ArgumentParser(
epilog=additional_help_text,
usage=usage_text,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
'chrome_dir', help='Directory containing chrome.exe and chromedriver.exe')
parser.add_argument('num_navigations',
type=int,
help='Number of times to navigate through list of URLs')
parser.add_argument('--interval',
'-i',
type=int,
help='Seconds to wait between navigations; default is 1')
parser.add_argument('--start_prompt',
'-s',
action='store_true',
help='Wait for confirmation before starting navigation')
parser.add_argument('--exit_prompt',
'-e',
action='store_true',
help='Wait for confirmation before exiting chrome.exe')
parser.add_argument(
'--idlewakeups_dir',
help='Windows only; directory containing idlewakeups.exe, if using')
parser.add_argument(
'url',
nargs='+',
help='URL(s) to navigate, separated by spaces; must include scheme, '
'e.g., "https://"')
args = parser.parse_args()
args.url, chrome_args = ParsePositionalArgs(args.url)
if not args.url:
parser.print_usage()
print(os.path.basename(__file__) + ': error: missing URL argument')
exit(EXIT_CODE_ERROR)
for url in args.url:
if not urllib.parse.urlparse(url).scheme:
print(os.path.basename(__file__) +
': error: URL is missing required scheme (e.g., "https://"): ' + url)
exit(EXIT_CODE_ERROR)
return [args, chrome_args]
# If |path| does not exist, prints a generic error plus optional |error_message|
# and exits.
def ExitIfNotFound(path, error_message=None):
if not os.path.exists(path):
print('File not found: {}.'.format(path))
if error_message:
print(error_message)
exit(EXIT_CODE_ERROR)
def main():
# Parse arguments and check that file paths received are valid.
args, chrome_args = ParseArgs()
ExitIfNotFound(os.path.join(args.chrome_dir, 'chrome.exe'),
'Build target "chrome" to generate it first.')
chromedriver_exe = os.path.join(args.chrome_dir, 'chromedriver.exe')
ExitIfNotFound(chromedriver_exe,
'Build target "chromedriver" to generate it first.')
if args.idlewakeups_dir:
idlewakeups_exe = os.path.join(args.idlewakeups_dir, 'idlewakeups.exe')
ExitIfNotFound(idlewakeups_exe)
# Start chrome.exe. Disable chrome.exe's extensive logging to make reading
# this script's output easier.
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('excludeSwitches', ['enable-logging'])
for arg in chrome_args:
chrome_options.add_argument(arg)
driver = webdriver.Chrome(os.path.abspath(chromedriver_exe),
options=chrome_options)
if args.start_prompt:
driver.get(args.url[0])
input('Press Enter to begin navigation...')
# Start IdleWakeups, if using, passing the browser process's ID as its target.
# IdleWakeups will monitor the browser process and its children. Other running
# chrome.exe processes (i.e., those not launched by this script) are excluded.
if args.idlewakeups_dir:
launched_processes = psutil.Process(
driver.service.process.pid).children(recursive=False)
if not launched_processes:
print('Error getting browser process ID for IdleWakeups.')
exit()
# Assume the first child process created by |driver| is the browser process.
idlewakeups = subprocess.Popen([
idlewakeups_exe,
str(launched_processes[0].pid), '--stop-on-exit', '--tabbed'
],
stdout=subprocess.PIPE)
# Navigate through |args.url| list |args.num_navigations| times, then close
# chrome.exe.
interval = args.interval if args.interval else DEFAULT_INTERVAL
for _ in range(args.num_navigations):
for url in args.url:
driver.get(url)
time.sleep(interval)
if args.exit_prompt:
input('Press Enter to exit...')
driver.quit()
# Print IdleWakeups' output, if using.
if args.idlewakeups_dir:
print(idlewakeups.communicate()[0])
if __name__ == '__main__':
sys.exit(main())