<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kayYOLO</title>
    <description>The latest articles on DEV Community by kayYOLO (@kayyolo).</description>
    <link>https://dev.to/kayyolo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F905262%2F09032bb8-ce6c-46a1-abce-c709d46d7eeb.png</url>
      <title>DEV Community: kayYOLO</title>
      <link>https://dev.to/kayyolo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kayyolo"/>
    <language>en</language>
    <item>
      <title>Clicknium Cookbook</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Thu, 09 Mar 2023 12:03:45 +0000</pubDate>
      <link>https://dev.to/kayyolo/clicknium-cookbook-1ai2</link>
      <guid>https://dev.to/kayyolo/clicknium-cookbook-1ai2</guid>
      <description>&lt;p&gt;&lt;a href="https://www.clicknium.com/documents" rel="noopener noreferrer"&gt;Clicknium&lt;/a&gt; is a Python UI automation library used primarily for automating Windows desktop applications and web applications. As the documents are hard to learn the tool quickly, this article will provide a systematic guide on how to use Clicknium.&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Basic Concepts
&lt;/h1&gt;

&lt;p&gt;Clicknium generates a locator by recording mouse clicks on UI elements, which stores various properties of the UI element. This allows Clicknium to locate the corresponding UI element by using the Locator. Once the UI element is located, Clicknium provides various common methods for operating UI elements, such as inputting (set_text), mouse clicks (Click), etc. With these methods, Python developers can write UI automation scripts easily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clicknium Development Kit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Clicknium Python SDK is the automation core of Clicknium. Around this core, Clicknium provides a series of plug-ins to assist in developing automation scripts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clicknium VS Code plug-in: manage and debug locators, provide Python code completion and intelligent prompts.&lt;/li&gt;
&lt;li&gt;Clicknium browser plug-in: enhance web automation capabilities, support Chrome, Firefox, Edge, Brave, and Vivaldi.&lt;/li&gt;
&lt;li&gt;Clicknium Recorder: supports recording UI elements to generate locators.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://pypi.org/project/clicknium/" rel="noopener noreferrer"&gt;Clicknium Python SDK&lt;/a&gt; can be installed via pip install clicknium. After searching for Clicknium in the VS Code extension and installing the extension, various plug-ins for Clicknium and the SDK can be managed and updated in the extension.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Development Environment Configuration
&lt;/h1&gt;

&lt;p&gt;Windows 7 SP1+ is required:&lt;br&gt;
Search for Clicknium in the VS Code extension and install it:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309150755.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309150755.png"&gt;&lt;/a&gt;&lt;br&gt;
Python module can also be installed by &lt;code&gt;pip install clicknium&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  3.Automation Script Development Process
&lt;/h1&gt;
&lt;h2&gt;
  
  
  3.1 Sample Script
&lt;/h2&gt;

&lt;p&gt;First, take a look at the sample script. Open VS Code, enter Clicknium: Sample with Ctrl+Shift+P, and then select a new empty directory to store the sample project.&lt;/p&gt;

&lt;p&gt;Now we have the following sample project. Press F5 to run and Ctrl+F5 to debug.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309160436.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309160436.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The directory structure of the sample project:&lt;/p&gt;

&lt;p&gt;/.locator: Locator information&lt;/p&gt;

&lt;p&gt;/.locator/sample_img: snapshot of the locator&lt;/p&gt;

&lt;p&gt;/.locator/sample.cnstore: stores the properties of this Locator&lt;/p&gt;

&lt;p&gt;Code analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Part 1: Installing the browser plug-in&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install_or_update&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please open edge browser to enable clicknium extension, then run sample again.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It is easy to understand that the corresponding browser plug-in needs to be installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Part 2&lt;/strong&gt;：Web automation, automatically open your browser, go to bing search, enter clicknium in the input box, and click the search button.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.bing.com/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_sb_form_q&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;clicknium&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Line 1: Using clicknium to call the Edge browser and open the Bing homepage, returning the corresponding browser tab.&lt;/p&gt;

&lt;p&gt;Line 2: Calling find_element within the tab and passing in the Locator of the input box as a parameter, then using the set_text API to input the text information.&lt;/p&gt;

&lt;p&gt;Line 3: Calling find_element within the tab and passing in the Locator of the search button as a parameter, then using the click function.&lt;/p&gt;

&lt;p&gt;Line 4&amp;amp;5: Waiting for 3 seconds, then closing the corresponding tab.&lt;/p&gt;

&lt;p&gt;Through this code snippet, one can roughly understand the logic of clicknium. Clicknium provides functions such as find_element that accept the locator parameter to obtain UI elements. It also provides some common methods for operating UI, such as set_text, click, etc., to simulate human operations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Part 3&lt;/strong&gt;：Windows desktop automation. Open Notepad and enter "clicknium".
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    process = subprocess.Popen("notepad")
    ui(locator.sample.notepad.document_15).set_text("clicknium")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The API for Desktop Applications and Web browsers is the same.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;the Clicknium core: Locator&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2F87c78cad99044844a99a229119404b6f~tplv-k3u1fbpfcp-zoom-1.image" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2F87c78cad99044844a99a229119404b6f~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/a&gt;​&lt;/p&gt;

&lt;p&gt;You might have no idea about how to create a locator since the sample is without a process. It will be introduced in the next part. &lt;/p&gt;
&lt;h2&gt;
  
  
  Developing Your Own Automation Scripts from Scratch
&lt;/h2&gt;

&lt;p&gt;Starting from scratch, use the Chrome browser to search for the Clicknium website and automatically register for an account.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Creating a Project&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a folder named ClickniumSample to store the Python Project, open the folder with VS Code, and create a Python file named Sample.py.&lt;/p&gt;

&lt;p&gt;Open the Clicknium official website:&lt;a href="https://www.clicknium.com/" rel="noopener noreferrer"&gt;The best python automation module | Clicknium&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In VS Code, find the Capture button next to LOCATOR and launch the Clicknium Recorder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309180528.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309180528.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hold down Ctrl and click on the Sign Up button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309182104.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309182104.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon success, the Locator for the registration button is obtained.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309182941.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309182941.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Locators can be organized in a folder structure or renamed by oneself. The structure is similar to that of namespaces, so special characters such as spaces cannot appear in the locator name.&lt;/p&gt;

&lt;p&gt;After generating the Locator, we can use the method &lt;a href="https://www.clicknium.com/documents/references/python/globalfunctions/find_element" rel="noopener noreferrer"&gt;find_element&lt;/a&gt; to locate the corresponding UI element. There will be intelligent prompts after inputting the Locator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183303.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183303.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the Mouse is placed on the Locator, a locator snapshot will appear to help identify the UI element corresponding to the Locator, and validation and re-recording can also be done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183401.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183401.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After locating the UI element, a series of operations are supported. Since the object is a button, we choose to click:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183423.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183423.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the same method, record the five input boxes and one button on the registration page:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183443.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309183443.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The button uses the Click method, and the input boxes use set_text. Use F5 to run and check the effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Locator&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.clicknium.com/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicknium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button_sign_up&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Kay&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Whitlock&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youremail@youremail.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youpassword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicknium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_firstname&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicknium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_lastname&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicknium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicknium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password_password&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicknium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password_confirmpassword&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicknium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button_sign_up&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  4. Mouse and Keyboard Input
&lt;/h1&gt;

&lt;p&gt;Clicknium's documentation provides a detailed description of the mouse and keyboard operations supported. Here is a brief introduction.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mouse Input:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mouse operations supported by Clicknium can be found at &lt;a href="https://www.clicknium.com/documents/references/python/mouse/" rel="noopener noreferrer"&gt;Mouse&lt;/a&gt;. Taking a single click as an example, let's take a look at the parameters supported by the click function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;mouse_button&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;left&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;middle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;right&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MouseButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;mouse_location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MouseLocation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MouseLocation&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mouse-emulation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;control-invocation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;MouseActionBy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MouseActionBy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;modifier_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nonekey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ctrl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shift&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;win&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ModifierKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoneKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
            Single click the target element.

            Parameters:

                mouse_button: The available values are: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;left&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;right&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; and &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;center&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, default is &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;left&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.  

                mouse_location: it is set to define the position where the element is to be clicked. The default position is the center of the element.  

                by: Defines the method to click the UI element.  
                    mouse-emulation: click the target UI element by simulating Mouse.  
                    control-invocation: click the target UI element by invoking its UI method. It may not be supported if it is a Windows desktop element.  
                    default: automatically choose method per element type. For Web element, use `control-invocation`; for Window element, use `mouse-emulation`.  

                modifier_key: The modifier key(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ctrl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shift&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;win&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;) to be pressed along with click, and the default is none.  

                timeout: timeout for the operation, the unit is second, and default is set to 30 seconds.  

            Returns:
                None
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;mouse_button&lt;/strong&gt;: The left or right button of the Mouse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mouselocation&lt;/strong&gt;: Absolute or relative position.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;by&lt;/strong&gt;: There are two modes: mouse-emulation and control-invocation. The names may sound abstract, but the former simulates the behavior of the Mouse, moving the Mouse and clicking it, while the latter uses a system call-like method invocation. In short, mouse-emulation has a higher success rate, while control-invocation has better performance. For desktop automation, it is recommended to use mouse-emulation first, and for browser automation, try control-invocation first and use mouse-emulation if it doesn't work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;modifier_key&lt;/strong&gt;: Achieve the effect of holding down special buttons like alt, ctrl, shift while clicking the Mouse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keyboard Input&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two commonly used keyboard inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inputting text&lt;/li&gt;
&lt;li&gt;Pressing special buttons
For inputting text, the set_text method is generally used:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        
        &lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set-text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sendkey-after-click&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sendkey-after-focus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;InputTextBy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InputTextBy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;overwrite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
            Set text for the target element, it can be used to input text to a system.  

            Parameters:

                text[Requried]: text string to be input.                 

                by: the method to perform the text input operation. 
                    set-text: call system method to set text to the target element. Some Windows application elements may not be supported.  
                    sendkey-after-click: simulate Mouse click to activate the element, then send keys by simulating keyboard.  
                    sendkey-after-focus: set the target element to a focused state, then send keys by simulating keyboard.  
                    default: using different methods per target element type. `set-text` for web element and `sendkey-after-click` for desktop element.  

                overwrite: whether overwrite or append the text on the target element, default is True. 

                timeout: timeout for the operation. The unit of the parameter is seconds. The default is set to 30 seconds.

            Returns:
                No
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parameter Section:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;text&lt;/strong&gt;: The string to be entered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;by&lt;/strong&gt;: set-text is a system call with the best performance and is generally used in browser scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sendkey-after-click&lt;/strong&gt;: Simulates clicking on this UI element and then inputs by simulating the keyboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sendkey-after-focus&lt;/strong&gt;: Sets the target UI element to focus and then inputs by simulating the keyboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;overwrite&lt;/strong&gt;: Can choose to append or overwrite directly.&lt;/p&gt;

&lt;p&gt;Sendkey-after-click is a very commonly used option because, currently, input boxes often need to be clicked by the Mouse to become activated to receive input. They cannot receive input when in an inactive state. This is also the reason why input operations often fail in automation processes. It should be noted that this method is often hijacked by input methods, so when using this parameter, the input method should be disabled and switched to English input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pressing special buttons:&lt;/strong&gt;&lt;br&gt;
The send_hotkey method is mainly used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_hotkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hotkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
            Send hotkey to the cursor&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s current position.

            Parameters:
                hotkey[Requried]: hotkey string represents one key or combined keys. For example, to represent the letter A, input string &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. To represent the letters A, B, and C, input paremeter &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ABC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. For special keys, please refer to [hotkeys](https://docs.microsoft.com/en-au/dotnet/api/system.windows.forms.sendkeys?view=windowsdesktop-6.0#remarks).

            Returns:
                None
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method accepts a string as the hotkey code. The specific hotkey code corresponding to the keyboard button can be found in Microsoft's &lt;a href="https://learn.microsoft.com/en-au/dotnet/api/system.windows.forms.sendkeys?view=windowsdesktop-6.0#remarks" rel="noopener noreferrer"&gt;hotkey list&lt;/a&gt;. For example, if you need to press the Enter key, you can find the code for Enter as {ENTER} in the table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_hotkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{ENTER}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  5. Locator
&lt;/h1&gt;

&lt;p&gt;The Locator is fundamental to locating UI elements. During the recording process, Clicknium Recorder reads various properties and structures of the UI elements, and then uses an algorithm to select the attributes that can help locate the UI element.&lt;/p&gt;

&lt;p&gt;Returning to the directory structure in the Sample, a .locator folder will appear in the Python project directory, which stores the Locator data. VS Code reads the Locator data and displays it under the LOCATORS tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309191257.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309191257.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above picture shows the Locator interface, where you can select the corresponding Locator under the LOCATORS tab to enter the Locator details page.&lt;/p&gt;

&lt;p&gt;There are three buttons on the upper right side: Recapture, Validation, and Action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recapture&lt;/strong&gt;: is mainly used to re-record the Locator after it becomes invalid. There is also an option called recapture&amp;amp;compare for comparison, especially when the Locator becomes invalid and needs to be re-recorded. This option can help identify which attributes have changed and caused the Locator to fail to locate the UI element.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validation&lt;/strong&gt;: is used to test whether the Locator can locate the corresponding UI element. Note that the webpage or app corresponding to the UI element needs to be open, and validation will not actively open it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Action&lt;/strong&gt;: is mainly used to test the usability of the Locator and perform some common UI operations, such as clicking (click), getting text (get_text), and setting text (set_text).&lt;/p&gt;

&lt;h2&gt;
  
  
  5.1 Locator Attributes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301locator_atribute.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301locator_atribute.png"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Locator attributes are actually the content of the Locator. When Clicknium Recorder captures an element, it automatically obtains the element's attributes and selects which attributes to use to locate the UI element. The content in the red box below the three shortcut buttons in the Locator interface is the Locator attributes. In the example in the above picture, there are three lines of attribute content from top to bottom. Clicknium finds the corresponding UI element through the hierarchical structure, and the three lines of attributes in the Locator actually represent the hierarchical relationship. The first line is the chrome.exe application. After locating the chrome application, the second line is the browser tab, and the third line locates the button through the web attribute.&lt;/p&gt;

&lt;h2&gt;
  
  
  5.2 Modifying Locator Attributes
&lt;/h2&gt;

&lt;p&gt;In most cases, the attributes automatically selected by Clicknium can successfully locate the UI element. However, in some cases, we still need to fine-tune the Locator attributes to better match the UI element: first, choose the hierarchical relationship. If it is determined that a certain level of an attribute is not needed, you can uncheck the blue box in front of the attribute to exclude it from locating the element. When you click the hierarchical attribute with the Mouse, the attribute on the right will be expanded. For the attributes within the hierarchy, you can also choose whether to participate in locating. At the same time, in order to improve the generalization ability, the attribute value matching rule supports four modes: equals, startWith, endWith, and regex.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301attributematch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301attributematch.png"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;When the matching pattern is 'equals', wildcard characters are also supported. For example, name='test?_node', where '?' matches one character and * matches zero or more characters.&lt;/p&gt;

&lt;h2&gt;
  
  
  5.3  Parametric Locator:
&lt;/h2&gt;

&lt;p&gt;For multiple UI elements of the same type, most locator attributes are the same, except for one or a few attribute values. In this case, creating a large number of locators is not feasible, especially when the number of elements is not fixed. This is where parametric locators are useful.&lt;/p&gt;

&lt;p&gt;Using parameters in locators:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use Mustache style by declaring a parameter with two curly braces and a variable name in the locator attribute:&lt;code&gt;{{variable}}&lt;/code&gt;. The entire attribute value can be set to a variable."：
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Web ancestorId="{{id}}" tag="A" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or the part of the attribute value can be set as a variable：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Locator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;
&lt;span class="c1"&gt;# replace variable'id' in parametric Locator during runtime
&lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_sb_form_q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;There is a list in the sample website：&lt;a href="https://getbootstrap.com/docs/5.1/components/list-group/" rel="noopener noreferrer"&gt;List group · Bootstrap v5.1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301paraLocatorsamplesite.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301paraLocatorsamplesite.png"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Use the Recorder to capture the fist item of the list, and get the Locator:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309194441.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230309194441.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modify the value of index by creating a variable: &lt;code&gt;{{indexValue}}&lt;/code&gt; using double brackets, and then iterating through each item in the code with a loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Locator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;

&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://getbootstrap.com/docs/5.1/components/list-group/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;variables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;indexValue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_existing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getbootstrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;li_anitem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getbootstrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;li_anitem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5.4 Get values of Locator attribute
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;get_text&lt;/code&gt; method automatically retrieves the text displayed in the corresponding UI element. When we need to obtain other attribute values of the UI element, we can use the &lt;a href="https://www.clicknium.com/documents/references/python/uielement/get_property" rel="noopener noreferrer"&gt;get_property&lt;/a&gt; method. Clicknium supports multiple automation technologies (refer to the &lt;a href="https://www.clicknium.com/documents/concepts/" rel="noopener noreferrer"&gt;Automation Concepts&lt;/a&gt;), and different automation technologies will generate different locators. Among them, Web corresponds to the browser, UIA and IA correspond to Windows desktop applications. For Web elements, on the Web automation page, you can find &lt;a href="https://www.clicknium.com/documents/concepts/web#web-element-properties" rel="noopener noreferrer"&gt;the list of properties (Web element properties)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301element%2520properties.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301element%2520properties.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Locator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;
&lt;span class="c1"&gt;#get the URL of currentpage
&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_sb_form_q&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;# get the title of the UI element
&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_sb_form_q&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Capture Similar elements
&lt;/h2&gt;

&lt;p&gt;We often need to handle a large number of similar elements in web pages or applications, such as UI elements in lists and grids. Sequentially capturing these elements will generate a large number of locators, which is obviously not a good method. Some users even ask how to traverse a locator folder when the same type of Locator is placed in a folder. Of course, using parameterized locators mentioned earlier is also a way. However, on the one hand, you need to analyze which attribute and what value to traverse UI elements, and on the other hand, the range of parameters may be unknown, especially as the application becomes more and more complex and more and more dynamic loading is used, leading to the total number of UI elements to be captured cannot be predicted.&lt;/p&gt;

&lt;p&gt;Usually, we use libraries like BeautifulSoup to parse the HTML structure of websites. As the website styles become more and more complex, the content captured is not always in the same structure. Each item may be wrapped in multiple layers of divs or other elements. Therefore, when parsing, we need to analyze the HTML structure and build an algorithm to find the smallest common node of all elements and traverse the structure. This process is indeed time-consuming but can be solved by algorithms.&lt;/p&gt;

&lt;p&gt;Clicknium Recorder includes a feature for capturing similar elements. Users can capture two similar (same level) elements, and Clicknium's built-in algorithm automatically parses the HTML structure and calculates the minimum common node and hierarchical information to capture similar elements. If the calculated element is not what the user wants, a third capture can be performed, and the algorithm will recalculate the capture path based on the information of three UI elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 how to use similar elements：
&lt;/h3&gt;

&lt;p&gt;Using the &lt;a href="https://opensea.io/collection/okay-bears" rel="noopener noreferrer"&gt;Okay Bear&lt;/a&gt; image in Opensea as an example, which is a typical Grid structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vlookujin49txh879nk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vlookujin49txh879nk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;a.  Click the Capture button in the VS Code plug-in to start the Recorder: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4wwy0n9kutxgxgk961q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4wwy0n9kutxgxgk961q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;b. Click on Similar elements in the Recorder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs5vd31kurx3khq95ldyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs5vd31kurx3khq95ldyg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;c. Ctrl + Mouse click to grab the first and second elements.：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhr1kzvezg5yrfal6l3n8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhr1kzvezg5yrfal6l3n8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95ne8byp0r4qj4iog8v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95ne8byp0r4qj4iog8v1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After crawling the Locator corresponding to the similar elements, call &lt;a href="https://www.clicknium.com/documents/references/python/webdriver/browser/browsertab/webelement%20/find_elements" rel="noopener noreferrer"&gt;find_elements&lt;/a&gt; to return a UI element list (&lt;a href="https://www.clicknium.com/documents/references/python/webdriver/browser/browsertab%20/webelement/find_element" rel="noopener noreferrer"&gt;find_element&lt;/a&gt; returns a single UI element.&lt;/p&gt;

&lt;p&gt;Sample code：&lt;/p&gt;

&lt;p&gt;Get the picture URL by &lt;a href="https://www.clicknium.com/documents/references/python/uielement/get_property" rel="noopener noreferrer"&gt;get_property&lt;/a&gt;. Download the picture using request lib, and use &lt;a href="https://www.clicknium.com/documents/references/python/uielement/send_hotkey" rel="noopener noreferrer"&gt;send_hotkey&lt;/a&gt; to press PgDn key to scroll and load more pictures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Locator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://opensea.io/collection/okay-bears&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;nftDic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;newDic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;nfts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opensea&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;img_okay_bear&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nft&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nfts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nftDic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;newDic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;
                &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;newDic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Downloading:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;imagePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.\image&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt; + key + &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
            with open(imagePath,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;) as f:
                f.write(r.content)

        nftDic = nftDic | newDic
        if finish:
            break
        else:
            print(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)
            cc.send_hotkey(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PGDN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)

if __name__ == &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:
    main()
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Get structured data
&lt;/h2&gt;

&lt;p&gt;In automated scenarios, there is a great demand for obtaining structured data, especially tabular data. Capturing similar elements is only suitable for capturing one column of data. Of course, one can capture a table column by column, but this approach may lead to alignment issues between different columns, increasing the risk of errors and making the operation very cumbersome.&lt;/p&gt;

&lt;p&gt;There are two common scenarios for structured data: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tables &lt;/li&gt;
&lt;li&gt;Non-tabular structured data. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tables are relatively easy to understand, but what is non-tabular structured data? As mentioned above, in the case of OpenSea's pages, if one needs to simultaneously capture the prices and numbers corresponding to NFT images in order to construct a table, this can be considered non-tabular structured data. Compared with obtaining similar elements, structured data adds a matching algorithm between different columns and a range of functions to facilitate table operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.1 Capturing tabular data.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start the Recorder in VS Code&lt;/li&gt;
&lt;li&gt;Click data scraper in the Recorder&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8przcrswmmrxaz4fpf7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8przcrswmmrxaz4fpf7a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, let's capture the following table in &lt;a href="https://www.coingecko.com/" rel="noopener noreferrer"&gt;Coingecko&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vv78by47ae4aenikz1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vv78by47ae4aenikz1a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use Ctrl+left mouse button to click on the first row and column of data in the table.
Clicknium will automatically detect the capture object for the table, and prompt whether to capture the full table information.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqfdyxvqpes1sq8317q3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqfdyxvqpes1sq8317q3.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Click Yes to see the data preview. On the preview page, you can modify the column name, change the column order, delete the column, and so on. You can also select No, and then select the desired data column by column.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp40dmpipgv3owle833wy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp40dmpipgv3owle833wy.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  7.2 Capture non-tabular structured data.
&lt;/h3&gt;

&lt;p&gt;Let's use an example：&lt;a href="https://www.amazon.com/s?k=gaming+chairs&amp;amp;pd_rd_r=071a746f-f709-4a1c-9131-c355b4cc70db&amp;amp;pd_rd_w=b4pJC&amp;amp;pd_rd_wg=gLsyP&amp;amp;pf_rd_p=12129333-2117-4490-9c17-6d31baf0582a&amp;amp;pf_rd_r=5R8Z3Y5NF2J8G0DQ66PC&amp;amp;ref=pd_gw_unk" rel="noopener noreferrer"&gt;Gaming chairs in Amazon website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, we need to fetch the product name, price and image. The operation is similar to capturing similar elements, where two elements determine a column.&lt;/p&gt;

&lt;p&gt;a. Capture the first cell in the first column: the first product name.&lt;/p&gt;

&lt;p&gt;b. Capture the second cell in the first column: the second product name.&lt;/p&gt;

&lt;p&gt;c. The first column is captured successfully, click Add column to start capturing the second column elements.&lt;/p&gt;

&lt;p&gt;d. Capture the second column, the first element: the first product price.&lt;br&gt;
......&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xtbbxjx5dpa9me4vkm7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xtbbxjx5dpa9me4vkm7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After capturing, Clicknium will organize the data into tables.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230310155948.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FkayYOLO%2Fpichost%2Fmain%2Fpic%2Fzh20230301%2F20230310155948.png"&gt;&lt;/a&gt;&lt;br&gt;
On the preview page, you can also change the column names, and column order and select different attributes as column values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1cuuo9ivodk8f72dtkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1cuuo9ivodk8f72dtkz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sample Code:&lt;br&gt;
For structured data, Clicknium provides the &lt;a href="https://www.clicknium.com/documents/references/python/globalfunctions/scrape_data" rel="noopener noreferrer"&gt;scrape_data&lt;/a&gt; method, which returns text in JSON format. Not only this function supports passing in the Locator of the page flip button to achieve automatic page flip, but page flip also supports setting controls and simulating the Mouse, etc., waiting for the page to load, grabbing the number of data bars, control and timeout.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdehy1r7rdwj0au9avjhw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdehy1r7rdwj0au9avjhw.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Locator&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scrape_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json_normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Automation Technology
&lt;/h2&gt;

&lt;p&gt;By default, Clicknium will automatically select the appropriate automation technology. However, when automating desktop applications, sometimes it is necessary to choose a different automation technology, and different automation technologies are thought to have different locator attributes.&lt;/p&gt;

&lt;p&gt;Clicknium includes automation technologies：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.clicknium.com/documents/concepts/web" rel="noopener noreferrer"&gt;Web Automation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.clicknium.com/documents/concepts/uia" rel="noopener noreferrer"&gt;UIA&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.clicknium.com/documents/concepts/ia" rel="noopener noreferrer"&gt;IA&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.clicknium.com/documents/concepts/image" rel="noopener noreferrer"&gt;Image Recognition&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.clicknium.com/documents/concepts/java" rel="noopener noreferrer"&gt;Java&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.clicknium.com/documents/concepts/sap" rel="noopener noreferrer"&gt;SAP Automation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that the Locator recorded by different automation technologies has different Locator attributes and Element properties. For Element properties, you can check the documentation of the corresponding technology above and get the value of the property through the get_property method.&lt;/p&gt;

&lt;p&gt;The following table provides a summary of the automation technologies supported by Clicknium.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Automation Technology&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Introduction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Browser Automation&lt;/td&gt;
&lt;td&gt;Chrome/Edge/IE/Firefox etc.&lt;/td&gt;
&lt;td&gt;Chrome DevTools Protocol/ Web elements are controlled using Clicknium browser plug-in with injected JavaScript scripts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UIA&lt;/td&gt;
&lt;td&gt;Windows desktop application&lt;/td&gt;
&lt;td&gt;Based on Microsoft UI Automation, it has richer method and property information than IA, and is specially optimized for WPF.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IA&lt;/td&gt;
&lt;td&gt;Windows desktop application&lt;/td&gt;
&lt;td&gt;Based on Microsoft Active Accessibility (MSAA), it exposes some of the interface properties and APIs using the COM interface. Better support for software that is older in development.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image Recognition&lt;/td&gt;
&lt;td&gt;try with other automation tech failed&lt;/td&gt;
&lt;td&gt;Based on Open CV, it is also the reason why the Clicknium Python SDK is relatively large&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JAVA automation&lt;/td&gt;
&lt;td&gt;automate Java GUI Application&lt;/td&gt;
&lt;td&gt;Based on the Java Access Bridge and enhanced with AWT components and more, you need to rely on the Clicknium Java plug-in.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SAP automation&lt;/td&gt;
&lt;td&gt;SAP WinGUI API&lt;/td&gt;
&lt;td&gt;Based on SAP GUI Scripting.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In the Recorder, the default options can be modified to select the automation techniques you need:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7zvwhd2ojo7uaqgwz90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7zvwhd2ojo7uaqgwz90.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Pack the Clicknium project as an executable file
&lt;/h2&gt;

&lt;p&gt;The user of an automation script is not necessarily the Python programmer himself. When automation scripts need to be handed off to different users, there are a variety of issues that need to be addressed. It is possible that the other party does not have a Python environment, lacks a particular Python library, or has a version conflict, or even that the other party is a business person and not a programmer. Packaging scripts into human-running exe executables can be a good solution to these problems.&lt;/p&gt;

&lt;p&gt;Packing method：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Clicknium Project&lt;/li&gt;
&lt;li&gt;  PyInstaller&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  9.1 Packed by Clicknium Project
&lt;/h3&gt;

&lt;p&gt;Clicknium Package is Clicknium's built-in project management approach, designed to ensure that automation scripts are developed, debugged, executed and distributed in a way that guarantees the same operational results.&lt;/p&gt;

&lt;p&gt;a. Create Clicknium Project&lt;/p&gt;

&lt;p&gt;In VS Code, press Ctrl+Shift+P to bring up the Command Palette, select Clicknium: Create Project, and specify a path to save the project. During the project creation process, a virtual environment will be created for the project at the same time. You can see the environment information displayed next to the Python interpreter in the bottom right corner of VS Code.&lt;/p&gt;

&lt;p&gt;Unlike a normal Python project, several files are automatically created in this Project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app.py: Python source file&lt;/li&gt;
&lt;li&gt;logo.icon: the Icon of the packaged executable&lt;/li&gt;
&lt;li&gt;clicknium.yaml: the configuration file for the Clicknium Project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;clicknium.yaml, which contains basic information about the project, including entry and dependencies, log paths, etc. The logo.icon can be replaced with the icon file you want.&lt;/p&gt;

&lt;p&gt;b. run and debug Clicknium Project&lt;/p&gt;

&lt;p&gt;Similarly, in VS Code, press Ctrl+Shift+P to bring up the Command Palette, and select Clicknium: Run Project. clicknium will run the project with the configuration in clicknium.yaml. When you run the file directly from F5, you will not see the configuration in yaml for deployment and execution.&lt;/p&gt;

&lt;p&gt;c. Clicknium Project package&lt;/p&gt;

&lt;p&gt;In VS Code, press Ctrl+Shift+P to bring up the Command Palette, select Clicknium: Package Project, then select a path to store the executable, then select console, if the script contains a graphical interface, please select GUI, otherwise the graphical interface may not be displayed properly. Clicknium will package the script according to the information in clicknium.yaml.&lt;/p&gt;

&lt;p&gt;The following is an example of a clicknium.yaml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;startUp: app
ignoreFiles: .gitignore
log:
  folder: 
  type: File
type: project
requirements:
  python: 3.9.13
  pip: 
  packages:
  - package: clicknium
    version: 
  - package: pandas
    version: 1.5.3
  locators: []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example：&lt;/p&gt;

&lt;p&gt;app:the entry point file of the Python program&lt;/p&gt;

&lt;p&gt;log: The default log path is C:\Users{currentUser}\AppData\Local\Clicknium\Log. It can be modified to other paths. For example, the current path is .\&lt;/p&gt;

&lt;p&gt;python: the version of the Python interpreter to be packaged into the executable file. &lt;/p&gt;

&lt;p&gt;Clicknium will automatically scan for Python libraries used in the script and automatically add the corresponding library name and version number. If there are problems with the automatic addition, you can modify this section manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.2 Package by PyInstaller
&lt;/h3&gt;

&lt;p&gt;In addition to the built-in packaging method, a more common practice in Python development is to use the Pyinstaller: &lt;a href="https://pyinstaller.org/en/stable/" rel="noopener noreferrer"&gt;PyInstaller Manual&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To keep the project clean, it is still recommended to use a Python virtual environment for development. Typically, the Python virtual environment used for a project can be found by opening the settings.json file in the .vscode folder of the project file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmxzahxphu9lqj7vovhs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmxzahxphu9lqj7vovhs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;a. Go to the directory of the virtual environment and use &lt;code&gt;pip install pyinstaller&lt;/code&gt; to install pyinstaller. use the &lt;code&gt;pip list&lt;/code&gt; to see what pyinstaller is included and the specific version information.&lt;/p&gt;

&lt;p&gt;b. Edit publish.spec&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xs5wkz774di7fjwu9vo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xs5wkz774di7fjwu9vo.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configuration description：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Project location&lt;/strong&gt;：{$"project app.py full path"}，input the full address of the project app.py, such as 'c:\Users\{Username}\Desktop\Sample\app.py'&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Clicknium SDK address&lt;/strong&gt;：($'clicknium .lib automation full path', 'clicknium\.lib\automation')，input Python virtual environment site-packages folder clicknium under.lib\automation，such as：binaries=[('C:\Users\{Username}\AppData\Local\Clicknium\Envs\Sample_17aea73e4ca65262\.virtualEnv\Lib\site-packages\clicknium\.lib\automation', 'clicknium\.lib\automation')]&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Locator address&lt;/strong&gt;：datas=[($'project .locator full path', '.locator')]，input the .locator address of project, such as, datas=[('c:\Users\YanZhiwei\Desktop\Sample\.locator', '.locator')]&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Executable file name&lt;/strong&gt;：name=$'project name', Fill in the package to generate exe name. You can fill in your own&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following is an example.：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# -*- mode: python ; coding: utf-8 -*-


block_cipher = None


a = Analysis(
    ['c:\Users\KayYOLO\Desktop\Sample\app.py'],
    pathex=[],
    binaries=[('C:\Users\KayYOLO\AppData\Local\Clicknium\Envs\Sample_17aea73e4ca65262\.virtualEnv\Lib\site-packages\clicknium\.lib\automation', 'clicknium\.lib\automation')],
    datas=[('c:\Users\KayYOLO\Desktop\Sample\.locator', '.locator')],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='Sample',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. Frequently Asked Questions：
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 How to launch a Windows application
&lt;/h3&gt;

&lt;p&gt;You can launch desktop applications using Python's subprocess module&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;

&lt;span class="n"&gt;process_notpad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notepad&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;process_feishu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;C:\Users\kay\AppData\Local\Feishu\Feishu.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10.2 How to set a timer to run
&lt;/h3&gt;

&lt;p&gt;a. Search for Task Scheduler in the taskbar&lt;/p&gt;

&lt;p&gt;b. Create a Task or Create a basic Task&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F876al9nqmpmfe26hi19j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F876al9nqmpmfe26hi19j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;c. Task Config：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Task name&lt;/li&gt;
&lt;li&gt; Trigger：Select trigger conditions, daily, weekly or monthly, at startup, at login, etc.&lt;/li&gt;
&lt;li&gt; Action： Select Launcher, Program or Script: Fill in the address of python.exe. Add parameter: the address of the automation script.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  10.3 For the same website, if you open multiple browsers to log in to different accounts
&lt;/h3&gt;

&lt;p&gt;With the browser automation extension, attach method is the choice. If you don't need to mouse and keyboard simulation, it is recommended to use Chrome and Edge browsers to call the CDP interface and bind the tab object to the corresponding browser tab. To make web browser instances not share cookies between them and to be able to log into different accounts on the same website, different User profiles can be used.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://www.clicknium.com/documents/references/python/webdriver/open" rel="noopener noreferrer"&gt;open method&lt;/a&gt; method：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def open(
        self,
        url: str,
        is_maximize: bool = True,
        is_wait_complete: bool = True,
        userdata_folder_mode: Literal["automatic", "default", "custom"] = WebUserDataMode.Automatic,
        userdata_folder_path: str = "",
        timeout: int = 30
    ) -&amp;gt; BrowserTab 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;set &lt;code&gt;userdata_folder_mode&lt;/code&gt; to 'custom', and pass different folder paths to &lt;code&gt;userdata_folder_path&lt;/code&gt;，as different addresses to store the user profile. For different browser tab, use differnet path, instant multi-account login is available.&lt;/p&gt;

&lt;h3&gt;
  
  
  10.4 Why sometimes the script will be stuck in the main for a long time? How to check the log？
&lt;/h3&gt;

&lt;p&gt;Most scripts get stuck because they cannot find the UI element corresponding to the Locator. Clicknium has a default timeout of 30 seconds for locator operations. You can check the API documentation for the timeout time of the method. If you get stuck, first use &lt;code&gt;Validation&lt;/code&gt; to make sure that the Locator can recognize the UI element.&lt;br&gt;
If it didn't work, use &lt;code&gt;Recapture&amp;amp;Compare&lt;/code&gt; to check the difference for the current UI element attribute and the old locator attribute.&lt;br&gt;
The default path to the logs：C:\Users{currentUser}\AppData\Local\Clicknium\Log&lt;/p&gt;

&lt;h3&gt;
  
  
  10.5 Why did the Locator fail after a while
&lt;/h3&gt;

&lt;p&gt;There are many reasons why a locator may fail, such as dynamic loading, version updates, and context changes. First, you can use the &lt;code&gt;Recapture&amp;amp;Compare&lt;/code&gt; function on the locator page to re-record and compare the differences between the old and new locators. Different properties will be highlighted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xhq81mmkejfbddu9v6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xhq81mmkejfbddu9v6j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make the Locator more stable, it is recommended to use wildcards, regular expressions, parameterized Locator, and other features to improve the Locator's robustness.&lt;/p&gt;

&lt;h3&gt;
  
  
  10.6 Why Mouse click and type text has no effect
&lt;/h3&gt;

&lt;p&gt;Toggles between the system call method and the simulated mouse method. In some cases, when recording a button, it may record the logo inside the button or the outer border. For system calls, only the button has the click property. Some input boxes also have a click or focus state to be activated, so you can choose to click or focus parameters before input. Since there is no return value after the system call is triggered, Clicknium cannot throw an error. In such cases, it is recommended to click the button in a simulated mouse way.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How we migrate Clicknium to Chrome Manifest V3</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Thu, 03 Nov 2022 03:07:18 +0000</pubDate>
      <link>https://dev.to/kayyolo/how-we-migrate-clicknium-to-chrome-manifest-v3-o6o</link>
      <guid>https://dev.to/kayyolo/how-we-migrate-clicknium-to-chrome-manifest-v3-o6o</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We started a project called &lt;a href="https://www.clicknium.com/"&gt;Clicknium&lt;/a&gt; this year, a Python automation library for browser and desktop applications. It depends on the Clicknium browser extension to control the browser, and simulate mouse and keyboard actions.&lt;br&gt;&lt;br&gt;
Since January 2022, adding new extensions based on Manifest V2 to the Chrome Web Store has been forbidden. All extensions on Manifest V2 will stop working in early 2023, even those that were added to Chrome Web Store earlier. &lt;/p&gt;

&lt;p&gt;We have no choice but to migrate to V3. After we review our code and &lt;a href="https://developer.chrome.com/docs/extensions/mv3/mv3-migration-checklist/"&gt;migration checklist&lt;/a&gt;,&lt;br&gt;
the most significant impact on Clicknium is that running &lt;a href="https://developer.chrome.com/docs/extensions/mv3/intro/mv3-overview/#remotely-hosted-code"&gt;remote code will be forbidden&lt;/a&gt; in &lt;a href="https://developer.chrome.com/docs/extensions/mv3/intro/mv3-overview/"&gt;Manifest V3&lt;/a&gt;.&lt;br&gt;
It asked to include all logic in the extension's package to review the behavior of the extension better.&lt;/p&gt;

&lt;p&gt;How does Clicknium run remote code in Manifest V3? Here is a brief introduction. &lt;/p&gt;
&lt;h2&gt;
  
  
  How Clicknium runs remote code in V2
&lt;/h2&gt;

&lt;p&gt;This is a simple Clicknium automation case, which executes a JS script on the Bing page to set the value of the search box to "Clicknium", and return "success".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bing.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ele&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_sb_form_q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ele&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"function SetText(st){_context$.currentElement.value = st; return &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SetText(&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Clicknium&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Manifest V2:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the background: Through chrome.runtime.sendMessage sends the received string to the content.&lt;/li&gt;
&lt;li&gt;In the content: Using "new Function(jsCode)" to convert the received string to Javascript's Function,
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;innerFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_context$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;innerFunction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;currentElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;targetElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabId&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Manifest V3, &lt;code&gt;Function&lt;/code&gt; and &lt;code&gt;eval&lt;/code&gt; is not available. So the main problem is that how to convert string to Javascript's Function.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Clicknium run remote code in V3
&lt;/h2&gt;

&lt;p&gt;There are two approaches to achieving it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Solution 1&lt;/strong&gt;: Use pop up window to imitate the background scripts/pages.
&lt;/h3&gt;

&lt;p&gt;In Manifest V3, Using &lt;a href="https://developer.chrome.com/docs/extensions/mv3/intro/mv3-overview/#service-workers"&gt;Service worker&lt;/a&gt; replace background scripts/pages. The window object can't be used in the Service worker.&lt;br&gt;
 But we can open a popup window in the Service worker to imitate background scripts/pages.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1&lt;/strong&gt; : Open a popup window in the Service worker.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Get the URL of the popup window.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backgroundUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backgroundPage.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minimized&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;backgroundUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 2&lt;/strong&gt; : In the popup window, when received a message, using chrome.debugger.sendCommand sends to the target of the popup window. And then, get Function from the window object.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Get the target of the popup window&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backgroundUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backgroundPage.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;debugger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTargets&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;backgroundUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Wrap up the Javascript's string, register to the window object&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsCodeWrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`window["evalFunction"] = function () {
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jsCode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
    };`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Attach to the popup window. And send expression.&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;debugger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;debugger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Runtime.evaluate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jsCodeWrapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the function just registered in the window&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrapperFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;evalFunction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Using chrome.scripting.executeScript to run Function in content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scripting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;frameIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frameId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;wrapperFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantage&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remote code works in content and background.&lt;/li&gt;
&lt;li&gt;Support to cross-domain iFrame.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantage&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need to open a popup window. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Solution 2&lt;/strong&gt;: In Service worker, using chrome.debugger.sendCommand sends to content.
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CDPRuntimeEvaluateResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;exceptionDetails&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="nl"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;debugger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;debugger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabId&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Runtime.evaluate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;CDPRuntimeEvaluateResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantage&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need to open a popup window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantage&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not support for cross-domain iFrame. Cross-domain iFrame's target isn't in the list of available debug targets, which uses the chrome.debugger.getTargets to get.&lt;/li&gt;
&lt;li&gt;Remote code can't work in the background.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As cross-domain iFrame is a critical feature we need, Clicknium chooses&lt;code&gt;Solution 1: use popup window&lt;/code&gt; to call chrome.debugger.sendCommand.&lt;br&gt;&lt;br&gt;
Manifest V3 has been supported by Clicknium since version 0.1.10. &lt;br&gt;
You can try it in &lt;br&gt;
&lt;a href="https://pypi.org/project/clicknium/"&gt;pypi&lt;/a&gt; website and Clicknium &lt;a href="https://marketplace.visualstudio.com/items?itemName=ClickCorp.clicknium"&gt;VS Code Extension&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One thing that should be noticed is that the Clicknium browser extension has to work with the Clicknium Python SDK. If we publish the browser extension to Chrome Web Store, all the existing extensions will auto-upgrade to the latest version, and it can not work with the SDK before V0.1.0. So we have to pull it off shelves and wait for a period. If you want to try the M3 version, please upgrade to the latest Python SDK. &lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>news</category>
      <category>javascript</category>
    </item>
    <item>
      <title>[Python]Facebook Scraper via Clicknium</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Thu, 13 Oct 2022 14:29:39 +0000</pubDate>
      <link>https://dev.to/kayyolo/pythonfacebook-scraper-via-clicknium-48k3</link>
      <guid>https://dev.to/kayyolo/pythonfacebook-scraper-via-clicknium-48k3</guid>
      <description>&lt;h1&gt;
  
  
  Facebook Scraper
&lt;/h1&gt;

&lt;p&gt;This is a sample to scrape Facebook posts using Clicknium.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.7+&lt;/li&gt;
&lt;li&gt;Windows 7 SP1+&lt;/li&gt;
&lt;li&gt;Chrome browser&lt;/li&gt;
&lt;li&gt;VS Code&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.clicknium.com/documents#set-up-clicknium-visual-studio-code-extension" rel="noopener noreferrer"&gt;Clicknium&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.clicknium.com/documents/tutorial/extensions/chromeextension#install" rel="noopener noreferrer"&gt;Clicknium Chrome extension&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scrape Facebook posts
&lt;/h2&gt;

&lt;p&gt;We will scrape the post of the Facebook company page as an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Python project
&lt;/h3&gt;

&lt;p&gt;Create a Python file, for example, &lt;code&gt;sample.py&lt;/code&gt;, under a project folder.&lt;br&gt;&lt;br&gt;
Show &lt;code&gt;Locators&lt;/code&gt; under the VS Code Explorer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfoo6opltikzrphg6ug4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfoo6opltikzrphg6ug4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Capture locator
&lt;/h3&gt;

&lt;p&gt;A locator is a tool that targets the UI elements.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login and open the Facebook company page: &lt;a href="https://www.facebook.com/facebook" rel="noopener noreferrer"&gt;https://www.facebook.com/facebook&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;code&gt;Capture&lt;/code&gt; button in VS Code.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgxohozlp7z7mcmjk6lu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgxohozlp7z7mcmjk6lu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;a href="https://www.clicknium.com/documents/tutorial/recorder/capture_similar_elements" rel="noopener noreferrer"&gt;similar elements&lt;/a&gt;
This feature lets you get all the posts on the page that have the same structure. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshkqm87tuinbufcn1kro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshkqm87tuinbufcn1kro.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;Ctrl + Click&lt;/code&gt; to capture the first post words on Facebook:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ey1y7d530gl1um81khl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ey1y7d530gl1um81khl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capture the second post in the same way:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4bzveesq0gc6tjxj754.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4bzveesq0gc6tjxj754.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see there are five elements matched. Click the save button and finish. &lt;/p&gt;
&lt;h3&gt;
  
  
  Get the text via Locator:
&lt;/h3&gt;

&lt;p&gt;To get the locator targets, we can use &lt;a href="https://www.clicknium.com/documents/references/python/globalfunctions/find_element" rel="noopener noreferrer"&gt;find_element&lt;/a&gt; function. In our scenario, we need to get multiple posts so we can use &lt;a href="https://www.clicknium.com/documents/references/python/globalfunctions/find_elements" rel="noopener noreferrer"&gt;find_elements&lt;/a&gt; function to get a result array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;UIs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;facebook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Python code, we can use &lt;code&gt;Locator.&lt;/code&gt; to use the locators we captured using Clicknium in this project. If there is a need to use the same Locator across projects, you can make the locator store into a cloud locator store, and you can reference it anywhere.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhj3af079sf5x30ruksc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhj3af079sf5x30ruksc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we get the UI elements, we need to find an element property that can contain the text info. Check the &lt;a href="https://www.clicknium.com/documents/concepts/web#web-element-properties" rel="noopener noreferrer"&gt;Web elements property&lt;/a&gt;. The property &lt;code&gt;innertext&lt;/code&gt; is what we need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;uis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;facebook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;uis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;innertext&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can print the text to check if it works or not.&lt;br&gt;&lt;br&gt;
If it doesn't work, we need to check the locator page to tune the property. The Locator uses the identity UI elements.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz86eken7eurvx1z3z9un.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz86eken7eurvx1z3z9un.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the above page, you can do some quick validation and action to check if the Locator can work or not. And you can also select and modify which attribute you want to use to locate the UI elements. &lt;/p&gt;
&lt;h3&gt;
  
  
  Go to the next page
&lt;/h3&gt;

&lt;p&gt;The Facebook content will be loaded when you scroll down the page. So if we capture once, we can't get all the information. So we have to capture each page. If we mimic the scroll action of the mouse, it would be hard to control. So the best choice would be to use the &lt;code&gt;PageDown&lt;/code&gt; button in the keyboard. The &lt;a href="https://www.clicknium.com/documents/references/python/uielement/send_hotkey" rel="noopener noreferrer"&gt;send_hotkey&lt;/a&gt; function can do it easily. we can find the &lt;code&gt;Code&lt;/code&gt; for &lt;code&gt;PageDown&lt;/code&gt; is &lt;code&gt;{PGDN}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_hotkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{PGDN}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use a while loop the get all the posts. Since the multiple capture would get the same post for times, we can use a dictionary to store the post and use &lt;code&gt;ancestorid&lt;/code&gt; as the key. &lt;/p&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/automation9417/FacebookScraper" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>programming</category>
      <category>datascience</category>
    </item>
    <item>
      <title>How to attach to existing Browsers in Web Automation</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Tue, 11 Oct 2022 12:52:24 +0000</pubDate>
      <link>https://dev.to/kayyolo/how-to-attach-to-existing-browsers-in-web-automation-40jc</link>
      <guid>https://dev.to/kayyolo/how-to-attach-to-existing-browsers-in-web-automation-40jc</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;For web automation, there are common scenarios containing end-to-end automation without human intervention, headless browser automation, and partial automation.&lt;/p&gt;

&lt;p&gt;Partial automation means that not the entire business process is automated, and humans may operate some in advance due to security concerns, complex operations which are not repetitive but time-consuming, etc. In this automation case, the browser is opened, the human will do the relevant preparation work, and then the automation script will be executed for the repetitive part.&lt;/p&gt;

&lt;p&gt;In this case, attaching the existing browser is necessary for the automation script to handle the same browser which human works on. We are introducing the browser attaching method for different automation libraries here, containing &lt;a href="https://www.selenium.dev/"&gt;Selenium&lt;/a&gt;, &lt;a href="https://playwright.dev/"&gt;Playwright&lt;/a&gt;, and &lt;a href="https://www.clicknium.com/"&gt;Clicknium&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selenium attaches to the existing browser
&lt;/h2&gt;

&lt;h1&gt;
  
  
  Requirements
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Download ChromeDriver from &lt;a href="https://chromedriver.storage.googleapis.com/index.html"&gt;here&lt;/a&gt;. You need to select the same version of chromedriver.exe with your installed chrome browser, which you can see it by &lt;code&gt;chrome://version&lt;/code&gt; in chrome browser.&lt;/li&gt;
&lt;li&gt;Place the chromedriver.exe in the same folder as Chrome.exe. For example, if your Chrome browser file path is &lt;code&gt;C:\Program Files\Google\Chrome\Application\chrome.exe&lt;/code&gt;, then the chromedriver.exe could be accessed with &lt;code&gt;C:\Program Files\Google\Chrome\Application\chromedriver.exe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The browser that needs to be attached should be started with argument --remote-debugging-port, and you also need to operate on this browser. The command looks like this:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=8888&lt;/li&gt;
&lt;li&gt;Notice that if there are other Chrome browsers running in the same time, it is better to close the others and keep the only one that you want to attach later, or the Selenium script might not successfully attach to the right browser, or the page that you want to automate may get refreshed when attaching.
## Code
The idea is to start a Chrome instance by specifying the option of &lt;code&gt;debugger_address&lt;/code&gt;, the port in the address is what we specified in the command before. And then, get to the page where you want to run the Selenium automation script after attaching.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChromeOptions&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.chrome.service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChromeOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debugger_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'8888'&lt;/span&gt;
&lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executable_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;Program Files&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;Google&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;Chrome&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;Application&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;chromedriver.exe"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://contoso.com/u/0/#in?compose=new"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The playwright attaches to the existing browser
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run playwright install to init the playwright prerequisites&lt;/li&gt;
&lt;li&gt;The browser that needs to be attached should be started with argument &lt;code&gt;--remote-debugging-port&lt;/code&gt; , and you also need to operate on this browser. The command looks like this:
&lt;code&gt;"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=8888&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Notice that if there are other Chrome browsers running in the same time, it is better to close the others and keep the only one that you want to attach later. And if there are multiple windows opened from the browser started by the above command, it is better to keep one page with the Url that you want to automate to avoid attaching to a non-target page.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;The playwright provides two ways to attach to existing browsers: &lt;a href="https://playwright.dev/python/docs/api/class-browsertype#browser-type-connect"&gt;connect&lt;/a&gt; and &lt;a href="https://playwright.dev/python/docs/api/class-browsertype#browser-type-connect-over-cdp"&gt;connect_over_cdp&lt;/a&gt;. The &lt;code&gt;connect&lt;/code&gt; needs to work with &lt;code&gt;launchServer&lt;/code&gt; in Node.js, so we will use &lt;code&gt;connect_over_cdp&lt;/code&gt; in Python to manually start the Chrome browser. The code is as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;playwright.sync_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sync_playwright&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;sync_playwright&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect_over_cdp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:8888"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;default_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;default_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Clicknium attaches to exsiting browser
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://marketplace.visualstudio.com/items?itemName=ClickCorp.clicknium"&gt;Clicknium VSCode Extension&lt;/a&gt; and Python module &lt;code&gt;pip install clicknium&lt;/code&gt;. More about &lt;a href="https://www.clicknium.com/"&gt;Clicknium&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install the Clicknium browser extension. There are two ways of doing this:&lt;/li&gt;
&lt;li&gt;Install via Python:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;
&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Install&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt; &lt;span class="n"&gt;VSCode&lt;/span&gt; &lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="n"&gt;UI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Notice that the browser extension needs to be enabled after installation.
## Code
Clicknium provides two ways to &lt;code&gt;attach&lt;/code&gt; existing browsers, attach and &lt;code&gt;attach_by_title_url&lt;/code&gt;. The &lt;code&gt;attach&lt;/code&gt; is to attach a browser by a web element specified in the target browser. The &lt;code&gt;attach_by_title_url&lt;/code&gt; is to attach to a target browser by title or Url. This is more flexible if the target page element can be dynamically changed. The code is as below: (we may use wildcard * if part of the Url may change)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;
&lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attach_by_title_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ulr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'https://contoso.com/u/0/in?id=*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;#browser.find_element(locator.hundun.img)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compare
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V3MzjeGA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qrb9rmurpmm68tswk37r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V3MzjeGA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qrb9rmurpmm68tswk37r.png" alt="Image description" width="880" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is not easy to make attaching to the browser stable. If you have any suggestions on this, please feel free to leave a comment. Thanks.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>[Python]Telegram Automation</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Sat, 08 Oct 2022 12:16:23 +0000</pubDate>
      <link>https://dev.to/kayyolo/pythontelegram-automation-5d9f</link>
      <guid>https://dev.to/kayyolo/pythontelegram-automation-5d9f</guid>
      <description>&lt;h1&gt;
  
  
  Telegram Automation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;It is a sample of using Python code to control the Telegram Windows client and send messages to contacts and the Telegram channel. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step by Step
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/clicknium/clicknium-docs#set-up-clicknium-visual-studio-code-extension"&gt;Set up Clicknium&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install VS Code Clicknium &lt;a href="https://marketplace.visualstudio.com/items?itemName=ClickCorp.clicknium"&gt;Extension&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use the extension to install Clicknium Python &lt;a href="https://pypi.org/project/clicknium/"&gt;SDK&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Log in to your Telegram client.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Capture the search bar  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;code&gt;Capture&lt;/code&gt; button
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1tFOrmVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s1.328888.xyz/2022/10/08/fW1Rm.png" alt="capture button" width="613" height="80"&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Ctrl + Click&lt;/code&gt; to capture search bar
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yRpvfhw---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s1.328888.xyz/2022/10/08/fWKVk.png" alt="search bar" width="796" height="616"&gt;
&lt;/li&gt;
&lt;li&gt;Get the search bar locator
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NQ_0cVuP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s1.328888.xyz/2022/10/08/fWcpE.png" alt="search bar locator" width="880" height="461"&gt;
&lt;/li&gt;
&lt;li&gt;Validate the locator
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--clPwrPQP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s1.328888.xyz/2022/10/08/fW2FJ.png" alt="validate locator" width="880" height="369"&gt;
The validation would be failed. The most simple way to debug this issue, we can use a new feature provided by Clicknium: &lt;code&gt;Recapture &amp;amp; Compare&lt;/code&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Djg0Hj6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s1.328888.xyz/2022/10/08/fWJpo.png" alt="recatpure" width="880" height="213"&gt; 
After recapturing the search bar, we can get the compared model to check the difference between the old and new. 
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nAl04VOC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s1.328888.xyz/2022/10/08/fWyOF.png" alt="compare" width="880" height="494"&gt;
It's easy to get the difference between the old and new is the &lt;code&gt;name&lt;/code&gt; attribute. There is a number that follows the word "Telegram."
We can use the &lt;a href="https://www.clicknium.com/documents/concepts/locator#wildcard-locator"&gt;wildcard&lt;/a&gt; to fix it by changing the number &lt;code&gt;383784&lt;/code&gt; to &lt;code&gt;*&lt;/code&gt; and saving the locator. 
Validate again, and it will succeed. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set text into the search bar&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Include the Clicknium package into your Python code and set the contacts name into the search bar using Clicknium API.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;

&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;telegram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contact_search&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DK H"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Select the contacts by pressing the &lt;code&gt;Enter&lt;/code&gt; key. 
More codes of the key can be found at &lt;a href="https://learn.microsoft.com/en-au/dotnet/api/system.windows.forms.sendkeys?view=windowsdesktop-6.0#remarks"&gt;the page&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    cc.send_hotkey("{ENTER}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Capture the message text input and send messages button using the same way as step 3. &lt;/li&gt;
&lt;li&gt;Code the workflow into Python. You can check the sample in the sample.py file. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/automation9417/TelegramAutomation"&gt;https://github.com/automation9417/TelegramAutomation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Generate reliable locators for web testing or data scrapy</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Tue, 27 Sep 2022 11:14:14 +0000</pubDate>
      <link>https://dev.to/kayyolo/generate-reliable-locators-for-web-testing-or-data-scrapy-33n</link>
      <guid>https://dev.to/kayyolo/generate-reliable-locators-for-web-testing-or-data-scrapy-33n</guid>
      <description>&lt;h1&gt;
  
  
  Generate reliable locators for web testing or data scrapy
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Suppose you do any Web UI testing automation or web data scrapy. In that case, you probably spend a large chunk of development time finding elements on a web page, such as input, checkbox, submit button, table, and divs. It can be challenging to locate the correct elements, especially when they lack unique attributes, such as id, name, and class names; it is even worse if the attributes are dynamic. For example, the id is always changed when opening the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.clicknium.com"&gt;Clicknium&lt;/a&gt; supplies an automation library and development tool, and it can improve developer efficiency and automatically generate locators for elements on any UI (web, desktop application, etc.). The auto-generated locator is a good choice for many general cases.&lt;br&gt;
However, based on some of the scenarios described above, the attributes used for positioning may be dynamic, which requires users to modify the locator. The Clicknium development tools provide multiple functions to help developers easily pick which attributes are used to locate UI elements and to make the final locator more stable.&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with Clicknium, you can try the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ClickCorp.clicknium"&gt;Clicknium Visual Studio Code Extension&lt;/a&gt; first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recapture and Compare
&lt;/h2&gt;

&lt;p&gt;Recapture &amp;amp; Compare allows you to recode the same UI element, create a new location, and present the user with a comparable view.&lt;br&gt;
The user may easily distinguish the dynamic attributes by comparing the new locator to the prior one. The chosen list should not include these dynamic attributes.&lt;/p&gt;

&lt;p&gt;Many websites today include dynamic pages, which means that when a user opens the same page, different material is shown. Locating the element will be challenging in this scenario. The element's locator was successfully found the last time, and it might fail next time. Use the "Recapture and Compare" feature to rapidly decide which properties on the locator should be used in this situation.&lt;/p&gt;

&lt;p&gt;The example below demonstrates how to take advantage of this functionality.&lt;/p&gt;

&lt;p&gt;Case background: The user wants to download the first video cover image from the YouTube main page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QutQA3Jd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8u9yf705u1bh7s7pknv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QutQA3Jd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8u9yf705u1bh7s7pknv.png" alt="Image description" width="851" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It is simple to generate the locator like the one below using Clicknium Recorder:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIgcURaS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/di5ug71stbg4bo12jt60.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIgcURaS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/di5ug71stbg4bo12jt60.png" alt="Image description" width="880" height="412"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you validate the location after refreshing the web page, it may fail because the image has changed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ygRs9crT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvmxe05wlonk1ti62tut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ygRs9crT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvmxe05wlonk1ti62tut.png" alt="Image description" width="841" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let us use 'Recapture and Compare' to recapture the first image again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oDJ815Jv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9xt1rqdp0di4zpifd4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oDJ815Jv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9xt1rqdp0di4zpifd4l.png" alt="Image description" width="880" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will get the following view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ruahOt-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnto5qar4vvjsms2sn8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ruahOt-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnto5qar4vvjsms2sn8v.png" alt="Image description" width="880" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the comparative mode, the values of the attributes "src" and "sInfo" have changed, so we should disregard them and choose different attributes.&lt;/p&gt;

&lt;p&gt;You can uncheck "src" and check "cssSelector" in this situation, then save the locator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Njr2jCOg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k969hzb2biphoxm1gdnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Njr2jCOg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k969hzb2biphoxm1gdnx.png" alt="Image description" width="880" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compared to the old locator, the new one ought to be more reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use custom web attributes
&lt;/h2&gt;

&lt;p&gt;From &lt;a href="https://www.clicknium.com/documents/concepts/locator"&gt;Locator&lt;/a&gt; and &lt;a href="https://www.clicknium.com/documents/concepts/web"&gt;Web Automation&lt;/a&gt;, you know which attributes Clicknium used to locate web element, such as "tag", "id", "name" and so forth.&lt;br&gt;&lt;br&gt;
A web element may occasionally include additional attributes, some of which are significant and can be used to identify the web element.&lt;/p&gt;

&lt;p&gt;The example below demonstrates how to take advantage of this functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample 1: Azure DevOps new work item page
&lt;/h3&gt;

&lt;p&gt;We want to locate the 'Discussion' input area.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gp6DtPme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/524082xhvy7wfuxv141q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gp6DtPme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/524082xhvy7wfuxv141q.png" alt="Image description" width="880" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is simple to generate the locator like the one below using Clicknium Recorder:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NKzkkpen--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9twlsb7modpbbx9v13q3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NKzkkpen--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9twlsb7modpbbx9v13q3.png" alt="Image description" width="880" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this scenario, the "ancestorId" of the produced locator is dynamic; if you create a work item again, the "ancestorId" may change.&lt;br&gt;
Given that Clicknium returns the values for all of the web element's attributes, choosing "aria-label" and excluding "ancestorId" will make the locator more dependable for this sample.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L4_TDXn4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8h6xiz52m8atxemfo9od.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L4_TDXn4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8h6xiz52m8atxemfo9od.png" alt="Image description" width="880" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to be flexible, you should alter the "title" to "New Bug *: - Boards".&lt;br&gt;
Please refer to &lt;a href="https://www.clicknium.com/documents/concepts/locator#wildcard-locator"&gt;wildcard locator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Clicknium provides several ways to make locator more robust:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically generate locator, feasible for many general cases.&lt;/li&gt;
&lt;li&gt;Supply 'Recapture&amp;amp;Compare' tool to help developers to choose stable attributes&lt;/li&gt;
&lt;li&gt;Use custom attributes of web UI element&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>OpenSea NFT Scraper</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Fri, 23 Sep 2022 11:00:48 +0000</pubDate>
      <link>https://dev.to/kayyolo/opensea-nft-scraper-1n3k</link>
      <guid>https://dev.to/kayyolo/opensea-nft-scraper-1n3k</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;OpenSea has a lot of NFT pictures. It's a good example of learning how to scrape. Compared to other typical static websites, pictures in OpenSea are dynamic loading along with the endless scroll. Pictures are loading if they are on the screen and will be gone &lt;br&gt;
when they are out of the screen. &lt;/p&gt;
&lt;h2&gt;
  
  
  Clicknium
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.clicknium.com/documents/"&gt;Clicknium&lt;/a&gt; is a Python automation library and very easy to do this kind of scraping work. It's more than a Python library but also provides a smooth and interactive coding experience with VS Code plugins and browser plugins. &lt;/p&gt;
&lt;h2&gt;
  
  
  Requirement
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Windows7 SP1+ &lt;/li&gt;
&lt;li&gt;Python 3.7+&lt;/li&gt;
&lt;li&gt;VS Code&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to
&lt;/h2&gt;

&lt;p&gt;Let's scrape &lt;a href="https://opensea.io/collection/okay-bears"&gt;Okay Bear&lt;/a&gt; as an example. &lt;/p&gt;
&lt;h3&gt;
  
  
  Picture info
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Okay Bear's page with Chrome.
&lt;/li&gt;
&lt;li&gt;Press F12 to open the DevTools, click the mouse icon, and then click the NFT picture.
In the following pic, we can see:&lt;/li&gt;
&lt;li&gt;Image alt can be used as picture name&lt;/li&gt;
&lt;li&gt;Picture src and srcset with different sizes. 
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dY_HdGNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/010605txekudq6lq6s2z.png" alt="Image description" width="880" height="384"&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Capture Pictures
&lt;/h3&gt;

&lt;p&gt;Capturing similar elements is quite easy for this scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the capture button in VS code extension to start the recorder.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qffCwfJY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/12hlhcvbvtlsio98mexj.png" alt="Image description" width="520" height="207"&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Similar elements&lt;/code&gt; .
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SdPK0UQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8sx4k8fhy8qha7b8qw2m.png" alt="Image description" width="329" height="484"&gt;
&lt;/li&gt;
&lt;li&gt;Ctrl + Click on the first pic and then capture the second.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lcZzNJWy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4jgltyzkojkvo01k912.png" alt="Image description" width="625" height="470"&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zlEklsuk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2qod69mddae93sxvv1nn.png" alt="Image description" width="608" height="794"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also use this way to capture the price. &lt;/p&gt;
&lt;h3&gt;
  
  
  Handle scroll to load pictures
&lt;/h3&gt;

&lt;p&gt;Clicknium provides API to control the mouse and keyboard. In this Scenario, Page-down is the easiest way. More about &lt;a href="https://learn.microsoft.com/en-au/dotnet/api/system.windows.forms.sendkeys?view=windowsdesktop-6.0#remarks"&gt;HotKey&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clicknium.send_hotkey("{PGDN}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download picture
&lt;/h3&gt;

&lt;p&gt;use requests(&lt;code&gt;pip install requests&lt;/code&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code:
&lt;/h2&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/automation9417/OpenSeaScraper"&gt;OpenSeaScraper&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests
from time import sleep
from clicknium import clicknium as cc, locator
def main():
    cc.chrome.open("https://opensea.io/collection/okay-bears")
    nftDic = {}

    while True:
        newDic = {}
        finish = True
        sleep(4)
        nfts = cc.find_elements(locator.sample.opensea.img_okay_bear)
        for nft in nfts:
            src = nft.get_property("src")
            name = nft.get_property("alt")
            if name not in nftDic:
                newDic[name]=src
                finish = False

        for key,value in newDic.items():
            r = requests.get(value)
            print("Downloading:"+ key)
            imagePath = ".\\image\\" + key + ".jpg"
            with open(imagePath,'wb') as f:
                f.write(r.content)

        nftDic = nftDic | newDic
        if finish:
            break
        else:
            print("next page")
            cc.send_hotkey("{PGDN}")

if __name__ == "__main__":
    main()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More sample:&lt;br&gt;
&lt;a href="https://dev.to/kayyolo/10-lines-of-python-code-to-upload-a-video-to-tiktok-instagram-twitter-c9n"&gt;10 lines of Python code to upload a video to TikTok, Instagram, Twitter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kayyolo/a-spotify-robot-824"&gt;A Spotify robot&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nft</category>
      <category>opensea</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>[Python]Keep MS Teams status active</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Thu, 15 Sep 2022 11:36:44 +0000</pubDate>
      <link>https://dev.to/kayyolo/pythonkeep-ms-teams-status-active-446b</link>
      <guid>https://dev.to/kayyolo/pythonkeep-ms-teams-status-active-446b</guid>
      <description>&lt;p&gt;Microsoft Teams will auto-offline without action from your mouse and keyboard for a while. So we can use Python to control the mouse and keyboard to keep moving.&lt;br&gt;
Clicknium is a Python Library that can control your mouse and keyboard. &lt;/p&gt;

&lt;h2&gt;
  
  
  install
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pip install clicknium&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Python script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;clicknium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;clicknium&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mouse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;  
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; 
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;      

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
            &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mouse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code will keep moving your mouse along a circle. You can stop it by `Ctrl+C.&lt;/p&gt;

&lt;p&gt;There are a lot of things that you can use Clicknium to achieve and it is quite easy. It can control the mouse and keyboard, automate desktop applications and web browsers. Follow the &lt;a href="https://www.clicknium.com/documents/"&gt;Clicknium quick start&lt;/a&gt; and turn your routine work into an automation workflow. &lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>teams</category>
      <category>microsoftteams</category>
    </item>
    <item>
      <title>A Spotify robot</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Fri, 26 Aug 2022 13:41:57 +0000</pubDate>
      <link>https://dev.to/kayyolo/a-spotify-robot-824</link>
      <guid>https://dev.to/kayyolo/a-spotify-robot-824</guid>
      <description>&lt;h1&gt;
  
  
  Spotify robot
&lt;/h1&gt;

&lt;p&gt;I want to scrape a Spotify playlist from a web page, at first I try to use selenium, but it is not obtaining the full list, as the song list is dynamically loaded, I must scroll down to the bottom, then it can load all songs.&lt;/p&gt;

&lt;p&gt;Finally, I find one Visual Studio Code automation development tool, &lt;a href="https://marketplace.visualstudio.com/items?itemName=ClickCorp.clicknium"&gt;clicknium&lt;/a&gt; (it should be new in 2022), it is really easy to use and one click to locate the UI element.&lt;br&gt;
I just need to record two locators and write several lines of python code, the job is accomplished.&lt;/p&gt;

&lt;p&gt;As the list is dynamically loaded, I use an iterate index to search each item, as &lt;a href="https://www.clicknium.com"&gt;clicknium&lt;/a&gt; can automatically scroll the item into view, it will trigger to load new items, so I don't need to take care of the dynamic loading.&lt;/p&gt;

&lt;p&gt;I use a parametric locator for title and author&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rmztDdsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/img/title.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rmztDdsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/img/title.png" alt="title" width="" height=""&gt;&lt;/a&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fLYwTI3c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j7n5nauyw6p0drslc6xh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fLYwTI3c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j7n5nauyw6p0drslc6xh.png" alt="Image description" width="880" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gLJjqVpv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3fkq9c4qolfvjscn1ntk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gLJjqVpv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3fkq9c4qolfvjscn1ntk.png" alt="Image description" width="880" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As one item may have multiple authors, so I use the following code to get multiple author's names and links:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div_author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;authers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to try Clicknium, you can get started with the video on clicknium official site.&lt;/p&gt;

</description>
      <category>scraping</category>
      <category>beginners</category>
      <category>python</category>
    </item>
    <item>
      <title>[Python]Control MS paint to draw a pixel style logo automatically</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Fri, 26 Aug 2022 10:32:00 +0000</pubDate>
      <link>https://dev.to/kayyolo/pythoncontrol-ms-paint-to-draw-a-pixel-style-logo-automatically-50d4</link>
      <guid>https://dev.to/kayyolo/pythoncontrol-ms-paint-to-draw-a-pixel-style-logo-automatically-50d4</guid>
      <description>&lt;p&gt;From:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xqYUU5O8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmx0msci0oc21t91ttxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xqYUU5O8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmx0msci0oc21t91ttxa.png" alt="Image description" width="429" height="175"&gt;&lt;/a&gt;&lt;br&gt;
To: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6BDsj3fz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iw8jto3kim0ypo7r75qa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6BDsj3fz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iw8jto3kim0ypo7r75qa.png" alt="Image description" width="244" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Firt of all, perpare a simple piture.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Python package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pip install opencv-python&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pip install clicknium&lt;/code&gt; 
&amp;gt; &lt;code&gt;opencv-python&lt;/code&gt;: CV library. Load image and convert to a pixel style graph. 
&amp;gt; &lt;code&gt;clicknium&lt;/code&gt;: Automation library. Lanch MS paint and control the mouse to pain the picture.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search and install &lt;code&gt;clicknium&lt;/code&gt; in VS Code extension market.&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ii10diJZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxqnhghynqdbweode0s0.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ii10diJZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxqnhghynqdbweode0s0.PNG" alt="Image description" width="880" height="469"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get the source code&lt;br&gt;
&lt;code&gt;git clone https://github.com/automation9417/mspaint-draw-img.git&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use VS Code to open the souce code folder and press &lt;code&gt;F5&lt;/code&gt;to run. Use Shift+F5 to stop.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also build your own automation task using Clicknium. This tool is very easy to use. You can use the Recorder to Capture UI element for both Windows applications and web browser. It will auto-generate the locator to help you to locate and control the UI elements. &lt;/p&gt;

&lt;p&gt;The Python script can also be package to a executable file and send to other people. Draw a something special or type some words that you want to speak to the one. &lt;/p&gt;

&lt;p&gt;More detial please check the &lt;a href="https://github.com/clicknium/clicknium-docs"&gt;doc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>10 lines of Python code to upload a video to TikTok, Instagram, Twitter</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Wed, 24 Aug 2022 05:33:34 +0000</pubDate>
      <link>https://dev.to/kayyolo/10-lines-of-python-code-to-upload-a-video-to-tiktok-instagram-twitter-c9n</link>
      <guid>https://dev.to/kayyolo/10-lines-of-python-code-to-upload-a-video-to-tiktok-instagram-twitter-c9n</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpvbs8u3wlq9wiud8xgr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpvbs8u3wlq9wiud8xgr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, let's look at the running video.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/automation9417/automation-samples/raw/main/UploadVideo/media/upload_video.mp4" rel="noopener noreferrer"&gt;upload video to Tiktok, Instagram, Twitter&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Material Prepared
&lt;/h2&gt;

&lt;p&gt;An mp4 video file, because twitter has a limit on the length of uploaded videos, a shortened video file has been prepared.&lt;br&gt;
A cover image for Instagram, TikTok uses the first frame of the video as cover.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fautomation9417%2Fautomation-samples%2Fraw%2Fmain%2FUploadVideo%2Fimg%2Fmedia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fautomation9417%2Fautomation-samples%2Fraw%2Fmain%2FUploadVideo%2Fimg%2Fmedia.png" alt="media"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Run Python Code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;follow &lt;a href="https://www.clicknium.com/documents/quickstart" rel="noopener noreferrer"&gt;clicknium getting started&lt;/a&gt; to set up develop environment.&lt;/li&gt;
&lt;li&gt;clone &lt;a href="https://github.com/automation9417/automation-samples" rel="noopener noreferrer"&gt;sample repo&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/automation9417/automation-samples.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;open the folder 'UploadVideo' in Visual Studio Code.&lt;/li&gt;
&lt;li&gt;open &lt;code&gt;sample.py&lt;/code&gt; in Visual Studio Code.&lt;/li&gt;
&lt;li&gt;open the chrome browser (guarantee that there is only one chrome window, explained later), open 3 tabs respectively, open and login TikTok, Twitter and Instagram.&lt;/li&gt;
&lt;li&gt;press &lt;code&gt;F5&lt;/code&gt; to debug the sample or press &lt;code&gt;CTRL+F5&lt;/code&gt; to run sample.
The video that comes with the sample will be uploaded, and you can also modify code to your own video content:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;caption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Clicknium introduction&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;cover_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;media&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;logo.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;video_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;media&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clicknium_introduction.mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;upload_tiktok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;video_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;short_video_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;media&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;short_introduction.mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;upload_twitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;short_video_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;upload_instagram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cover_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;video_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Here is an example of uploading a video to Instagram, uploading a video to TikTok and Twitter is a similar process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the open browser tab by attaching the browser, and then navigate to the Instagram Home page.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attach_by_title_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://*instagram.com/*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.instagram.com/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Click the 'add post' button, all web page elements here are recorded by &lt;a href="https://www.clicknium.com/documents/tutorial/recorder/quickstart" rel="noopener noreferrer"&gt;Clicknium Recorder&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instagram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;svg_add_post&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Click the 'Select from computer' button to pop up a file selection dialog box. Due to browser security restrictions, click here by simulating a mouse.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instagram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button_select_file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mouse-emulation&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Using Clicknium desktop automation to select video file and click open button.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit_file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;video_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;set-text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button_open&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;control-invocation&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A special note here is that I changed the recorded locator 'edit_file' and 'button_open':&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flnthpj6xs3j6f27am9qm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flnthpj6xs3j6f27am9qm.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktnrodrwr0eb5k2fqw86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktnrodrwr0eb5k2fqw86.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Changed the window matching Name to the wildcard *, because uploading videos to TikTok and Twitter also requires the operation of the file selection dialog. In order to avoid repeated recording, the wildcard is used to match the window to achieve reuse. Therefore, the previous steps require only one Chrome browser window to ensure that the window can be correctly matched.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the 'next' button, then select the cover image, the code is similar to the above.&lt;/li&gt;
&lt;li&gt;Enter the text you want to send, then click 'Share' button.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instagram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textarea&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instagram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button_share&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Wait for the upload to succeed, the time required varies according to the size of the video.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_appear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instagram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h2_yourposthasbeenshared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wait_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Uploading a video to Instagram requires a few more steps to upload a cover image. The following is the complete code for uploading a video to Twitter. It only takes 9 lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attach_by_title_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://*twitter.com/*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://twitter.com/compose/tweet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit_file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;video_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;set-text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button_open&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;control-invocation&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_appear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;span_tweet&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are welcome to comment on the needs of uploading videos to other video platforms, and I can provide more sample code.&lt;/p&gt;

</description>
      <category>youtuber</category>
      <category>beginners</category>
      <category>python</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>GUI automation under the hood</title>
      <dc:creator>kayYOLO</dc:creator>
      <pubDate>Tue, 23 Aug 2022 12:34:00 +0000</pubDate>
      <link>https://dev.to/kayyolo/gui-automation-under-the-hood-3j4j</link>
      <guid>https://dev.to/kayyolo/gui-automation-under-the-hood-3j4j</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/clicknium/clicknium-docs"&gt;Clicknium&lt;/a&gt; provides the automation technology in a variety of scenarios with different forms, such as SAP automation, Java automation, Windows desktop automation and image automation. I would like to share the automation technology in Clicknium. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Regarding software automation technology, it was mainly used for software testing in the very beginning, especially for UI automation testing. Many system software designs take the accessibility of disabled users into account. See windows accessibility. In recent years, RPA (Robotic Process Automation) has been accepted by more and more enterprises. RPA plays a great role in multiple business field scenarios to optimize the process, reduce costs and increase efficiency, and quickly improve the level of informatization. RPA products generally include automated operation components for various software, data processing components, process logic control components, etc., among which UI automation components are the mostly used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Windows UI Automation Technology
&lt;/h2&gt;

&lt;p&gt;Windows applications include a functional design: Accessibility, which allows more users to operate the software. For example, allow the blind users to read the screen through their voice, etc. The UI automation technology provided by Microsoft can access the control elements of the windows application. The main technologies are as follows: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UIA (UI Automation) UI Automation provides programmatic access to information about the user interface (UI) for Microsoft Windows, enabling assistive technology products (such as screen readers) to provide information about the UI to end users using means other than standard input and Manipulate UI. UI Automation also enables automated test scripts to interact with the UI.&lt;/li&gt;
&lt;li&gt;MSAA（Microsoft Active Accessibility） Microsoft Active Accessibility was the application accessibility solution from Microsoft earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;UIA&lt;/th&gt;
&lt;th&gt;MSAA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Programing Languages&lt;/td&gt;
&lt;td&gt;Written in managed code, client applications are most easily programmed using C#&lt;/td&gt;
&lt;td&gt;based on the Component Object Model (COM) with support for dual interfaces.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows Presentation Foundation&lt;/td&gt;
&lt;td&gt;full support&lt;/td&gt;
&lt;td&gt;WPF do not contain native support for MSAA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Servers and Clients&lt;/td&gt;
&lt;td&gt;a core service between the server (called a provider) and the client, providing more information to the client&lt;/td&gt;
&lt;td&gt;servers and clients communicate directly, largely through the server's implementation of IAccessible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;UIA removes the need of providers to call through to other provider code. The UI Automation core service does all the necessary aggregation.&lt;/td&gt;
&lt;td&gt;Some IAccessible customization scenarios require wrapping a base IAccessible and calling through to it. There is a potential security risk, since a partially trusted component should not be an intermediary on a code path.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are interested in Windows automation technology, you can directly go to &lt;a href="https://docs.microsoft.com/zh-CN/dotnet/framework/ui-automation/ui-automation-overview"&gt;Microsoft's official technical documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java Access Bridge (JAB)
&lt;/h2&gt;

&lt;p&gt;Java Access Bridge is a technology that exposes the Java Accessibility API in a Microsoft Windows DLL, enabling Java applications and applets that implement the Java Accessibility API to be visible to assistive technologies on Microsoft Windows systems. Java Accessibility API is part of Java Accessibility Utilities, a set of utility classes that help assistive technologies provide access to GUI toolkits that implement the Java Accessibility API. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dXbVkM7A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0u1jvsx6wvks7ep4092.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dXbVkM7A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0u1jvsx6wvks7ep4092.png" alt="Image description" width="316" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To learn more about JAB, please visit &lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/access/jab/introduction.html#jab-overview"&gt;oracle&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Web Automation
&lt;/h2&gt;

&lt;p&gt;Web automation mainly depends on the type of browsers, and currently, there are two main categories:&lt;/p&gt;
&lt;h3&gt;
  
  
  Internet Explorer(IE)
&lt;/h3&gt;

&lt;p&gt;Through javascript injection based on the Component Object Model (COM).&lt;br&gt;
Due to different versions of IE, it is still a technical issue to make multiple versions of IE compatible. &lt;/p&gt;
&lt;h3&gt;
  
  
  Chromium-based browsers
&lt;/h3&gt;

&lt;p&gt;There are generally three ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selenium webdriver
 To learn more about webdriver, please visit WebDriver, Chrome webdriver.&lt;/li&gt;
&lt;li&gt;Chrome devtool protocol(CDP)
Since CDP is used in many tools, you can refer to awesome-chrome-devtools. Related to web automation testing, they are Puppeteer and Playwright. The playwright's python code to start the Chrome browser is as below:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"chrome"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headless&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# Open new page
&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# Go to https://www.google.com/
&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.google.com/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With ProcessExplorer, you can see that Chrome starts the parameters as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-background-networking --enable-features=NetworkService,NetworkServiceInProcess --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,AcceptCHFrame,AutoExpandDetailsElement --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-sync --force-color-profile=srgb --metrics-recording-only --no-first-run --enable-automation --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --no-sandbox --user-data-dir=C:\Users\test\AppData\Local\Temp\playwright_chromiumdev_profile-V3LZUg **--remote-debugging-pipe** --no-startup-window
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the chrome startup parameter description:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--remote-debugging-pipe: Enables remote debug over stdio pipes [in=3, out=4]. Optionally, specifies the format for the protocol messages, can be either "JSON" (the default) or "CBOR"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the way to use CDP, you can get started from &lt;a href="https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md"&gt;this link&lt;/a&gt;. More Chrome startup parameters can be found in the official documentation or &lt;a href="https://github.com/GoogleChrome/chrome-launcher/blob/master/docs/chrome-flags-for-tools.md"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native messaging Extensions and apps can exchange messages with native applications by an API similar to the other &lt;a href="https://developer.chrome.com/docs/apps/nativeMessaging/messaging"&gt;message passing APIs&lt;/a&gt;. Native applications that support this feature must register a native messaging host knowing how to communicate with the extension. Chrome starts the host in a separate process and communicates with it using standard input and standard output streams.
More about Native Messaging, please visit &lt;a href="https://developer.chrome.com/docs/apps/nativeMessaging/messaging"&gt;this link&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SAP Automation
&lt;/h2&gt;

&lt;p&gt;As SAP provides script automation officially, most RPA products automate SAP applications based on their own automation technology. &lt;/p&gt;

&lt;h3&gt;
  
  
  Automated supplementary technology
&lt;/h3&gt;

&lt;p&gt;In addition to the above native automation technologies, the following automation technologies are generally used to achieve hybrid automation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image recognition, shortcut keys&lt;/li&gt;
&lt;li&gt;OCR&lt;/li&gt;
&lt;li&gt;Screen word picking&lt;/li&gt;
&lt;li&gt;Computer vision&lt;/li&gt;
&lt;li&gt;Windows Native API&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Clicknium Does
&lt;/h2&gt;

&lt;p&gt;With the automation technologies above, Clicknium offers development tools that allow users to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capture UI elements and store them as locators or selectors.&lt;/li&gt;
&lt;li&gt;Automate all kinds of applications with a single Python API.&lt;/li&gt;
&lt;li&gt;Higher efficiency in writing code with locator IntelliSense.
In addition to the automation technologies above, we also add other enhancements:&lt;/li&gt;
&lt;li&gt;Combine various automation technologies to increase robustness.&lt;/li&gt;
&lt;li&gt;Find the UI component with a fast searching algorithm.&lt;/li&gt;
&lt;li&gt;Algorithm for generating locators.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can visit &lt;a href="https://marketplace.visualstudio.com/items/ClickCorp.clicknium/changelog"&gt;Clicknium Visual Studio Code Extension change log&lt;/a&gt; to see more functions.&lt;/p&gt;

</description>
      <category>rpa</category>
      <category>python</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
