requestium 0.5.1__tar.gz → 0.6.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.
Files changed (31) hide show
  1. {requestium-0.5.1/requestium.egg-info → requestium-0.6.0}/PKG-INFO +87 -109
  2. {requestium-0.5.1 → requestium-0.6.0}/README.md +83 -65
  3. {requestium-0.5.1 → requestium-0.6.0}/pyproject.toml +20 -15
  4. {requestium-0.5.1 → requestium-0.6.0}/requestium/__init__.py +1 -1
  5. {requestium-0.5.1 → requestium-0.6.0}/requestium/requestium_mixin.py +13 -13
  6. {requestium-0.5.1 → requestium-0.6.0}/requestium/requestium_response.py +1 -1
  7. requestium-0.6.0/requestium/requestium_session.py +234 -0
  8. {requestium-0.5.1 → requestium-0.6.0/requestium.egg-info}/PKG-INFO +87 -109
  9. {requestium-0.5.1 → requestium-0.6.0}/requestium.egg-info/SOURCES.txt +6 -0
  10. requestium-0.6.0/requestium.egg-info/requires.txt +4 -0
  11. requestium-0.6.0/tests/test_add_cookie.py +124 -0
  12. requestium-0.6.0/tests/test_cookies.py +144 -0
  13. requestium-0.6.0/tests/test_driver_parsing.py +48 -0
  14. requestium-0.6.0/tests/test_ensure_element.py +196 -0
  15. requestium-0.6.0/tests/test_mixin.py +91 -0
  16. requestium-0.6.0/tests/test_proxy.py +53 -0
  17. requestium-0.6.0/tests/test_remote_driver.py +98 -0
  18. requestium-0.6.0/tests/test_response_parsing.py +107 -0
  19. requestium-0.6.0/tests/test_session.py +173 -0
  20. requestium-0.6.0/tests/test_user_agent.py +81 -0
  21. requestium-0.5.1/requestium/requestium_session.py +0 -163
  22. requestium-0.5.1/requestium.egg-info/requires.txt +0 -15
  23. requestium-0.5.1/tests/test_cookies.py +0 -95
  24. requestium-0.5.1/tests/test_mixin.py +0 -118
  25. requestium-0.5.1/tests/test_session.py +0 -92
  26. requestium-0.5.1/tests/test_user_agent.py +0 -34
  27. {requestium-0.5.1 → requestium-0.6.0}/LICENSE +0 -0
  28. {requestium-0.5.1 → requestium-0.6.0}/requestium/requestium.py +0 -0
  29. {requestium-0.5.1 → requestium-0.6.0}/requestium.egg-info/dependency_links.txt +0 -0
  30. {requestium-0.5.1 → requestium-0.6.0}/requestium.egg-info/top_level.txt +0 -0
  31. {requestium-0.5.1 → requestium-0.6.0}/setup.cfg +0 -0
@@ -1,44 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: requestium
3
- Version: 0.5.1
3
+ Version: 0.6.0
4
4
  Author-email: Joaquin Alori <joaquin@tryolabs.com>
5
- Maintainer-email: Judson Neer <jkudson.neer@gmail.com>
6
- License: BSD 3-Clause License
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
-
5
+ Maintainer-email: Judson Neer <judson.neer@gmail.com>
6
+ License-Expression: BSD-3-Clause
36
7
  Project-URL: source, https://github.com/tryolabs/requestium
37
8
  Project-URL: download, https://pypi.org/project/requestium/#files
38
9
  Project-URL: issues, https://github.com/tryolabs/requestium/issues
39
10
  Classifier: Development Status :: 4 - Beta
40
11
  Classifier: Intended Audience :: Developers
41
- Classifier: License :: OSI Approved :: BSD License
42
12
  Classifier: Programming Language :: Python :: 3.10
43
13
  Classifier: Programming Language :: Python :: 3.11
44
14
  Classifier: Programming Language :: Python :: 3.12
@@ -56,20 +26,10 @@ Classifier: Topic :: Software Development :: Testing
56
26
  Requires-Python: >=3.10
57
27
  Description-Content-Type: text/markdown
58
28
  License-File: LICENSE
59
- Requires-Dist: parsel>=1.7
29
+ Requires-Dist: parsel>=1.8
60
30
  Requires-Dist: requests>=2.27
61
31
  Requires-Dist: selenium>=4.32
62
32
  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
33
  Dynamic: license-file
74
34
 
75
35
  ![Requestium](https://user-images.githubusercontent.com/14966348/32966130-8bb15b00-cbb7-11e7-9faf-85963ec5bd82.png)
@@ -81,15 +41,16 @@ Dynamic: license-file
81
41
  [![Coverage](https://raw.githubusercontent.com/tryolabs/requestium/python-coverage-comment-action-data/badge.svg)](https://htmlpreview.github.io/?https://github.com/tryolabs/requestium/blob/python-coverage-comment-action-data/htmlcov/index.html)
82
42
  [![Python checks](https://github.com/tryolabs/requestium/actions/workflows/python.yml/badge.svg)](https://github.com/tryolabs/requestium/actions/workflows/python.yml)
83
43
 
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 automatizing web actions.
44
+ 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
45
 
86
46
  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
47
 
88
48
  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
49
 
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/).
50
+ Read more about the motivation behind creating this library in this [blog post](https://tryolabs.com/blog/2017/11/22/requestium-integration-layer-requests-selenium-web-automation/).
91
51
 
92
52
  ## Features
53
+
93
54
  - Enables switching between a Requests' Session and a Selenium webdriver while maintaining the current web session.
94
55
  - Integrates Parsel's parser into the library, making xpath, css, and regex much cleaner to write.
95
56
  - Improves Selenium's handling of dynamically loading elements.
@@ -98,19 +59,21 @@ Read more about the motivation behind creating this library in this [blopost](ht
98
59
  - Supports Chromedriver natively plus adding a custom webdriver.
99
60
 
100
61
  ## Installation
62
+
101
63
  ```bash
102
64
  pip install requestium
103
65
  ```
104
66
 
105
- You should then download your preferred Selenium webdriver if you plan to use the Selenium part of Requestium, such as [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/).
67
+ 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
68
 
107
69
  ## Usage
108
70
  First create a session as you would do on Requests, and optionally add arguments for the web-driver if you plan to use one.
71
+
109
72
  ```python
110
73
  from requestium import Session, Keys
111
74
 
112
- options = {'arguments': ['headless']}
113
- s = Session(webdriver_path='./chromedriver', default_timeout=15, webdriver_options=options)
75
+ options = {"arguments": ["headless"]}
76
+ s = Session(webdriver_path="./chromedriver", default_timeout=15, webdriver_options=options)
114
77
  ```
115
78
 
116
79
  Since headless mode is common, there's a shortcut for it by specifying `headless=True`.
@@ -118,7 +81,7 @@ Since headless mode is common, there's a shortcut for it by specifying `headless
118
81
  ```python
119
82
  from requestium import Session, Keys
120
83
 
121
- s = Session(webdriver_path='./chromedriver' headless=True)
84
+ s = Session(webdriver_path="./chromedriver", headless=True)
122
85
  ```
123
86
 
124
87
  You can also create a Selenium webdriver outside Requestium and have it use that instead:
@@ -132,7 +95,19 @@ firefox_driver = webdriver.Firefox()
132
95
  s = Session(driver=firefox_driver)
133
96
  ```
134
97
 
135
- You can also specify a 3rd party Chrome webdriver class and use it by specifying the `browser` argument as well. This will allow, for example, to use [Selenium-Wire](https://github.com/wkeeling/selenium-wire) to get XHR requests of a web page:
98
+ A remote webdriver works too, with all the `ensure_*` and xpath/css/re helpers:
99
+
100
+ ```python
101
+ from selenium import webdriver
102
+ from requestium import Session
103
+
104
+ options = webdriver.ChromeOptions()
105
+ remote_driver = webdriver.Remote(command_executor="http://localhost:4444/wd/hub", options=options)
106
+
107
+ s = Session(driver=remote_driver)
108
+ ```
109
+
110
+ 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
111
 
137
112
  ```python
138
113
  from seleniumwire import webdriver
@@ -140,41 +115,45 @@ from requestium import Session, Keys
140
115
 
141
116
  seleniumwire_driver = webdriver.Chrome()
142
117
 
143
- s = Session(webdriver_path='./chromedriver', driver=seleniumwire_driver)
144
-
118
+ s = Session(driver=seleniumwire_driver)
145
119
  ```
146
120
 
147
121
  You don't need to parse the response, it is done automatically when calling xpath, css or re.
122
+
148
123
  ```python
149
- title = s.get('http://samplesite.com').xpath('//title/text()').extract_first(default='Default Title')
124
+ title = s.get("http://samplesite.com").xpath("//title/text()").extract_first(default="Default Title")
150
125
  ```
151
126
 
152
127
  Regex require less boilerplate when compared to Python's standard `re` module.
128
+
153
129
  ```python
154
- response = s.get('http://samplesite.com/sample_path')
130
+ response = s.get("http://samplesite.com/sample_path")
155
131
 
156
132
  # Extracts the first match
157
- identifier = response.re_first(r'ID_\d\w\d', default='ID_1A1')
133
+ identifier = response.re_first(r"ID_\d\w\d", default="ID_1A1")
158
134
 
159
135
  # Extracts all matches as a list
160
- users = response.re(r'user_\d\d\d')
136
+ users = response.re(r"user_\d\d\d")
161
137
  ```
162
138
 
163
- The Session object is just a regular Requests's session object, so you can use all of its methods.
139
+ 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.
140
+
164
141
  ```python
165
- s.post('http://www.samplesite.com/sample', data={'field1': 'data1'})
166
- s.proxies.update({'http': 'http://10.11.4.254:3128', 'https': 'https://10.11.4.252:3128'})
142
+ s.post("http://www.samplesite.com/sample", data={"field1": "data1"})
143
+ s.proxies.update({"http": "http://10.11.4.254:3128", "https": "https://10.11.4.252:3128"})
167
144
  ```
168
145
 
169
146
  And you can switch to using the Selenium webdriver to run any js code.
147
+
170
148
  ```python
171
149
  s.transfer_session_cookies_to_driver() # You can maintain the session if needed
172
- s.driver.get('http://www.samplesite.com/sample/process')
150
+ s.driver.get("http://www.samplesite.com/sample/process")
173
151
  ```
174
152
 
175
153
  The driver object is a Selenium webdriver object, so you can use any of the normal selenium methods plus new methods added by Requestium.
154
+
176
155
  ```python
177
- s.driver.find_element("xpath", "//input[@class='user_name']").send_keys('James Bond', Keys.ENTER)
156
+ s.driver.find_element("xpath", "//input[@class='user_name']").send_keys("James Bond", Keys.ENTER)
178
157
 
179
158
  # New methods which wait for element to load instead of failing, useful for single page web apps
180
159
  s.driver.ensure_element("xpath", "//div[@attribute='button']").click()
@@ -182,15 +161,26 @@ s.driver.ensure_element_by_xpath("//div[@attribute='button']").click()
182
161
  ```
183
162
 
184
163
  Requestium also adds xpath, css, and re methods to the Selenium driver object.
164
+
185
165
  ```python
186
- if s.driver.re(r'ID_\d\w\d some_pattern'):
187
- print('Found it!')
166
+ if s.driver.re(r"ID_\d\w\d some_pattern"):
167
+ print("Found it!")
188
168
  ```
189
169
 
190
170
  And finally you can switch back to using Requests.
171
+
191
172
  ```python
192
173
  s.transfer_driver_cookies_to_session()
193
- s.post('http://www.samplesite.com/sample2', data={'key1': 'value1'})
174
+ s.post("http://www.samplesite.com/sample2", data={"key1": "value1"})
175
+ ```
176
+
177
+ 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.
178
+
179
+ ```python
180
+ s.close()
181
+
182
+ with Session(headless=True) as s:
183
+ s.driver.get("http://www.samplesite.com")
194
184
  ```
195
185
 
196
186
  ## Selenium workarounds
@@ -200,6 +190,7 @@ Requestium adds several 'ensure' methods to the driver object, as Selenium is kn
200
190
  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
191
 
202
192
  Requestium can wait for an element to be in any of the following states:
193
+
203
194
  - present (default)
204
195
  - clickable
205
196
  - visible
@@ -210,7 +201,7 @@ These methods are very useful for single page web apps where the site is dynamic
210
201
  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
202
 
212
203
  ```python
213
- s.driver.ensure_element("xpath", "//li[@class='b1']", state='clickable', timeout=5).ensure_click()
204
+ s.driver.ensure_element("xpath", "//li[@class='b1']", state="clickable", timeout=5).ensure_click()
214
205
 
215
206
  # === We also added these methods named in accordance to Selenium's api design ===
216
207
  # ensure_element_by_id
@@ -224,61 +215,57 @@ s.driver.ensure_element("xpath", "//li[@class='b1']", state='clickable', timeout
224
215
  ```
225
216
 
226
217
  ### 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.
218
+ 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
219
 
229
220
  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
221
 
231
222
  ```python
232
- cookie = {"domain": "www.site.com",
233
- "secure": false,
234
- "value": "sd2451dgd13",
235
- "expiry": 1516824855.759154,
236
- "path": "/",
237
- "httpOnly": true,
238
- "name": "sessionid"}
239
- s.driver.ensure_add_cookie(cookie, override_domain='')
223
+ cookie = {"domain": "www.site.com", "secure": False, "value": "sd2451dgd13", "expiry": 1516824855.759154, "path": "/", "httpOnly": True, "name": "sessionid"}
224
+ s.driver.ensure_add_cookie(cookie, override_domain="")
240
225
  ```
241
226
 
242
227
  ## Considerations
243
228
  New features are lazily evaluated, meaning:
229
+
244
230
  - 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
231
  - 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
232
 
247
233
  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
234
 
249
235
  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:
236
+
250
237
  ```python
251
238
  s.copy_user_agent_from_driver()
252
239
  ```
253
240
  Take into account that doing this will launch a browser process.
254
241
 
255
- Note: The Selenium Chrome webdriver doesn't support automatic transfer of proxies from the Session to the Webdriver at the moment.
242
+ 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
243
 
257
244
  ## Comparison with Requests + Selenium + lxml
258
245
  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
246
 
260
247
  ### Using Requestium
248
+
261
249
  ```python
262
250
  from requestium import Session, Keys
263
251
 
264
252
  # If you want requestium to type your username in the browser for you, write it in here:
265
- reddit_user_name = ''
253
+ reddit_user_name = ""
266
254
 
267
- s = Session('./chromedriver', default_timeout=15)
268
- s.driver.get('http://reddit.com')
255
+ s = Session(default_timeout=15)
256
+ s.driver.get("http://reddit.com")
269
257
  s.driver.find_element("xpath", "//a[@href='https://www.reddit.com/login']").click()
270
258
 
271
- print('Waiting for elements to load...')
272
- s.driver.ensure_element("class name", "desktop-onboarding-sign-up__form-toggler",
273
- state='visible').click()
259
+ print("Waiting for elements to load...")
260
+ s.driver.ensure_element("class name", "desktop-onboarding-sign-up__form-toggler", state="visible").click()
274
261
 
275
262
  if reddit_user_name:
276
- s.driver.ensure_element('id', 'user_login').send_keys(reddit_user_name)
277
- s.driver.ensure_element('id', 'passwd_login').send_keys(Keys.BACKSPACE)
278
- print('Please log-in in the chrome browser')
263
+ s.driver.ensure_element("id", "user_login").send_keys(reddit_user_name)
264
+ s.driver.ensure_element("id", "passwd_login").send_keys(Keys.BACKSPACE)
265
+ print("Please log-in in the chrome browser")
279
266
 
280
- s.driver.ensure_element("class name", "desktop-onboarding__title", timeout=60, state='invisible')
281
- print('Thanks!')
267
+ s.driver.ensure_element("class name", "desktop-onboarding__title", timeout=60, state="invisible")
268
+ print("Thanks!")
282
269
 
283
270
  if not reddit_user_name:
284
271
  reddit_user_name = s.driver.xpath("//span[@class='user']//text()").extract_first()
@@ -308,34 +295,26 @@ from selenium.webdriver.support.ui import WebDriverWait
308
295
  from selenium.webdriver.support import expected_conditions as EC
309
296
 
310
297
  # If you want requestium to type your username in the browser for you, write it in here:
311
- reddit_user_name = ''
298
+ reddit_user_name = ""
312
299
 
313
- driver = webdriver.Chrome('./chromedriver')
314
- driver.get('http://reddit.com')
300
+ driver = webdriver.Chrome()
301
+ driver.get("http://reddit.com")
315
302
  driver.find_element("xpath", "//a[@href='https://www.reddit.com/login']").click()
316
303
 
317
- print('Waiting for elements to load...')
318
- WebDriverWait(driver, 15).until(
319
- EC.visibility_of_element_located((By.CLASS_NAME, "desktop-onboarding-sign-up__form-toggler"))
320
- ).click()
304
+ print("Waiting for elements to load...")
305
+ WebDriverWait(driver, 15).until(EC.visibility_of_element_located((By.CLASS_NAME, "desktop-onboarding-sign-up__form-toggler"))).click()
321
306
 
322
307
  if reddit_user_name:
323
- WebDriverWait(driver, 15).until(
324
- EC.presence_of_element_located((By.ID, 'user_login'))
325
- ).send_keys(reddit_user_name)
326
- driver.find_element('id', 'passwd_login').send_keys(Keys.BACKSPACE)
327
- print('Please log-in in the chrome browser')
308
+ WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.ID, "user_login"))).send_keys(reddit_user_name)
309
+ driver.find_element("id", "passwd_login").send_keys(Keys.BACKSPACE)
310
+ print("Please log-in in the chrome browser")
328
311
 
329
312
  try:
330
- WebDriverWait(driver, 3).until(
331
- EC.presence_of_element_located((By.CLASS_NAME, "desktop-onboarding__title"))
332
- )
313
+ WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CLASS_NAME, "desktop-onboarding__title")))
333
314
  except TimeoutException:
334
315
  pass
335
- WebDriverWait(driver, 60).until(
336
- EC.invisibility_of_element_located((By.CLASS_NAME, "desktop-onboarding__title"))
337
- )
338
- print('Thanks!')
316
+ WebDriverWait(driver, 60).until(EC.invisibility_of_element_located((By.CLASS_NAME, "desktop-onboarding__title")))
317
+ print("Thanks!")
339
318
 
340
319
  if not reddit_user_name:
341
320
  tree = etree.HTML(driver.page_source)
@@ -350,11 +329,10 @@ if reddit_user_name:
350
329
  selenium_user_agent = driver.execute_script("return navigator.userAgent;")
351
330
  s.headers.update({"user-agent": selenium_user_agent})
352
331
  for cookie in driver.get_cookies():
353
- s.cookies.set(cookie['name'], cookie['value'], domain=cookie['domain'])
332
+ s.cookies.set(cookie["name"], cookie["value"], domain=cookie["domain"])
354
333
  response = s.get("https://www.reddit.com/user/{}/".format(reddit_user_name))
355
334
  try:
356
- cmnt_karma = etree.HTML(response.content).xpath(
357
- "//span[@class='karma comment-karma']//text()")[0]
335
+ cmnt_karma = etree.HTML(response.content).xpath("//span[@class='karma comment-karma']//text()")[0]
358
336
  except IndexError:
359
337
  cmnt_karma = None
360
338
  match = re.search(r"(\d+) gildings given out", str(response.content))