You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中嵌入Python Selenium成功实现谷歌搜索HELLO并解决函数调用错误

Fixing C++ Embedded Python Selenium Issues: Google Search & Function Call Errors

Let's break down and fix your problems step by step. The core issues causing those AttributeError and "Cannot find function" messages, plus getting the Google search working, are easy to resolve once you spot them.

Key Problems Identified

  1. Premature Python Module Destruction
    Your __callpy_warg and __callpy_noarg functions call Py_DECREF(pModule) after every function invocation. This destroys the Python module object immediately after the first call, so subsequent attempts to access functions like click_ELEMENT fail because the module no longer exists. That's why you're seeing those "Cannot find function" errors and weird object type mismatches.

  2. Uninitialized Variables in C++
    The __callpy_warg function uses an undeclared variable i in the loop that builds the argument tuple. This will cause a compile error.

  3. Outdated Selenium Syntax
    Your Python code uses driver.find_element_by_name() which is deprecated in newer Selenium versions. Replacing it with the modern driver.find_element(By.NAME, ...) syntax avoids warnings and ensures compatibility.

Corrected Code Implementations

Fixed C++ Code

#define PY_SSIZE_T_CLEAN
#include <python/Python.h>
#include <conio.h>
#include <iostream>
#include <string>
#include <filesystem>
#include <vector>
// Assuming pyhelper.hpp is properly included
using namespace std;

#define PYSRCDIR "/PythonSrc/"
PyObject* pName, *pModule, *pFunc;
PyObject* pArgs, *pValue;
string file; // Declare global file variable

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(), '\\', '/');
    
    if (!Py_IsInitialized()) {
        cout << "cpp >> INITIALIZE with <Py_Initialize();> first\n";
        return -1;
    }
    
    PyRun_SimpleString("import sys");
    PyRun_SimpleString((string("sys.path.append(\"") + _path + PYSRCDIR + "\")").c_str());
    
    pName = PyUnicode_DecodeFSDefault(file.c_str());
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);
    
    return pModule ? 0 : -1;
}

inline int __callpy_noarg(string funcptr) {
    if (pModule == NULL) {
        PyErr_Print();
        fprintf(stderr, "Failed to load module \"%s\"\n", file.c_str());
        return 1;
    }

    pFunc = PyObject_GetAttrString(pModule, funcptr.c_str());
    if (pFunc && PyCallable_Check(pFunc)) {
        pValue = PyObject_CallObject(pFunc, NULL);
    } else {
        if (PyErr_Occurred()) PyErr_Print();
        fprintf(stderr, "Cannot find function \"%s\"\n", funcptr.c_str());
    }

    Py_XDECREF(pFunc);
    // DO NOT DECREF pModule here - keep it for subsequent calls
    return 0;
}

inline int __callpy_warg(string funcptr, vector<string>* args) {
    if (pModule == NULL) {
        PyErr_Print();
        fprintf(stderr, "Failed to load module \"%s\"\n", file.c_str());
        return 1;
    }

    pFunc = PyObject_GetAttrString(pModule, funcptr.c_str());
    if (pFunc && PyCallable_Check(pFunc)) {
        pArgs = PyTuple_New(args->size());
        for (int i = 0; i < args->size(); ++i) { // Declare i explicitly
            string str = args->at(i);
            pValue = PyUnicode_FromString(str.c_str());
            if (!pValue) {
                Py_DECREF(pArgs);
                fprintf(stderr, "Cannot convert argument %d\n", i);
                return 1;
            }
            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 {
            PyErr_Print();
            fprintf(stderr, "Call to \"%s\" failed\n", funcptr.c_str());
            return 1;
        }
    } else {
        if (PyErr_Occurred()) PyErr_Print();
        fprintf(stderr, "Cannot find function \"%s\"\n", funcptr.c_str());
    }

    Py_XDECREF(pFunc);
    // DO NOT DECREF pModule here
    return 0;
}

int main() {
    CPyInstance inst; // This should handle Py_Initialize()
    if (__initialize_path("pyemb3") != 0) {
        cerr << "Failed to initialize Python module\n";
        return 1;
    }

    // Initialize Selenium with empty param (non-headless)
    std::vector<string> vec1 = {""};
    __callpy_warg("init_selenium", &vec1);

    // Navigate to Google
    std::vector<string> vec2 = {"https://www.google.com/"};
    __callpy_warg("get_search", &vec2);

    // Wait a moment for page to load (optional but helpful)
    std::vector<string> vec_wait = {"2"};
    __callpy_warg("driver_WAIT", &vec_wait);

    // Get search box element by name "q"
    std::vector<string> vec3 = {"q"};
    __callpy_warg("get_elem_NAME", &vec3);

    // Click the search box (optional, but ensures focus)
    std::vector<string> vec4 = {"0"};
    __callpy_warg("click_ELEMENT", &vec4);

    // Type "HELLO" into the search box
    std::vector<string> vec5 = {"0", "HELLO"};
    __callpy_warg("type_ELEMENT", &vec5);

    // Press Enter to search
    std::vector<string> vec6 = {"0", "\ue007"};
    __callpy_warg("type_ELEMENT", &vec6);

    // Keep browser open for a few seconds
    std::vector<string> vec_wait2 = {"5"};
    __callpy_warg("driver_WAIT", &vec_wait2);

    // Cleanup
    __callpy_noarg("driver_QUIT");
    Py_DECREF(pModule); // Now we can safely destroy the module
    return 0;
}

Updated Python Code

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

chromedriver_autoinstaller.install()

driver = None
elements_list = []

def init_selenium(param):
    global driver
    options = Options()
    paramlist = param.split(" ") if param else []
    
    if "headless" in paramlist:
        options.add_argument("--headless")
        print("init_selenium --HEADLESS mode enabled")
    
    driver = webdriver.Chrome(options=options)
    print("init_selenium --Chrome driver initialized")

def get_search(PATH):
    global driver
    if not driver:
        print("get_search --Selenium not initialized. Call init_selenium first.")
        return
    if PATH:
        driver.get(PATH)
        print(f"get_search --Navigated to {PATH}")
    else:
        print("get_search --NO PATH SPECIFIED")

def wait_elem_XPATH(ELEMDATA, TIME):
    global driver
    if not driver:
        print("wait_elem_XPATH --Selenium not initialized")
        return
    try:
        element = WebDriverWait(driver, int(TIME)).until(
            EC.presence_of_element_located((By.XPATH, ELEMDATA)))
        elements_list.append(element)
        print(f"wait_elem_XPATH --Found element with XPath: {ELEMDATA}")
    except Exception as e:
        print(f"wait_elem_XPATH --Error: {str(e)}")

def get_elem_XPATH(ELEMDATA):
    global driver
    if not driver:
        print("get_elem_XPATH --Selenium not initialized")
        return
    try:
        element = driver.find_element(By.XPATH, ELEMDATA)
        elements_list.append(element)
        print(f"get_elem_XPATH --Added element with XPath: {ELEMDATA}")
    except Exception as e:
        print(f"get_elem_XPATH --Error: {str(e)}")

def get_elem_NAME(ELEMDATA):
    global driver
    if not driver:
        print("get_elem_NAME --Selenium not initialized")
        return
    try:
        element = driver.find_element(By.NAME, ELEMDATA)
        elements_list.append(element)
        print(f"get_elem_NAME --Added element with name: {ELEMDATA}")
    except Exception as e:
        print(f"get_elem_NAME --Error: {str(e)}")

def click_ELEMENT(ELEMNUMBER):
    global elements_list
    try:
        elem_idx = int(ELEMNUMBER)
        if 0 <= elem_idx < len(elements_list):
            elements_list[elem_idx].click()
            print(f"click_ELEMENT --Clicked element at index {elem_idx}")
        else:
            print(f"click_ELEMENT --Invalid index {elem_idx}")
    except Exception as e:
        print(f"click_ELEMENT --Error: {str(e)}")

def type_ELEMENT(ELEMNUMBER, TEXT):
    global elements_list
    try:
        elem_idx = int(ELEMNUMBER)
        if 0 <= elem_idx < len(elements_list):
            elements_list[elem_idx].send_keys(TEXT)
            print(f"type_ELEMENT --Typed '{TEXT}' into element at index {elem_idx}")
        else:
            print(f"type_ELEMENT --Invalid index {elem_idx}")
    except Exception as e:
        print(f"type_ELEMENT --Error: {str(e)}")

def driver_QUIT():
    global driver
    if driver:
        driver.quit()
        print("driver_QUIT --Chrome driver closed")
        driver = None

def driver_WAIT(sec):
    global driver
    if driver:
        time.sleep(int(sec)) # Using time.sleep for explicit wait here
        print(f"driver_WAIT --Waited {sec} seconds")

What Changed & Why

  1. Preserved Python Module
    Removed Py_DECREF(pModule) from the function call helpers. Now the module is only destroyed at the end of main(), allowing repeated function calls without losing access to the Python functions.

  2. Fixed Variable Declarations
    Added explicit int i declaration in the argument loop of __callpy_warg to resolve compile errors.

  3. Modernized Selenium Code
    Replaced deprecated find_element_by_name with find_element(By.NAME, ...) and added error checking for uninitialized driver instances to make the code more robust.

  4. Added Explicit Waits
    Added calls to driver_WAIT to give the page time to load, which prevents race conditions where Selenium tries to interact with elements that haven't rendered yet.

  5. Improved Error Handling
    Added print statements in Python functions to help debug what's happening at each step, making it easier to track issues if they arise.

Testing the Fix

When you run the corrected code:

  1. Chrome will open (non-headless mode)
  2. Navigate to Google's homepage
  3. Wait 2 seconds for the page to load
  4. Locate the search box element
  5. Click the search box to focus it
  6. Type "HELLO"
  7. Press Enter to trigger the search
  8. Wait 5 seconds to see the results
  9. Close the browser

This should resolve all your AttributeError and function-not-found issues, and successfully perform the Google search as intended.

内容的提问来源于stack exchange,提问作者S.T.A.L.K.E.R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 16:07:39