pythonc++python-3.xseleniumpython-embedding

How can i call a Python Function from C++ in the same instance succesfully?


hey so im trying to embed Python Selenium in C++ , but i managed it to just open the browser and get a item. How can i succesfully open the browser and search HELLO inside the google searchbar?

#define PY_SSIZE_T_CLEAN
#include <python/Python.h>
#include <conio.h>
#include <iostream>
#include <string>
#include <filesystem>
#include <python/pyhelper.hpp>


using namespace std;
#define PYSRCDIR "/PythonSrc/"

PyObject* pName, * pModule, * pFunc;
PyObject* pArgs, * pValue;


inline int  __initialize_path(string __file) {
    file = __file;
    
    std::filesystem::path path = std::filesystem::current_path();
    std::string _path = path.string();
  
    std::replace(_path.begin(), _path.end(), '\\', '/');
    try {
        PyRun_SimpleString("import sys");
    }
    catch (...) {
        cout << "cpp >> INITIALIZE with <Py_Initialize();> first\n";
        return -1;
    }
    PyRun_SimpleString((string("sys.path.append(\"") + _path + string(PYSRCDIR) + string("\")")).c_str());
    
    pName = PyUnicode_DecodeFSDefault(file.c_str());
    /* Error checking of pName left out */

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    return 0;
}
/**
 * It calls a python function from C++
 * 
 * @param file The name of the python file to be executed. It should be located in PYSRCDIR dir
 * @param funcptr The name of the function to call.
 * 
 * @return The return value is the status.
 */
inline int __callpy_noarg(string funcptr) {
   
    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, funcptr.c_str());
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {
            pValue = PyObject_CallObject(pFunc , NULL);
        }
        else {
            /* Checking if there is an error. If there is an error, it prints it out. */
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"%s\"\n", funcptr);
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\"\n", file.c_str());
        return 1;
    }
    
    return 0;
}
 /**
  * It calls a Python function with args from C++.
  * 
  * @param file The name of the python file to be executed.
  * @param funcptr The name of the function to call.
  * @param args A vector of strings that are the arguments to pass to the Python function.
  * 
  * @return The return value is the status.
  */
inline int __callpy_warg(string funcptr, vector<string>* args) {
     
     if (pModule != NULL) {
         pFunc = PyObject_GetAttrString(pModule, funcptr.c_str());
         /* pFunc is a new reference */

         if (pFunc && PyCallable_Check(pFunc)) {
             pArgs = PyTuple_New(args->size());
             for (i = 0; i < args->size(); ++i) {
                 string str = args->at(i);
                 pValue = PyUnicode_FromString(str.c_str());
                 if (!pValue) {
                     Py_DECREF(pArgs);
                     Py_DECREF(pModule);
                     fprintf(stderr, "Cannot convert argument\n");
                     return 1;
                 }
                 /* pValue reference stolen here: */
                 PyTuple_SetItem(pArgs, i, pValue);
             }
             pValue = PyObject_CallObject(pFunc, pArgs);
             Py_DECREF(pArgs);
             if (pValue != NULL) {
                 printf("Result of call: %ld\n", PyLong_AsLong(pValue));
                 Py_DECREF(pValue);
             }
             else {
                 Py_DECREF(pFunc);
                 Py_DECREF(pModule);
                 PyErr_Print();
                 fprintf(stderr, "Call failed\n");
                 return 1;
             }
         }
         else {
             if (PyErr_Occurred())
                 PyErr_Print();
             fprintf(stderr, "Cannot find function \"%s\"\n", funcptr.c_str());
         }
         Py_XDECREF(pFunc);
         Py_DECREF(pModule);
     }
     else {
         PyErr_Print();
         fprintf(stderr, "Failed to load \"%s\"\n", file.c_str());
         return 1;
     }
     
     return 0;
 }


int main()
{
    CPyInstance inst;

    __initialize_path("pyemb3");
    std::vector<string>* vec1 = new std::vector<string>;
    vec1->push_back(" ");
    __callpy_warg("init_selenium", vec1);
    delete vec1;

    std::vector<string>* vec2 = new std::vector<string>;
    vec2->push_back("https://www.google.com/");
    __callpy_warg("get_search", vec2);
    delete vec2;

    std::vector<string>* vec3 = new std::vector<string>;
    vec3->push_back("q");
    __callpy_warg("get_elem_NAME", vec3);
    delete vec3;

    std::vector<string>* vec4 = new std::vector<string>;
    vec4->push_back("0");
    __callpy_warg("click_ELEMENT", vec4);
    delete vec4;


    std::vector<string>* vec5 = new std::vector<string>;
    vec5->push_back("0");
    vec5->push_back("HELLO");
    __callpy_warg("type_ELEMENT", vec5);
    delete vec5;

    std::vector<string>* vec6 = new std::vector<string>;
    vec6->push_back("0");
    vec6->push_back('\ue007');// enter key unicode
    __callpy_warg("type_ELEMENT", vec6);
    delete vec6;



   
}

so in the main function im calling some functions defined inside this python file

# It imports the necessary modules to run the code.

from selenium.webdriver.chrome.options import Options
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import threading
import chromedriver_autoinstaller

chromedriver_autoinstaller.install()

global option
driver = ""
elements_list = []




def init_selenium(param):
    options = Options()
    if not param == "":
        paramlist = param.split(" ");
    else:
        print("init_selenium --NO ARGS")
    if "headless" in paramlist:
        options.add_argument("--headless")
        print("init_selenium --HEADLESS")

    global driver;
    driver = webdriver.Chrome(options=options)


def get_search(PATH):
    global driver;
    if not PATH == "":
        driver.get(PATH)
    else:
        print("get_search --NO PATH SPECIFIED")


def wait_elem_XPATH(ELEMDATA , TIME):
    global driver;
    try:
        element1 = WebDriverWait(driver, int(TIME)).until(
            EC.presence_of_element_located((By.XPATH, ELEMDATA)))
    except:
        print("wait_elem_XPATH --INVALID ARGS")

def get_elem_XPATH(ELEMDATA):
    global driver;
    element3 = driver.find_element_by_xpath(ELEMDATA)
    global elements_list;
    elements_list.append(element3);


def get_elem_NAME(ELEMDATA):
    global driver;
    element3 = driver.find_element_by_name(ELEMDATA)
    global elements_list;
    elements_list.append(element3);

def click_ELEMENT(ELEMNUMBER):
    global elements_list;
    elements_list[int(ELEMNUMBER)].click()

def type_ELEMENT(ELEMNUMBER , TEXT):
    global elements_list;
    elements_list[int(ELEMNUMBER)].send_keys(TEXT)

def driver_QUIT():
    global driver;
    driver.quit()


def driver_WAIT(sec):
    driver.implicitly_wait(int(sec)) # seconds

the error says that it cant find the functions but it can find the others....

AttributeError: '_collections._deque_iterator' object has no attribute 'click_ELEMENT'
Cannot find function "click_ELEMENT"
AttributeError: 'builtin_function_or_method' object has no attribute 'type_ELEMENT'
Cannot find function "type_ELEMENT"
AttributeError: 'AttributeError' object has no attribute 'type_ELEMENT'
Cannot find function "type_ELEMENT"

github project link : https://github.com/Vasika-uso/Selenium-embedded-in-cpp


Solution

  • I think you can make a .dll form .py file and pass it while compiling your c++ code. You can use pyinstaller for converting the .py files into executable with all required packages into .dll format.

    Step 1. pip install pyinstaller,

    step 2. new python file let's name it code.py .

    step 3. Write some lines of code i.e print("Hello World")

    step 4. Open Command Prompt in the same location and write pyinstaller code.py hit enter. Last Step see in the same location two folders name build, dist will be created. inside dist folder there is folder code and inside that folder there is an exe file code.exe along with required .dll files.