summaryrefslogtreecommitdiff
path: root/python-hlisa.spec
blob: 20ef3dc81a532197789de8813f31a69dea94e874 (plain)
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
%global _empty_manifest_terminate_build 0
Name:		python-HLISA
Version:	1.5.0
Release:	1
Summary:	A reimplementation of the Selenium API, emulating human interactions
License:	GPLv3
URL:		https://github.com/droefs/HLISA
Source0:	https://mirrors.aliyun.com/pypi/web/packages/33/40/fdb82ba4e6860e39cfe9eec30ee75b4a9ecedf0e765bdd21357592c34c16/HLISA-1.5.0.tar.gz
BuildArch:	noarch

Requires:	python3-selenium
Requires:	python3-numpy

%description
# HLISA

HLISA is a drop-in replacement for the ActionChains object of the Selenium [API](https://www.selenium.dev/selenium/docs/api/py/webdriver/selenium.webdriver.common.action_chains.html) (Python only), featuring more human-like interaction. Besides providing all functionality the original Selenium ActionChains offers, additional interaction functionality is [provided](https://github.com/droefs/HLISA/blob/master/docs/api.md#additional-actions-available-in-hlisa). Calling interaction on elements (`element.click()`) is not provided.

## Important documents
- [API documentation](https://github.com/droefs/HLISA/blob/master/docs/api.md)
- [Changelog](https://github.com/droefs/HLISA/blob/master/docs/changelog.md)

## Demo

![Demo of HLISA and default Selenium in action](https://github.com/droefs/HLISA/raw/master/hlisa_demo.gif "Demo of HLISA and default Selenium in action")

## Installing and updating

### Installing

The package can be installed using pip:

`pip install HLISA`

And upgraded in the same fashion:

`pip install HLISA --upgrade`

(When using OpenWPM, it might be necessary to activate the correct conda environment before installing or upgrading HLISA: `conda activate openwpm`).

## Usage

See the [API description](https://github.com/droefs/HLISA/blob/master/docs/api.md) for all functions. The HLISA_ActionChains can be used just like the Selenium ActionChains object. It is however not possible to use standard Selenium interaction methods before using HLISA in a single session. This means that executing a Selenium ActionChain before executing an HLISA_ActionChain is not possible. Similarly, calling interaction on Elements (`element.click()`) can not be used before executing HLISA_ActionChains. Using Selenium actions to perform web page interaction before using HLISA in a single session can result in unexpected behavior.

### Usage example

```python
from HLISA.hlisa_action_chains import HLISA_ActionChains

human_like_actions = HLISA_ActionChains(webdriver)
human_like_actions.click()
human_like_actions.perform()
```

**The chain pattern works exactly like the Selenium ActionChains:**

```python
actions = HLISA_ActionChains(webdriver)
menu = webdriver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = webdriver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
actions.move_to_element(menu).click(hidden_submenu).perform()
```

**And so does queuing up:**

```python
menu = webdriver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = webdriver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
actions = HLISA_ActionChains(webdriver)`
actions.move_to_element(menu)
actions.click(hidden_submenu)
actions.perform()
```

### Difference in element selection

In contrast to Selenium ActionChains, HLISA_ActionChains functions do not select items when the elements are hidden (for example behind an image). This can cause different results. If an item is not selected because it is hidden, HLISA prints a message to the console. 

### More fine-grained control

By default, HLISA introduces delays within actions to make its interaction with web pages more human-like. An additional delay is added after every action to make the collection of interactions more human-like as well. In case you want to control the delay between actions yourself, use the `addDelayAfter`-flag when adding an action to the HLISA_ActionChain:

`actions.click(addDelayAfter=False)`

This flag ensures no delay is added after the action is completed. Delays within the action are unaffected. This also holds for composite actions, for example `.click` with an element specified `.click(element)`: this first moves the mouse to the element, then performs a click. Even if `addDelayAfter=False` is specified, there will be a pause between the mouse movement and the click (only the delay after the click is removed). To remove both delays, call `.move_to_element(element, addDelayAfter=False)` and `.click(addDelayAfter=False)` instead of `.click(element, addDelayAfter=False)`. This allows for complete control over delays between actions, because no delay or a custom delay can be specified this way. Example:

Standard delay after the mouse movement, standard delay after the click:

```python
HLISA_ActionChains(wd)
.click(element)
.perform()
```

Standard delay after the mouse movement, no delay after the click:

```python
HLISA_ActionChains(wd)
.click(element, addDelayAfter=False)
.perform()
```

No delay after the mouse movement, no delay after the click:

```python
HLISA_ActionChains(wd)
.move_to_element(element, addDelayAfter=False)
.click(addDelayAfter=False)
.perform()
```

Custom delay after the mouse movement, custom delay after the click:

```python
HLISA_ActionChains(wd)
.move_to_element(element, addDelayAfter=False)
.pause(0.1)
.click(addDelayAfter=False)
.pause(0.2)
.perform()
```

## API
Check the [API description under docs/api.md.](https://github.com/droefs/HLISA/blob/master/docs/api.md)

## Migrating from Selenium ActionChains to HLISA ActionChains

The functionality HLISA_ActionChains provides is a superset of the functionality provided by Selenium ActionChains. Therefore, migrating is trivial if the existing codebase only uses Selenium ActionChains:

1: import the HLISA ActionChains object:

`from HLISA.hlisa_action_chains import HLISA_ActionChains`

2: replace all occurrences of `ActionChains` by `HLISA_ActionChains`:

`actions = ActionChains(driver)` becomes `actions = HLISA_ActionChains(driver)`

If the syntax form of directly calling interactions on Elements is used (`element.click()`) in the existing codebase, migrating entails rewriting this syntax into ActionChains syntax. Depending on the existing codebase, this can be a time-consuming process.

3: only applicable if `element.click()`-like syntax (calling interaction directly on elements) was used: replace this type of syntax with HLISA_ActionChains syntax (which is equal to Selenium's ActionChains syntax). For example, `element.click()` becomes `HLISA_ActionChains(driver).click(element).perform()`.

## How does it work?

HLISA uses the Selenium API to interact with web pages. Some actions only feature additional delays. For example, HLISA_ActionChains(wd)[.click()](https://github.com/droefs/HLISA/blob/962d5bbc6b8dca64171dbc465be69f9e5dcd1bd4/src/HLISA/selenium_actions.py#L35) is implemented as:

```python
    def click(self, element=None):
        if element is not None:
            self.move_to_element(element)
        self.actions.click_and_hold()
        self.actions.pause(np.random.normal(0.092, 0.018))
        self.actions.release()
        self.addDelayAfterAction()
        return self
```

Other functions add additional actions. For example, a HLISA mouse movement consists of hundreds of tiny Selenium mouse movements that together form a jittery curve.
'''

## Notes on detection

HLISA (and Selenium) can be immediately detected if the browser is minimized while actions are being performed HLISA. This can be prevented by never minimizing the window when HLISA is active. Also note, that special keys can be detected, when not covered by HLISA (see the API description *send_keys_to_element* for details).

## Limitations

- HLISA does not support a remote end (Selenium Server).
- It is not possible to call interactions on Elements (`element.click()`-like syntax):

`text_field = webdriver.find_element_by_id("text_field")`

`text_field.send_keys("keys")`

This syntax has to be replaced by ActionChains syntax:

`text_field = webdriver.find_element_by_id("text_field")`

`HLISA_ActionChains(webdriver).send_keys("keys", text_field).perform()`

- It is not possible to use HLISA functionality after calling mouse movement functions of the original Selenium ActionChains API.

- The *context_click()* function is not human like.
- The *drag_and_drop()* function is not human like.
- The *drag_and_drop_by_offset()* function is not human like.

- HLISA is slow - it interacts with a web page web only as fast as a standard human would. This contrasts to Selenium which interacts with web pages in a superhuman fashion - just like a standard robot would. Please note that although HLISA is slow, this is only caused by intentionally introduced delays; HLISA is not significantly more resource intensive than Selenium.

- The **back**() and **forward**() functions of Selenium's **webdriver** object are not combatible with HLISA. Instead, the HLISA_ActionChains provides the functions back() and forward() to be used instead, exposing the same functionality.

## Publication and citation

For more details, please see [our IMC 2021 publication](https://doi.org/10.1145/3487552.3487843). If you use HLISA, you can cite our
work as follow:

```
HLISA: towards a more reliable measurement tool. D. Goßen, H. Jonker, S. Karsch,
B. Krumnow and D. Roefs. In Proceedings of the 21st ACM⁄SIGCOMM Internet 
Measurement Conference (IMC’21). ACM, pp. 380–389, 2021. 
```

or by using this BibTeX entry:

```
@inproceedings{GJKKR21,
  author    = {Daniel Go{\ss}en and
               Hugo Jonker and
               Stefan Karsch and
               Benjamin Krumnow and
               David Roefs},
  title     = {{HLISA:} towards a more reliable measurement tool},
  booktitle	= {Proceedings of the 21st ACM Internet Measurement Conference ({IMC'21})},
  pages		= {380--389},
  year      = {2021},
  url       = {https://doi.org/10.1145/3487552.3487843},
  doi       = {10.1145/3487552.3487843}
}
```


%package -n python3-HLISA
Summary:	A reimplementation of the Selenium API, emulating human interactions
Provides:	python-HLISA
BuildRequires:	python3-devel
BuildRequires:	python3-setuptools
BuildRequires:	python3-pip
%description -n python3-HLISA
# HLISA

HLISA is a drop-in replacement for the ActionChains object of the Selenium [API](https://www.selenium.dev/selenium/docs/api/py/webdriver/selenium.webdriver.common.action_chains.html) (Python only), featuring more human-like interaction. Besides providing all functionality the original Selenium ActionChains offers, additional interaction functionality is [provided](https://github.com/droefs/HLISA/blob/master/docs/api.md#additional-actions-available-in-hlisa). Calling interaction on elements (`element.click()`) is not provided.

## Important documents
- [API documentation](https://github.com/droefs/HLISA/blob/master/docs/api.md)
- [Changelog](https://github.com/droefs/HLISA/blob/master/docs/changelog.md)

## Demo

![Demo of HLISA and default Selenium in action](https://github.com/droefs/HLISA/raw/master/hlisa_demo.gif "Demo of HLISA and default Selenium in action")

## Installing and updating

### Installing

The package can be installed using pip:

`pip install HLISA`

And upgraded in the same fashion:

`pip install HLISA --upgrade`

(When using OpenWPM, it might be necessary to activate the correct conda environment before installing or upgrading HLISA: `conda activate openwpm`).

## Usage

See the [API description](https://github.com/droefs/HLISA/blob/master/docs/api.md) for all functions. The HLISA_ActionChains can be used just like the Selenium ActionChains object. It is however not possible to use standard Selenium interaction methods before using HLISA in a single session. This means that executing a Selenium ActionChain before executing an HLISA_ActionChain is not possible. Similarly, calling interaction on Elements (`element.click()`) can not be used before executing HLISA_ActionChains. Using Selenium actions to perform web page interaction before using HLISA in a single session can result in unexpected behavior.

### Usage example

```python
from HLISA.hlisa_action_chains import HLISA_ActionChains

human_like_actions = HLISA_ActionChains(webdriver)
human_like_actions.click()
human_like_actions.perform()
```

**The chain pattern works exactly like the Selenium ActionChains:**

```python
actions = HLISA_ActionChains(webdriver)
menu = webdriver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = webdriver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
actions.move_to_element(menu).click(hidden_submenu).perform()
```

**And so does queuing up:**

```python
menu = webdriver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = webdriver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
actions = HLISA_ActionChains(webdriver)`
actions.move_to_element(menu)
actions.click(hidden_submenu)
actions.perform()
```

### Difference in element selection

In contrast to Selenium ActionChains, HLISA_ActionChains functions do not select items when the elements are hidden (for example behind an image). This can cause different results. If an item is not selected because it is hidden, HLISA prints a message to the console. 

### More fine-grained control

By default, HLISA introduces delays within actions to make its interaction with web pages more human-like. An additional delay is added after every action to make the collection of interactions more human-like as well. In case you want to control the delay between actions yourself, use the `addDelayAfter`-flag when adding an action to the HLISA_ActionChain:

`actions.click(addDelayAfter=False)`

This flag ensures no delay is added after the action is completed. Delays within the action are unaffected. This also holds for composite actions, for example `.click` with an element specified `.click(element)`: this first moves the mouse to the element, then performs a click. Even if `addDelayAfter=False` is specified, there will be a pause between the mouse movement and the click (only the delay after the click is removed). To remove both delays, call `.move_to_element(element, addDelayAfter=False)` and `.click(addDelayAfter=False)` instead of `.click(element, addDelayAfter=False)`. This allows for complete control over delays between actions, because no delay or a custom delay can be specified this way. Example:

Standard delay after the mouse movement, standard delay after the click:

```python
HLISA_ActionChains(wd)
.click(element)
.perform()
```

Standard delay after the mouse movement, no delay after the click:

```python
HLISA_ActionChains(wd)
.click(element, addDelayAfter=False)
.perform()
```

No delay after the mouse movement, no delay after the click:

```python
HLISA_ActionChains(wd)
.move_to_element(element, addDelayAfter=False)
.click(addDelayAfter=False)
.perform()
```

Custom delay after the mouse movement, custom delay after the click:

```python
HLISA_ActionChains(wd)
.move_to_element(element, addDelayAfter=False)
.pause(0.1)
.click(addDelayAfter=False)
.pause(0.2)
.perform()
```

## API
Check the [API description under docs/api.md.](https://github.com/droefs/HLISA/blob/master/docs/api.md)

## Migrating from Selenium ActionChains to HLISA ActionChains

The functionality HLISA_ActionChains provides is a superset of the functionality provided by Selenium ActionChains. Therefore, migrating is trivial if the existing codebase only uses Selenium ActionChains:

1: import the HLISA ActionChains object:

`from HLISA.hlisa_action_chains import HLISA_ActionChains`

2: replace all occurrences of `ActionChains` by `HLISA_ActionChains`:

`actions = ActionChains(driver)` becomes `actions = HLISA_ActionChains(driver)`

If the syntax form of directly calling interactions on Elements is used (`element.click()`) in the existing codebase, migrating entails rewriting this syntax into ActionChains syntax. Depending on the existing codebase, this can be a time-consuming process.

3: only applicable if `element.click()`-like syntax (calling interaction directly on elements) was used: replace this type of syntax with HLISA_ActionChains syntax (which is equal to Selenium's ActionChains syntax). For example, `element.click()` becomes `HLISA_ActionChains(driver).click(element).perform()`.

## How does it work?

HLISA uses the Selenium API to interact with web pages. Some actions only feature additional delays. For example, HLISA_ActionChains(wd)[.click()](https://github.com/droefs/HLISA/blob/962d5bbc6b8dca64171dbc465be69f9e5dcd1bd4/src/HLISA/selenium_actions.py#L35) is implemented as:

```python
    def click(self, element=None):
        if element is not None:
            self.move_to_element(element)
        self.actions.click_and_hold()
        self.actions.pause(np.random.normal(0.092, 0.018))
        self.actions.release()
        self.addDelayAfterAction()
        return self
```

Other functions add additional actions. For example, a HLISA mouse movement consists of hundreds of tiny Selenium mouse movements that together form a jittery curve.
'''

## Notes on detection

HLISA (and Selenium) can be immediately detected if the browser is minimized while actions are being performed HLISA. This can be prevented by never minimizing the window when HLISA is active. Also note, that special keys can be detected, when not covered by HLISA (see the API description *send_keys_to_element* for details).

## Limitations

- HLISA does not support a remote end (Selenium Server).
- It is not possible to call interactions on Elements (`element.click()`-like syntax):

`text_field = webdriver.find_element_by_id("text_field")`

`text_field.send_keys("keys")`

This syntax has to be replaced by ActionChains syntax:

`text_field = webdriver.find_element_by_id("text_field")`

`HLISA_ActionChains(webdriver).send_keys("keys", text_field).perform()`

- It is not possible to use HLISA functionality after calling mouse movement functions of the original Selenium ActionChains API.

- The *context_click()* function is not human like.
- The *drag_and_drop()* function is not human like.
- The *drag_and_drop_by_offset()* function is not human like.

- HLISA is slow - it interacts with a web page web only as fast as a standard human would. This contrasts to Selenium which interacts with web pages in a superhuman fashion - just like a standard robot would. Please note that although HLISA is slow, this is only caused by intentionally introduced delays; HLISA is not significantly more resource intensive than Selenium.

- The **back**() and **forward**() functions of Selenium's **webdriver** object are not combatible with HLISA. Instead, the HLISA_ActionChains provides the functions back() and forward() to be used instead, exposing the same functionality.

## Publication and citation

For more details, please see [our IMC 2021 publication](https://doi.org/10.1145/3487552.3487843). If you use HLISA, you can cite our
work as follow:

```
HLISA: towards a more reliable measurement tool. D. Goßen, H. Jonker, S. Karsch,
B. Krumnow and D. Roefs. In Proceedings of the 21st ACM⁄SIGCOMM Internet 
Measurement Conference (IMC’21). ACM, pp. 380–389, 2021. 
```

or by using this BibTeX entry:

```
@inproceedings{GJKKR21,
  author    = {Daniel Go{\ss}en and
               Hugo Jonker and
               Stefan Karsch and
               Benjamin Krumnow and
               David Roefs},
  title     = {{HLISA:} towards a more reliable measurement tool},
  booktitle	= {Proceedings of the 21st ACM Internet Measurement Conference ({IMC'21})},
  pages		= {380--389},
  year      = {2021},
  url       = {https://doi.org/10.1145/3487552.3487843},
  doi       = {10.1145/3487552.3487843}
}
```


%package help
Summary:	Development documents and examples for HLISA
Provides:	python3-HLISA-doc
%description help
# HLISA

HLISA is a drop-in replacement for the ActionChains object of the Selenium [API](https://www.selenium.dev/selenium/docs/api/py/webdriver/selenium.webdriver.common.action_chains.html) (Python only), featuring more human-like interaction. Besides providing all functionality the original Selenium ActionChains offers, additional interaction functionality is [provided](https://github.com/droefs/HLISA/blob/master/docs/api.md#additional-actions-available-in-hlisa). Calling interaction on elements (`element.click()`) is not provided.

## Important documents
- [API documentation](https://github.com/droefs/HLISA/blob/master/docs/api.md)
- [Changelog](https://github.com/droefs/HLISA/blob/master/docs/changelog.md)

## Demo

![Demo of HLISA and default Selenium in action](https://github.com/droefs/HLISA/raw/master/hlisa_demo.gif "Demo of HLISA and default Selenium in action")

## Installing and updating

### Installing

The package can be installed using pip:

`pip install HLISA`

And upgraded in the same fashion:

`pip install HLISA --upgrade`

(When using OpenWPM, it might be necessary to activate the correct conda environment before installing or upgrading HLISA: `conda activate openwpm`).

## Usage

See the [API description](https://github.com/droefs/HLISA/blob/master/docs/api.md) for all functions. The HLISA_ActionChains can be used just like the Selenium ActionChains object. It is however not possible to use standard Selenium interaction methods before using HLISA in a single session. This means that executing a Selenium ActionChain before executing an HLISA_ActionChain is not possible. Similarly, calling interaction on Elements (`element.click()`) can not be used before executing HLISA_ActionChains. Using Selenium actions to perform web page interaction before using HLISA in a single session can result in unexpected behavior.

### Usage example

```python
from HLISA.hlisa_action_chains import HLISA_ActionChains

human_like_actions = HLISA_ActionChains(webdriver)
human_like_actions.click()
human_like_actions.perform()
```

**The chain pattern works exactly like the Selenium ActionChains:**

```python
actions = HLISA_ActionChains(webdriver)
menu = webdriver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = webdriver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
actions.move_to_element(menu).click(hidden_submenu).perform()
```

**And so does queuing up:**

```python
menu = webdriver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = webdriver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
actions = HLISA_ActionChains(webdriver)`
actions.move_to_element(menu)
actions.click(hidden_submenu)
actions.perform()
```

### Difference in element selection

In contrast to Selenium ActionChains, HLISA_ActionChains functions do not select items when the elements are hidden (for example behind an image). This can cause different results. If an item is not selected because it is hidden, HLISA prints a message to the console. 

### More fine-grained control

By default, HLISA introduces delays within actions to make its interaction with web pages more human-like. An additional delay is added after every action to make the collection of interactions more human-like as well. In case you want to control the delay between actions yourself, use the `addDelayAfter`-flag when adding an action to the HLISA_ActionChain:

`actions.click(addDelayAfter=False)`

This flag ensures no delay is added after the action is completed. Delays within the action are unaffected. This also holds for composite actions, for example `.click` with an element specified `.click(element)`: this first moves the mouse to the element, then performs a click. Even if `addDelayAfter=False` is specified, there will be a pause between the mouse movement and the click (only the delay after the click is removed). To remove both delays, call `.move_to_element(element, addDelayAfter=False)` and `.click(addDelayAfter=False)` instead of `.click(element, addDelayAfter=False)`. This allows for complete control over delays between actions, because no delay or a custom delay can be specified this way. Example:

Standard delay after the mouse movement, standard delay after the click:

```python
HLISA_ActionChains(wd)
.click(element)
.perform()
```

Standard delay after the mouse movement, no delay after the click:

```python
HLISA_ActionChains(wd)
.click(element, addDelayAfter=False)
.perform()
```

No delay after the mouse movement, no delay after the click:

```python
HLISA_ActionChains(wd)
.move_to_element(element, addDelayAfter=False)
.click(addDelayAfter=False)
.perform()
```

Custom delay after the mouse movement, custom delay after the click:

```python
HLISA_ActionChains(wd)
.move_to_element(element, addDelayAfter=False)
.pause(0.1)
.click(addDelayAfter=False)
.pause(0.2)
.perform()
```

## API
Check the [API description under docs/api.md.](https://github.com/droefs/HLISA/blob/master/docs/api.md)

## Migrating from Selenium ActionChains to HLISA ActionChains

The functionality HLISA_ActionChains provides is a superset of the functionality provided by Selenium ActionChains. Therefore, migrating is trivial if the existing codebase only uses Selenium ActionChains:

1: import the HLISA ActionChains object:

`from HLISA.hlisa_action_chains import HLISA_ActionChains`

2: replace all occurrences of `ActionChains` by `HLISA_ActionChains`:

`actions = ActionChains(driver)` becomes `actions = HLISA_ActionChains(driver)`

If the syntax form of directly calling interactions on Elements is used (`element.click()`) in the existing codebase, migrating entails rewriting this syntax into ActionChains syntax. Depending on the existing codebase, this can be a time-consuming process.

3: only applicable if `element.click()`-like syntax (calling interaction directly on elements) was used: replace this type of syntax with HLISA_ActionChains syntax (which is equal to Selenium's ActionChains syntax). For example, `element.click()` becomes `HLISA_ActionChains(driver).click(element).perform()`.

## How does it work?

HLISA uses the Selenium API to interact with web pages. Some actions only feature additional delays. For example, HLISA_ActionChains(wd)[.click()](https://github.com/droefs/HLISA/blob/962d5bbc6b8dca64171dbc465be69f9e5dcd1bd4/src/HLISA/selenium_actions.py#L35) is implemented as:

```python
    def click(self, element=None):
        if element is not None:
            self.move_to_element(element)
        self.actions.click_and_hold()
        self.actions.pause(np.random.normal(0.092, 0.018))
        self.actions.release()
        self.addDelayAfterAction()
        return self
```

Other functions add additional actions. For example, a HLISA mouse movement consists of hundreds of tiny Selenium mouse movements that together form a jittery curve.
'''

## Notes on detection

HLISA (and Selenium) can be immediately detected if the browser is minimized while actions are being performed HLISA. This can be prevented by never minimizing the window when HLISA is active. Also note, that special keys can be detected, when not covered by HLISA (see the API description *send_keys_to_element* for details).

## Limitations

- HLISA does not support a remote end (Selenium Server).
- It is not possible to call interactions on Elements (`element.click()`-like syntax):

`text_field = webdriver.find_element_by_id("text_field")`

`text_field.send_keys("keys")`

This syntax has to be replaced by ActionChains syntax:

`text_field = webdriver.find_element_by_id("text_field")`

`HLISA_ActionChains(webdriver).send_keys("keys", text_field).perform()`

- It is not possible to use HLISA functionality after calling mouse movement functions of the original Selenium ActionChains API.

- The *context_click()* function is not human like.
- The *drag_and_drop()* function is not human like.
- The *drag_and_drop_by_offset()* function is not human like.

- HLISA is slow - it interacts with a web page web only as fast as a standard human would. This contrasts to Selenium which interacts with web pages in a superhuman fashion - just like a standard robot would. Please note that although HLISA is slow, this is only caused by intentionally introduced delays; HLISA is not significantly more resource intensive than Selenium.

- The **back**() and **forward**() functions of Selenium's **webdriver** object are not combatible with HLISA. Instead, the HLISA_ActionChains provides the functions back() and forward() to be used instead, exposing the same functionality.

## Publication and citation

For more details, please see [our IMC 2021 publication](https://doi.org/10.1145/3487552.3487843). If you use HLISA, you can cite our
work as follow:

```
HLISA: towards a more reliable measurement tool. D. Goßen, H. Jonker, S. Karsch,
B. Krumnow and D. Roefs. In Proceedings of the 21st ACM⁄SIGCOMM Internet 
Measurement Conference (IMC’21). ACM, pp. 380–389, 2021. 
```

or by using this BibTeX entry:

```
@inproceedings{GJKKR21,
  author    = {Daniel Go{\ss}en and
               Hugo Jonker and
               Stefan Karsch and
               Benjamin Krumnow and
               David Roefs},
  title     = {{HLISA:} towards a more reliable measurement tool},
  booktitle	= {Proceedings of the 21st ACM Internet Measurement Conference ({IMC'21})},
  pages		= {380--389},
  year      = {2021},
  url       = {https://doi.org/10.1145/3487552.3487843},
  doi       = {10.1145/3487552.3487843}
}
```


%prep
%autosetup -n HLISA-1.5.0

%build
%py3_build

%install
%py3_install
install -d -m755 %{buildroot}/%{_pkgdocdir}
if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
pushd %{buildroot}
if [ -d usr/lib ]; then
	find usr/lib -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
if [ -d usr/lib64 ]; then
	find usr/lib64 -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
if [ -d usr/bin ]; then
	find usr/bin -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
if [ -d usr/sbin ]; then
	find usr/sbin -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
touch doclist.lst
if [ -d usr/share/man ]; then
	find usr/share/man -type f -printf "\"/%h/%f.gz\"\n" >> doclist.lst
fi
popd
mv %{buildroot}/filelist.lst .
mv %{buildroot}/doclist.lst .

%files -n python3-HLISA -f filelist.lst
%dir %{python3_sitelib}/*

%files help -f doclist.lst
%{_docdir}/*

%changelog
* Fri Jun 09 2023 Python_Bot <Python_Bot@openeuler.org> - 1.5.0-1
- Package Spec generated