L o a d i n g . . .
主打一个C++
文章详情

C++使用chromedriver完成浏览器自动化操作测试

Posted on 2024-10-03 06:03:16 by 主打一个C++

bb: 因项目需求,要获取某音直播间的实时数据,一堆坑🕳,总算爬出来~~~

大致看了一下chromedriver的功能还是非常庞大的,能实现的不能实现的都实现了。。。我只取一瓢~~~~

测试结果

浏览器自动化测试.png


测试环境:

windows操作系统 + C++ + curl.lib

资源:

1.chromedriver.exe 下载地址: https://sites.google.com/chromium.org/driver/downloads (尽量与浏览器版本对应)

2.谷歌的Chrome for Testing: https://googlechromelabs.github.io/chrome-for-testing/

我试用的130.0.6723.58版本 : https://storage.googleapis.com/chrome-for-testing-public/130.0.6723.58/win64/chrome-win64.zip

3.相关指令: https://chromium.googlesource.com/chromium/src/+/master/docs/chromedriver_status.md


初始化配置:CCurl.h (bb: 代码仅供测试)

为了方便,直接封装了两个函数,一个头文件调用方便随时扩展,Curl7.几版本以下貌似非线程安全,so

#pragma once
#ifndef CCURL_H
#define CCURL_H
#include <curl.h>
#pragma comment(lib, "libcurl")
class CCurl
{
	CCurl() {
		curl_global_init(CURL_GLOBAL_DEFAULT);
		m_curl = curl_easy_init();
		if (m_curl == nullptr) {
			printf("Curl init failed!\n");
		}
	};
	~CCurl() {
		if (m_curl) {
			curl_easy_cleanup(m_curl);
			curl_global_cleanup();
		}
	};
public:
	static CCurl* This() {
		static CCurl instance;
		return &instance;
	}
	int Excute(const char* _url,const char* _command) {
		curl_easy_setopt(m_curl, CURLOPT_URL, _url);
		curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, _command);
		CURLcode res = curl_easy_perform(m_curl);
		if (res != CURLE_OK) {
			std::cerr << "Excute failed: " << curl_easy_strerror(res) << std::endl;
			return 3;
		}
		return 0;
}
	int Post(const char* _url, const char* _postData, std::string* _readBuffer) {
		_readBuffer->clear();
		curl_easy_setopt(m_curl, CURLOPT_URL, _url);
		curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, _postData);
		// 设置回调函数以处理返回的数据
		curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, CCurl::WriteCallback);
		// 将缓冲区传递给回调函数
		curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, _readBuffer);
		// 设置请求头
		//struct curl_slist* headers = NULL;
		//headers = curl_slist_append(headers, "Accept: */*");
		//curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
		// 设置 Cookie
		//curl_easy_setopt(m_curl, CURLOPT_COOKIE, "");

		CURLcode res = curl_easy_perform(m_curl);
		if (res != CURLE_OK) {
			std::cerr << "Post failed: " << curl_easy_strerror(res) << std::endl;
			return 5;
		}
		
		return 0;
	}
private:
	static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) {
		size_t totalSize = size * nmemb;
		userp->append((char*)contents, totalSize);
		return totalSize;

	}
private:
	CURL* m_curl = nullptr;
};
#endif // !CCURL_H

启动配置:main.cpp

#include <iostream>
#include "CJson.h"
//#include "dy_tcp.h"
#include "CCurl.h"
//启动,默认为附加自身
int StartChromeProcess() {
    printf("%s\n", __FUNCTION__);
    std::string _cmdLine = DY_CHROME_FULL_PATH;
    _cmdLine += " --port=";
    _cmdLine += DY_CHROME_PORT;
    bool _isHidden = false;
    // 创建一个 STARTUPINFO 结构体实例
    STARTUPINFOA si{ (DWORD)sizeof(si) };
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOW;
    if (_isHidden) {
        si.wShowWindow = SW_HIDE;
    }
    // 启动cmd.exe
    if (::CreateProcessA(
        NULL,
        (LPSTR)_cmdLine.c_str(), //参数
        NULL, // 进程句柄不可继承
        NULL, // 线程句柄不可继承
        FALSE, // 不继承句柄
        0, // 创建标志CREATE_NEW_CONSOLE
        NULL, // 使用默认的环境变量
        NULL, // 使用默认的当前目录
        &si, // STARTUPINFO 结构体
        &pi) // PROCESS_INFORMATION 结构体
        ) {

        // 等待进程结束
        //WaitForSingleObject(pi.hProcess, INFINITE);

        // 关闭进程和线程句柄
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    else {
        std::cerr << "Failed to start Chrome process: "<< GetLastError() << std::endl;
    }
    return 0;
}
//结束进程
bool TerminateProcessByName(DWORD _processId) {
    printf("%s\n", __FUNCTION__);
    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, _processId);
    if (hProcess != NULL) {
        // 强制结束进程
        if (TerminateProcess(hProcess, 0)) {
            return true;
        }
        CloseHandle(hProcess);
    }
    return false;
}
//打开一个网页
void openUrl(const std::string& session_id, const std::string& url, std::string* readBuffer) {
    CURLcode res;
    // 打开指定的 URL
    std::string openUrl = DY_CHROME_HOST;
    openUrl += ":";
    openUrl += DY_CHROME_PORT;
    openUrl += "/session/";
    openUrl += session_id;
    openUrl += "/url";
    std::string postFields = "{"url": "" + url + ""}";
    if (CCurl::This()->Post(openUrl.c_str(), postFields.c_str(), readBuffer) != 0) {
    }
    else {
        std::cerr << "Response data: " << readBuffer << std::endl;
    }
}
//执行js代码
void executeJs(const std::string& session_id, const std::string& jsCode, std::string* readBuffer) {
    CURLcode res;
    // 执行 JavaScript 代码
    std::string executeJsUrl = DY_CHROME_HOST;
    executeJsUrl += ":";
    executeJsUrl += DY_CHROME_PORT;
    executeJsUrl += "/session/";
    executeJsUrl += session_id;
    executeJsUrl += "/execute/sync";

    std::string jsPostFields = "{"script":"" + jsCode + "","args":[]}";

    if (CCurl::This()->Post(executeJsUrl.c_str(), jsPostFields.c_str(), readBuffer) != 0) {

    }
    else {
        std::cerr << "Response data: " << readBuffer << std::endl;
    }
}
//关闭浏览器窗口
void closeChromeDriver(const std::string& session_id) {
     printf("%s\n",__FUNCTION__);
    std::string closeWindowUrl = DY_CHROME_HOST;
    closeWindowUrl += ":";
    closeWindowUrl += DY_CHROME_PORT;
    closeWindowUrl += "/session/";
    closeWindowUrl += session_id;
    CCurl::This()->Excute(closeWindowUrl.c_str(), "DELETE");
}
//启动chromeDirver
std::string StartChromeDriver() {
    printf("%s\n", __FUNCTION__);
    std::string session_id = "";

    std::string readBuffer = "";  // 用于存储返回数据
    //                    "--headless",
    const char* postFields = R"({
        "desiredCapabilities": {
            "browserName": "chrome",
            "goog:chromeOptions": {
                "excludeSwitches": ["enable-automation"],
                "args": [
                    "--window-size=1024,768",
                    "--disable-extensions",
                    "--disable-dev-shm-usage",
                    "--no-sandbox",
                    "--disable-setuid-sandbox",
                    "--disable-popup-blocking",
                    "--disable-notifications",
                    "--disable-print-preview",
                    "--disable-prompt-on-repost",
                    "--disable-desktop-notifications",
                    "--disable-device-discovery-notifications",
                    "--disable-features=site-per-process",
                    "--disable-sync",
                    "--disable-translate",
                    "--disable-save-password-bubble",
                    "--disable-single-click-autofill",
                    "--disable-infobars",
                    "--disable-background-timer-throttle",
                    "--disable-backgrounding-occluded-windows",
                    "--useAutomationExtension=false"
                ]
            }
        }
    })";
    std::string url = DY_CHROME_HOST;//"http://localhost:1900/session";
    url += ":";
    url += DY_CHROME_PORT;
    url += "/session";

    if (CCurl::This()->Post(url.c_str(), postFields, &readBuffer) != 0) {

    }
    else {
        std::cerr << "Response data: " << readBuffer << std::endl;  // 输出返回的数据

        CJson json(&readBuffer);
        session_id = json.getValue("sessionId").toString();
        printf("sessionId=[%s]\n", session_id.c_str());
    }
    return session_id;
}
//启动浏览器
int main(int argc, char* argv[]) {
    if (StartChromeProcess() == 0) {
        std::string session_id = StartChromeDriver(); // 启动 `chromedriver`
        if (session_id.empty()) {
            std::cerr << "Failed to start ChromeDriver" << std::endl;
            return 2;
        }
        std::string readBuffer = "";
        openUrl(session_id, "https://live.douyin.com/963259834694", &readBuffer);
        SetWindowTextA(GetConsoleWindow(), "Press Ctrl+Space to quit.");
        //Sleep(3000);
        //closeChromeDriver(session_id + "/window/");
    }
    printf("quit.\n");
    return 0;
}

//至此完成!

*转载请注明出处:原文链接:https://cpp.vin/page/60.html

作者近期文章
  • 随手笔记
  • 主打一个C++   2025-01-11 20:02:01
  • 都2000000025年了。还有不能随意访问guthub的,仔细看。在国内其实是可以正常访问的,gfw并没屏蔽。这里给出其中一个简单直接的方法稳定访问。1. 随便百度一个”dn
提示
×
确定
数据库执行: 8次 总耗时: 0.03s
页面加载耗时: 



wechat +447752296473
wechat cpp-blog