requestium 0.5.1__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {requestium-0.5.1 → requestium-0.7.0}/LICENSE +1 -0
- {requestium-0.5.1/requestium.egg-info → requestium-0.7.0}/PKG-INFO +95 -118
- {requestium-0.5.1 → requestium-0.7.0}/README.md +87 -69
- {requestium-0.5.1 → requestium-0.7.0}/pyproject.toml +24 -20
- {requestium-0.5.1 → requestium-0.7.0}/requestium/__init__.py +1 -1
- {requestium-0.5.1 → requestium-0.7.0}/requestium/requestium_mixin.py +13 -13
- {requestium-0.5.1 → requestium-0.7.0}/requestium/requestium_response.py +1 -1
- requestium-0.7.0/requestium/requestium_session.py +234 -0
- {requestium-0.5.1 → requestium-0.7.0/requestium.egg-info}/PKG-INFO +95 -118
- {requestium-0.5.1 → requestium-0.7.0}/requestium.egg-info/SOURCES.txt +6 -0
- requestium-0.7.0/requestium.egg-info/requires.txt +4 -0
- requestium-0.7.0/tests/test_add_cookie.py +124 -0
- requestium-0.7.0/tests/test_cookies.py +144 -0
- requestium-0.7.0/tests/test_driver_parsing.py +48 -0
- requestium-0.7.0/tests/test_ensure_element.py +197 -0
- requestium-0.7.0/tests/test_mixin.py +91 -0
- requestium-0.7.0/tests/test_proxy.py +53 -0
- requestium-0.7.0/tests/test_remote_driver.py +98 -0
- requestium-0.7.0/tests/test_response_parsing.py +107 -0
- requestium-0.7.0/tests/test_session.py +173 -0
- requestium-0.7.0/tests/test_user_agent.py +81 -0
- requestium-0.5.1/requestium/requestium_session.py +0 -163
- requestium-0.5.1/requestium.egg-info/requires.txt +0 -15
- requestium-0.5.1/tests/test_cookies.py +0 -95
- requestium-0.5.1/tests/test_mixin.py +0 -118
- requestium-0.5.1/tests/test_session.py +0 -92
- requestium-0.5.1/tests/test_user_agent.py +0 -34
- {requestium-0.5.1 → requestium-0.7.0}/requestium/requestium.py +0 -0
- {requestium-0.5.1 → requestium-0.7.0}/requestium.egg-info/dependency_links.txt +0 -0
- {requestium-0.5.1 → requestium-0.7.0}/requestium.egg-info/top_level.txt +0 -0
- {requestium-0.5.1 → requestium-0.7.0}/setup.cfg +0 -0
|
@@ -1,45 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: requestium
|
|
3
|
-
Version: 0.
|
|
4
|
-
Author
|
|
5
|
-
Maintainer-email: Judson Neer <
|
|
6
|
-
License: BSD
|
|
7
|
-
|
|
8
|
-
Copyright (c) 2017, Tryolabs
|
|
9
|
-
All rights reserved.
|
|
10
|
-
|
|
11
|
-
Redistribution and use in source and binary forms, with or without
|
|
12
|
-
modification, are permitted provided that the following conditions are met:
|
|
13
|
-
|
|
14
|
-
* Redistributions of source code must retain the above copyright notice, this
|
|
15
|
-
list of conditions and the following disclaimer.
|
|
16
|
-
|
|
17
|
-
* Redistributions in binary form must reproduce the above copyright notice,
|
|
18
|
-
this list of conditions and the following disclaimer in the documentation
|
|
19
|
-
and/or other materials provided with the distribution.
|
|
20
|
-
|
|
21
|
-
* Neither the name of the copyright holder nor the names of its
|
|
22
|
-
contributors may be used to endorse or promote products derived from
|
|
23
|
-
this software without specific prior written permission.
|
|
24
|
-
|
|
25
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
26
|
-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
27
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
28
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
29
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
30
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
31
|
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
32
|
-
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
33
|
-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
34
|
-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
35
|
-
|
|
36
|
-
Project-URL: source, https://github.com/tryolabs/requestium
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Author: Joaquin Alori
|
|
5
|
+
Maintainer-email: Judson Neer <judson.neer@gmail.com>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: source, https://github.com/lordjabez/requestium
|
|
37
8
|
Project-URL: download, https://pypi.org/project/requestium/#files
|
|
38
|
-
Project-URL: issues, https://github.com/
|
|
9
|
+
Project-URL: issues, https://github.com/lordjabez/requestium/issues
|
|
39
10
|
Classifier: Development Status :: 4 - Beta
|
|
40
11
|
Classifier: Intended Audience :: Developers
|
|
41
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
42
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
43
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
44
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
45
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
@@ -53,23 +22,13 @@ Classifier: Environment :: Web Environment
|
|
|
53
22
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
54
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
55
24
|
Classifier: Topic :: Software Development :: Testing
|
|
56
|
-
Requires-Python: >=3.
|
|
25
|
+
Requires-Python: >=3.11
|
|
57
26
|
Description-Content-Type: text/markdown
|
|
58
27
|
License-File: LICENSE
|
|
59
|
-
Requires-Dist: parsel>=1.
|
|
28
|
+
Requires-Dist: parsel>=1.8
|
|
60
29
|
Requires-Dist: requests>=2.27
|
|
61
30
|
Requires-Dist: selenium>=4.32
|
|
62
31
|
Requires-Dist: tldextract>=5.3
|
|
63
|
-
Provides-Extra: dev
|
|
64
|
-
Requires-Dist: bandit[sarif]==1.9.2; extra == "dev"
|
|
65
|
-
Requires-Dist: mypy==1.19.1; extra == "dev"
|
|
66
|
-
Requires-Dist: pre-commit~=4.5.0; extra == "dev"
|
|
67
|
-
Requires-Dist: pytest-cov~=7.0.0; extra == "dev"
|
|
68
|
-
Requires-Dist: pytest-xdist~=3.8.0; extra == "dev"
|
|
69
|
-
Requires-Dist: pytest~=9.0.0; extra == "dev"
|
|
70
|
-
Requires-Dist: ruff==0.14.11; extra == "dev"
|
|
71
|
-
Requires-Dist: ssort==0.16.0; extra == "dev"
|
|
72
|
-
Requires-Dist: types-requests==2.32.4.20260107; extra == "dev"
|
|
73
32
|
Dynamic: license-file
|
|
74
33
|
|
|
75
34
|

|
|
@@ -78,18 +37,17 @@ Dynamic: license-file
|
|
|
78
37
|
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
79
38
|
[](https://pypi.org/project/requestium/)
|
|
80
39
|
[](https://pypi.org/project/requestium/)
|
|
81
|
-
[](https://htmlpreview.github.io/?https://github.com/lordjabez/requestium/blob/python-coverage-comment-action-data/htmlcov/index.html)
|
|
41
|
+
[](https://github.com/lordjabez/requestium/actions/workflows/python.yml)
|
|
83
42
|
|
|
84
|
-
Requestium is a Python library that merges the power of [Requests](https://github.com/requests/requests), [Selenium](https://github.com/SeleniumHQ/selenium), and [Parsel](https://github.com/scrapy/parsel) into a single integrated tool for
|
|
43
|
+
Requestium is a Python library that merges the power of [Requests](https://github.com/requests/requests), [Selenium](https://github.com/SeleniumHQ/selenium), and [Parsel](https://github.com/scrapy/parsel) into a single integrated tool for automating web actions.
|
|
85
44
|
|
|
86
45
|
The library was created for writing web automation scripts that are written using mostly Requests but that are able to seamlessly switch to Selenium for the JavaScript heavy parts of the website, while maintaining the session.
|
|
87
46
|
|
|
88
47
|
Requestium adds independent improvements to both Requests and Selenium, and every new feature is lazily evaluated, so its useful even if writing scripts that use only Requests or Selenium.
|
|
89
48
|
|
|
90
|
-
Read more about the motivation behind creating this library in this [blopost](https://tryolabs.com/blog/2017/11/22/requestium-integration-layer-requests-selenium-web-automation/).
|
|
91
|
-
|
|
92
49
|
## Features
|
|
50
|
+
|
|
93
51
|
- Enables switching between a Requests' Session and a Selenium webdriver while maintaining the current web session.
|
|
94
52
|
- Integrates Parsel's parser into the library, making xpath, css, and regex much cleaner to write.
|
|
95
53
|
- Improves Selenium's handling of dynamically loading elements.
|
|
@@ -98,19 +56,21 @@ Read more about the motivation behind creating this library in this [blopost](ht
|
|
|
98
56
|
- Supports Chromedriver natively plus adding a custom webdriver.
|
|
99
57
|
|
|
100
58
|
## Installation
|
|
59
|
+
|
|
101
60
|
```bash
|
|
102
61
|
pip install requestium
|
|
103
62
|
```
|
|
104
63
|
|
|
105
|
-
|
|
64
|
+
Selenium 4.6+ includes Selenium Manager, which downloads the matching driver (such as Chromedriver) automatically, so you don't need to install one yourself. If you prefer to manage the driver yourself, download it and pass its location with the `webdriver_path` argument.
|
|
106
65
|
|
|
107
66
|
## Usage
|
|
108
67
|
First create a session as you would do on Requests, and optionally add arguments for the web-driver if you plan to use one.
|
|
68
|
+
|
|
109
69
|
```python
|
|
110
70
|
from requestium import Session, Keys
|
|
111
71
|
|
|
112
|
-
options = {
|
|
113
|
-
s = Session(webdriver_path=
|
|
72
|
+
options = {"arguments": ["headless"]}
|
|
73
|
+
s = Session(webdriver_path="./chromedriver", default_timeout=15, webdriver_options=options)
|
|
114
74
|
```
|
|
115
75
|
|
|
116
76
|
Since headless mode is common, there's a shortcut for it by specifying `headless=True`.
|
|
@@ -118,7 +78,7 @@ Since headless mode is common, there's a shortcut for it by specifying `headless
|
|
|
118
78
|
```python
|
|
119
79
|
from requestium import Session, Keys
|
|
120
80
|
|
|
121
|
-
s = Session(webdriver_path=
|
|
81
|
+
s = Session(webdriver_path="./chromedriver", headless=True)
|
|
122
82
|
```
|
|
123
83
|
|
|
124
84
|
You can also create a Selenium webdriver outside Requestium and have it use that instead:
|
|
@@ -132,7 +92,19 @@ firefox_driver = webdriver.Firefox()
|
|
|
132
92
|
s = Session(driver=firefox_driver)
|
|
133
93
|
```
|
|
134
94
|
|
|
135
|
-
|
|
95
|
+
A remote webdriver works too, with all the `ensure_*` and xpath/css/re helpers:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from selenium import webdriver
|
|
99
|
+
from requestium import Session
|
|
100
|
+
|
|
101
|
+
options = webdriver.ChromeOptions()
|
|
102
|
+
remote_driver = webdriver.Remote(command_executor="http://localhost:4444/wd/hub", options=options)
|
|
103
|
+
|
|
104
|
+
s = Session(driver=remote_driver)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
You can also pass an instance of a 3rd party webdriver class, such as Chrome from [Selenium-Wire](https://github.com/wkeeling/selenium-wire), which lets you get the XHR requests of a web page. When `driver` is given, `webdriver_path` is ignored:
|
|
136
108
|
|
|
137
109
|
```python
|
|
138
110
|
from seleniumwire import webdriver
|
|
@@ -140,41 +112,45 @@ from requestium import Session, Keys
|
|
|
140
112
|
|
|
141
113
|
seleniumwire_driver = webdriver.Chrome()
|
|
142
114
|
|
|
143
|
-
s = Session(
|
|
144
|
-
|
|
115
|
+
s = Session(driver=seleniumwire_driver)
|
|
145
116
|
```
|
|
146
117
|
|
|
147
118
|
You don't need to parse the response, it is done automatically when calling xpath, css or re.
|
|
119
|
+
|
|
148
120
|
```python
|
|
149
|
-
title = s.get(
|
|
121
|
+
title = s.get("http://samplesite.com").xpath("//title/text()").extract_first(default="Default Title")
|
|
150
122
|
```
|
|
151
123
|
|
|
152
124
|
Regex require less boilerplate when compared to Python's standard `re` module.
|
|
125
|
+
|
|
153
126
|
```python
|
|
154
|
-
response = s.get(
|
|
127
|
+
response = s.get("http://samplesite.com/sample_path")
|
|
155
128
|
|
|
156
129
|
# Extracts the first match
|
|
157
|
-
identifier = response.re_first(r
|
|
130
|
+
identifier = response.re_first(r"ID_\d\w\d", default="ID_1A1")
|
|
158
131
|
|
|
159
132
|
# Extracts all matches as a list
|
|
160
|
-
users = response.re(r
|
|
133
|
+
users = response.re(r"user_\d\d\d")
|
|
161
134
|
```
|
|
162
135
|
|
|
163
|
-
The Session object is just a regular Requests's session object, so you can use all of its methods.
|
|
136
|
+
The Session object is just a regular Requests's session object, so you can use all of its methods. Responses from all HTTP verbs (get, post, put, patch, delete, head, options) have the xpath, css, and re helpers.
|
|
137
|
+
|
|
164
138
|
```python
|
|
165
|
-
s.post(
|
|
166
|
-
s.proxies.update({
|
|
139
|
+
s.post("http://www.samplesite.com/sample", data={"field1": "data1"})
|
|
140
|
+
s.proxies.update({"http": "http://10.11.4.254:3128", "https": "https://10.11.4.252:3128"})
|
|
167
141
|
```
|
|
168
142
|
|
|
169
143
|
And you can switch to using the Selenium webdriver to run any js code.
|
|
144
|
+
|
|
170
145
|
```python
|
|
171
146
|
s.transfer_session_cookies_to_driver() # You can maintain the session if needed
|
|
172
|
-
s.driver.get(
|
|
147
|
+
s.driver.get("http://www.samplesite.com/sample/process")
|
|
173
148
|
```
|
|
174
149
|
|
|
175
150
|
The driver object is a Selenium webdriver object, so you can use any of the normal selenium methods plus new methods added by Requestium.
|
|
151
|
+
|
|
176
152
|
```python
|
|
177
|
-
s.driver.find_element("xpath", "//input[@class='user_name']").send_keys(
|
|
153
|
+
s.driver.find_element("xpath", "//input[@class='user_name']").send_keys("James Bond", Keys.ENTER)
|
|
178
154
|
|
|
179
155
|
# New methods which wait for element to load instead of failing, useful for single page web apps
|
|
180
156
|
s.driver.ensure_element("xpath", "//div[@attribute='button']").click()
|
|
@@ -182,15 +158,26 @@ s.driver.ensure_element_by_xpath("//div[@attribute='button']").click()
|
|
|
182
158
|
```
|
|
183
159
|
|
|
184
160
|
Requestium also adds xpath, css, and re methods to the Selenium driver object.
|
|
161
|
+
|
|
185
162
|
```python
|
|
186
|
-
if s.driver.re(r
|
|
187
|
-
print(
|
|
163
|
+
if s.driver.re(r"ID_\d\w\d some_pattern"):
|
|
164
|
+
print("Found it!")
|
|
188
165
|
```
|
|
189
166
|
|
|
190
167
|
And finally you can switch back to using Requests.
|
|
168
|
+
|
|
191
169
|
```python
|
|
192
170
|
s.transfer_driver_cookies_to_session()
|
|
193
|
-
s.post(
|
|
171
|
+
s.post("http://www.samplesite.com/sample2", data={"key1": "value1"})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
When you are done, close the session. This quits the webdriver if one was started, including a driver you passed in. It also works as a context manager.
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
s.close()
|
|
178
|
+
|
|
179
|
+
with Session(headless=True) as s:
|
|
180
|
+
s.driver.get("http://www.samplesite.com")
|
|
194
181
|
```
|
|
195
182
|
|
|
196
183
|
## Selenium workarounds
|
|
@@ -200,6 +187,7 @@ Requestium adds several 'ensure' methods to the driver object, as Selenium is kn
|
|
|
200
187
|
The `ensure_element` and `ensure_element_by_` methods wait for the element to be loaded in the browser and returns it as soon as it loads. They're named after Selenium's `find_element` and `find_element_by_` methods (which immediately raise an exception if they can't find the element).
|
|
201
188
|
|
|
202
189
|
Requestium can wait for an element to be in any of the following states:
|
|
190
|
+
|
|
203
191
|
- present (default)
|
|
204
192
|
- clickable
|
|
205
193
|
- visible
|
|
@@ -210,7 +198,7 @@ These methods are very useful for single page web apps where the site is dynamic
|
|
|
210
198
|
Elements you get using these methods have the new `ensure_click` method which makes the click less prone to failure. This helps with getting through a lot of the problems with Selenium clicking.
|
|
211
199
|
|
|
212
200
|
```python
|
|
213
|
-
s.driver.ensure_element("xpath", "//li[@class='b1']", state=
|
|
201
|
+
s.driver.ensure_element("xpath", "//li[@class='b1']", state="clickable", timeout=5).ensure_click()
|
|
214
202
|
|
|
215
203
|
# === We also added these methods named in accordance to Selenium's api design ===
|
|
216
204
|
# ensure_element_by_id
|
|
@@ -224,61 +212,57 @@ s.driver.ensure_element("xpath", "//li[@class='b1']", state='clickable', timeout
|
|
|
224
212
|
```
|
|
225
213
|
|
|
226
214
|
### Add cookie
|
|
227
|
-
The `ensure_add_cookie` method makes adding cookies much more robust. Selenium needs the browser to be at the cookie's domain before being able to add the cookie, this method offers several workarounds for this. If the browser is not in the cookies domain, it GETs the domain before adding the cookie. It also allows you to override the domain before adding it, and avoid making this GET. The domain can be overridden to `''`, this sets the cookie's domain to whatever domain the driver is currently in.
|
|
215
|
+
The `ensure_add_cookie` method makes adding cookies much more robust. Selenium needs the browser to be at the cookie's domain before being able to add the cookie, this method offers several workarounds for this. If the browser is not in the cookies domain, it GETs the domain before adding the cookie, over https if the cookie is `secure` and over http otherwise. It also allows you to override the domain before adding it, and avoid making this GET. The domain can be overridden to `''`, this sets the cookie's domain to whatever domain the driver is currently in.
|
|
228
216
|
|
|
229
217
|
If it can't add the cookie it tries to add it with a less restrictive domain (Eg.: home.site.com -> site.com) before failing.
|
|
230
218
|
|
|
231
219
|
```python
|
|
232
|
-
cookie = {"domain": "www.site.com",
|
|
233
|
-
|
|
234
|
-
"value": "sd2451dgd13",
|
|
235
|
-
"expiry": 1516824855.759154,
|
|
236
|
-
"path": "/",
|
|
237
|
-
"httpOnly": true,
|
|
238
|
-
"name": "sessionid"}
|
|
239
|
-
s.driver.ensure_add_cookie(cookie, override_domain='')
|
|
220
|
+
cookie = {"domain": "www.site.com", "secure": False, "value": "sd2451dgd13", "expiry": 1516824855.759154, "path": "/", "httpOnly": True, "name": "sessionid"}
|
|
221
|
+
s.driver.ensure_add_cookie(cookie, override_domain="")
|
|
240
222
|
```
|
|
241
223
|
|
|
242
224
|
## Considerations
|
|
243
225
|
New features are lazily evaluated, meaning:
|
|
226
|
+
|
|
244
227
|
- The Selenium webdriver process is only started if you call the driver object. So if you don't need to use the webdriver, you could use the library with no overhead. Very useful if you just want to use the library for its integration with Parsel.
|
|
245
228
|
- Parsing of the responses is only done if you call the `xpath`, `css`, or `re` methods of the response. So again there is no overhead if you don't need to use this feature.
|
|
246
229
|
|
|
247
230
|
A byproduct of this is that the Selenium webdriver could be used just as a tool to ease in the development of regular Requests code: You can start writing your script using just the Requests' session, and at the last step of the script (the one you are currently working on) transfer the session to the Chrome webdriver. This way, a Chrome process starts in your machine, and acts as a real time "visor" for the last step of your code. You can see in what state your session is currently in, inspect it with Chrome's excellent inspect tools, and decide what's the next step your session object should take. Very useful to try code in an IPython interpreter and see how the site reacts in real time.
|
|
248
231
|
|
|
249
232
|
When `transfer_driver_cookies_to_session` is called, Requestium automatically updates your Requests session user-agent to match that of the browser used in Selenium. This doesn't happen when running Requests without having switched from a Selenium session first though. So if you just want to run Requests but want it to use your browser's user agent instead of the default one (which sites love to block), just run:
|
|
233
|
+
|
|
250
234
|
```python
|
|
251
235
|
s.copy_user_agent_from_driver()
|
|
252
236
|
```
|
|
253
237
|
Take into account that doing this will launch a browser process.
|
|
254
238
|
|
|
255
|
-
|
|
239
|
+
When Requestium launches its own Chrome, it carries over the session's `proxies` (as `--proxy-server`) and a custom `User-Agent` header, as long as they are set before the driver is first used. Proxies with credentials aren't supported by Chrome flags and are skipped with a warning. Other headers are not synced. This doesn't apply to a driver you pass in yourself.
|
|
256
240
|
|
|
257
241
|
## Comparison with Requests + Selenium + lxml
|
|
258
242
|
A silly working example of a script that runs on Reddit. We'll then show how it compares to using Requests + Selenium + lxml instead of Requestium.
|
|
259
243
|
|
|
260
244
|
### Using Requestium
|
|
245
|
+
|
|
261
246
|
```python
|
|
262
247
|
from requestium import Session, Keys
|
|
263
248
|
|
|
264
249
|
# If you want requestium to type your username in the browser for you, write it in here:
|
|
265
|
-
reddit_user_name =
|
|
250
|
+
reddit_user_name = ""
|
|
266
251
|
|
|
267
|
-
s = Session(
|
|
268
|
-
s.driver.get(
|
|
252
|
+
s = Session(default_timeout=15)
|
|
253
|
+
s.driver.get("http://reddit.com")
|
|
269
254
|
s.driver.find_element("xpath", "//a[@href='https://www.reddit.com/login']").click()
|
|
270
255
|
|
|
271
|
-
print(
|
|
272
|
-
s.driver.ensure_element("class name", "desktop-onboarding-sign-up__form-toggler",
|
|
273
|
-
state='visible').click()
|
|
256
|
+
print("Waiting for elements to load...")
|
|
257
|
+
s.driver.ensure_element("class name", "desktop-onboarding-sign-up__form-toggler", state="visible").click()
|
|
274
258
|
|
|
275
259
|
if reddit_user_name:
|
|
276
|
-
s.driver.ensure_element(
|
|
277
|
-
s.driver.ensure_element(
|
|
278
|
-
print(
|
|
260
|
+
s.driver.ensure_element("id", "user_login").send_keys(reddit_user_name)
|
|
261
|
+
s.driver.ensure_element("id", "passwd_login").send_keys(Keys.BACKSPACE)
|
|
262
|
+
print("Please log-in in the chrome browser")
|
|
279
263
|
|
|
280
|
-
s.driver.ensure_element("class name", "desktop-onboarding__title", timeout=60, state=
|
|
281
|
-
print(
|
|
264
|
+
s.driver.ensure_element("class name", "desktop-onboarding__title", timeout=60, state="invisible")
|
|
265
|
+
print("Thanks!")
|
|
282
266
|
|
|
283
267
|
if not reddit_user_name:
|
|
284
268
|
reddit_user_name = s.driver.xpath("//span[@class='user']//text()").extract_first()
|
|
@@ -308,34 +292,26 @@ from selenium.webdriver.support.ui import WebDriverWait
|
|
|
308
292
|
from selenium.webdriver.support import expected_conditions as EC
|
|
309
293
|
|
|
310
294
|
# If you want requestium to type your username in the browser for you, write it in here:
|
|
311
|
-
reddit_user_name =
|
|
295
|
+
reddit_user_name = ""
|
|
312
296
|
|
|
313
|
-
driver = webdriver.Chrome(
|
|
314
|
-
driver.get(
|
|
297
|
+
driver = webdriver.Chrome()
|
|
298
|
+
driver.get("http://reddit.com")
|
|
315
299
|
driver.find_element("xpath", "//a[@href='https://www.reddit.com/login']").click()
|
|
316
300
|
|
|
317
|
-
print(
|
|
318
|
-
WebDriverWait(driver, 15).until(
|
|
319
|
-
EC.visibility_of_element_located((By.CLASS_NAME, "desktop-onboarding-sign-up__form-toggler"))
|
|
320
|
-
).click()
|
|
301
|
+
print("Waiting for elements to load...")
|
|
302
|
+
WebDriverWait(driver, 15).until(EC.visibility_of_element_located((By.CLASS_NAME, "desktop-onboarding-sign-up__form-toggler"))).click()
|
|
321
303
|
|
|
322
304
|
if reddit_user_name:
|
|
323
|
-
WebDriverWait(driver, 15).until(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
driver.find_element('id', 'passwd_login').send_keys(Keys.BACKSPACE)
|
|
327
|
-
print('Please log-in in the chrome browser')
|
|
305
|
+
WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.ID, "user_login"))).send_keys(reddit_user_name)
|
|
306
|
+
driver.find_element("id", "passwd_login").send_keys(Keys.BACKSPACE)
|
|
307
|
+
print("Please log-in in the chrome browser")
|
|
328
308
|
|
|
329
309
|
try:
|
|
330
|
-
WebDriverWait(driver, 3).until(
|
|
331
|
-
EC.presence_of_element_located((By.CLASS_NAME, "desktop-onboarding__title"))
|
|
332
|
-
)
|
|
310
|
+
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CLASS_NAME, "desktop-onboarding__title")))
|
|
333
311
|
except TimeoutException:
|
|
334
312
|
pass
|
|
335
|
-
WebDriverWait(driver, 60).until(
|
|
336
|
-
|
|
337
|
-
)
|
|
338
|
-
print('Thanks!')
|
|
313
|
+
WebDriverWait(driver, 60).until(EC.invisibility_of_element_located((By.CLASS_NAME, "desktop-onboarding__title")))
|
|
314
|
+
print("Thanks!")
|
|
339
315
|
|
|
340
316
|
if not reddit_user_name:
|
|
341
317
|
tree = etree.HTML(driver.page_source)
|
|
@@ -350,11 +326,10 @@ if reddit_user_name:
|
|
|
350
326
|
selenium_user_agent = driver.execute_script("return navigator.userAgent;")
|
|
351
327
|
s.headers.update({"user-agent": selenium_user_agent})
|
|
352
328
|
for cookie in driver.get_cookies():
|
|
353
|
-
s.cookies.set(cookie[
|
|
329
|
+
s.cookies.set(cookie["name"], cookie["value"], domain=cookie["domain"])
|
|
354
330
|
response = s.get("https://www.reddit.com/user/{}/".format(reddit_user_name))
|
|
355
331
|
try:
|
|
356
|
-
cmnt_karma = etree.HTML(response.content).xpath(
|
|
357
|
-
"//span[@class='karma comment-karma']//text()")[0]
|
|
332
|
+
cmnt_karma = etree.HTML(response.content).xpath("//span[@class='karma comment-karma']//text()")[0]
|
|
358
333
|
except IndexError:
|
|
359
334
|
cmnt_karma = None
|
|
360
335
|
match = re.search(r"(\d+) gildings given out", str(response.content))
|
|
@@ -373,4 +348,6 @@ This project intends to be a drop-in replacement of Requests' Session object, wi
|
|
|
373
348
|
|
|
374
349
|
|
|
375
350
|
## License
|
|
376
|
-
Copyright ©
|
|
351
|
+
Copyright © 2017, [Tryolabs](https://tryolabs.com/). Copyright © 2022-2026, Judson Neer. Released under the [BSD 3-Clause](https://github.com/lordjabez/requestium/blob/main/LICENSE).
|
|
352
|
+
|
|
353
|
+
Requestium was originally developed as an internal tool at Tryolabs and later released as open source. In 2026, Tryolabs transferred the project to Jud Neer, who maintains it independently. Tryolabs is not responsible for the project or for any release made after the transfer.
|