Загрузка данных
/*
* cdp-clicker — минималистичный кроссплатформенный кликер (C99)
* Windows (MinGW/GCC) и Linux (GCC)
*
* Сборка:
* Windows: gcc -O2 -s -o clicker.exe main.c
* Linux: gcc -O2 -s -o clicker_linux main.c
*
* Требования: curl в PATH, curl 7.86+ (WebSocket-клиент)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
# include <windows.h>
# include <io.h>
# define access _access
# define F_OK 0
#else
# include <unistd.h>
#endif
#define DEFAULT_QUERY "\xd0\xbc\xd0\xb5\xd0\xb3\xd0\xb0\xd0\xb1\xd0\xb0\xd0\xb9\xd1\x82 \xd0\xbf\xd0\xbb\xd1\x8e\xd1\x81"
#define DEFAULT_DOMAIN "megabyteplus.ru"
#define CDP_PORT 9222
#define TMP_JSON "cdp_cmd.json"
#define TMP_LIST "cdp_list.json"
static int g_cdp_id = 1;
/* ---------- утилиты ---------- */
static void sleep_ms(int ms)
{
#ifdef _WIN32
Sleep((DWORD)ms);
#else
usleep((useconds_t)ms * 1000);
#endif
}
static int file_exists(const char *path)
{
return access(path, F_OK) == 0;
}
static void json_escape(const char *src, char *dst, size_t dst_size)
{
size_t j = 0;
if (dst_size == 0)
return;
for (; *src && j + 2 < dst_size; src++) {
char c = *src;
if (c == '\\' || c == '"') {
if (j + 3 >= dst_size)
break;
dst[j++] = '\\';
dst[j++] = c;
} else if ((unsigned char)c < 0x20) {
if (j + 6 >= dst_size)
break;
j += (size_t)snprintf(dst + j, dst_size - j, "\\u%04x", (unsigned char)c);
} else {
dst[j++] = c;
}
}
dst[j] = '\0';
}
static int write_text_file(const char *path, const char *text)
{
FILE *f = fopen(path, "wb");
if (!f)
return -1;
if (fputs(text, f) == EOF) {
fclose(f);
return -1;
}
fclose(f);
return 0;
}
static int run_curl_capture(const char *args, char *out, size_t out_size)
{
char cmd[4096];
#ifdef _WIN32
snprintf(cmd, sizeof(cmd), "curl -s %s > \"%s\" 2>nul", args, TMP_LIST);
#else
snprintf(cmd, sizeof(cmd), "curl -s %s > '%s' 2>/dev/null", args, TMP_LIST);
#endif
if (system(cmd) != 0)
return -1;
FILE *f = fopen(TMP_LIST, "rb");
if (!f)
return -1;
size_t n = fread(out, 1, out_size - 1, f);
out[n] = '\0';
fclose(f);
return (int)n;
}
static int cdp_send_ws(const char *ws_url, const char *json_body)
{
if (write_text_file(TMP_JSON, json_body) != 0)
return -1;
char cmd[8192];
#ifdef _WIN32
snprintf(cmd, sizeof(cmd),
"curl -s --max-time 10 --no-buffer --websocket \"%s\" -d @\"%s\" >nul 2>nul",
ws_url, TMP_JSON);
#else
snprintf(cmd, sizeof(cmd),
"curl -s --max-time 10 --no-buffer --websocket '%s' -d @'%s' >/dev/null 2>&1",
ws_url, TMP_JSON);
#endif
return system(cmd);
}
static int extract_ws_url(const char *json, char *ws_url, size_t ws_size)
{
const char *key = "\"webSocketDebuggerUrl\":\"";
const char *p = strstr(json, key);
if (!p)
return -1;
p += strlen(key);
const char *end = strchr(p, '"');
if (!end || (size_t)(end - p) >= ws_size)
return -1;
memcpy(ws_url, p, (size_t)(end - p));
ws_url[end - p] = '\0';
return 0;
}
static int cdp_get_ws_url(char *ws_url, size_t ws_size)
{
char list[65536];
char url[128];
snprintf(url, sizeof(url), "http://127.0.0.1:%d/json/list", CDP_PORT);
/* несколько попыток — браузер может стартовать медленно */
for (int attempt = 0; attempt < 15; attempt++) {
if (run_curl_capture(url, list, sizeof(list)) > 0) {
if (extract_ws_url(list, ws_url, ws_size) == 0)
return 0;
}
sleep_ms(500);
}
return -1;
}
static int cdp_evaluate(const char *ws_url, const char *expression)
{
char escaped[8192];
char json[9216];
json_escape(expression, escaped, sizeof(escaped));
snprintf(json, sizeof(json),
"{\"id\":%d,\"method\":\"Runtime.evaluate\",\"params\":{\"expression\":\"%s\"}}",
g_cdp_id++, escaped);
return cdp_send_ws(ws_url, json);
}
static int cdp_key_char(const char *ws_url, const char *text)
{
char escaped[64];
char json[512];
json_escape(text, escaped, sizeof(escaped));
snprintf(json, sizeof(json),
"{\"id\":%d,\"method\":\"Input.dispatchKeyEvent\",\"params\":{\"type\":\"char\",\"text\":\"%s\"}}",
g_cdp_id++, escaped);
return cdp_send_ws(ws_url, json);
}
static int cdp_key_enter(const char *ws_url)
{
char json_down[512];
char json_up[512];
snprintf(json_down, sizeof(json_down),
"{\"id\":%d,\"method\":\"Input.dispatchKeyEvent\",\"params\":"
"{\"type\":\"keyDown\",\"windowsVirtualKeyCode\":13,\"nativeVirtualKeyCode\":13,"
"\"code\":\"Enter\",\"key\":\"Enter\"}}",
g_cdp_id++);
snprintf(json_up, sizeof(json_up),
"{\"id\":%d,\"method\":\"Input.dispatchKeyEvent\",\"params\":"
"{\"type\":\"keyUp\",\"windowsVirtualKeyCode\":13,\"nativeVirtualKeyCode\":13,"
"\"code\":\"Enter\",\"key\":\"Enter\"}}",
g_cdp_id++);
cdp_send_ws(ws_url, json_down);
return cdp_send_ws(ws_url, json_up);
}
/* ---------- UTF-8: следующий символ ---------- */
static const char *next_utf8(const char *s, char *buf, size_t buf_size)
{
unsigned char c;
int len;
if (!s || !*s)
return NULL;
c = (unsigned char)*s;
if (c < 0x80)
len = 1;
else if ((c & 0xE0) == 0xC0)
len = 2;
else if ((c & 0xF0) == 0xE0)
len = 3;
else if ((c & 0xF8) == 0xF0)
len = 4;
else
len = 1;
if ((int)buf_size <= len)
len = 1;
memcpy(buf, s, (size_t)len);
buf[len] = '\0';
return s + len;
}
/* ---------- поиск браузера ---------- */
static int find_browser(char *path, size_t path_size)
{
#ifdef _WIN32
static const char *candidates[] = {
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
NULL
};
int i;
for (i = 0; candidates[i]; i++) {
if (file_exists(candidates[i])) {
strncpy(path, candidates[i], path_size - 1);
path[path_size - 1] = '\0';
return 0;
}
}
{
const char *local = getenv("LOCALAPPDATA");
if (local) {
snprintf(path, path_size,
"%s\\Yandex\\YandexBrowser\\Application\\browser.exe", local);
if (file_exists(path))
return 0;
}
}
#else
static const char *candidates[] = {
"/usr/bin/google-chrome",
"/usr/bin/chromium",
"/usr/bin/chromium-browser",
"/usr/bin/microsoft-edge",
"/usr/bin/yandex-browser",
NULL
};
int i;
for (i = 0; candidates[i]; i++) {
if (file_exists(candidates[i])) {
strncpy(path, candidates[i], path_size - 1);
path[path_size - 1] = '\0';
return 0;
}
}
#endif
return -1;
}
static int launch_browser(const char *browser_path)
{
char cmd[2048];
#ifdef _WIN32
snprintf(cmd, sizeof(cmd),
"start \"\" \"%s\" --remote-debugging-port=%d \"https://ya.ru\"",
browser_path, CDP_PORT);
#else
snprintf(cmd, sizeof(cmd),
"\"%s\" --remote-debugging-port=%d \"https://ya.ru\" >/dev/null 2>&1 &",
browser_path, CDP_PORT);
#endif
return system(cmd);
}
/* ---------- основной сценарий ---------- */
static int click_target_link(const char *ws_url, const char *domain)
{
char js[4096];
char escaped_domain[256];
json_escape(domain, escaped_domain, sizeof(escaped_domain));
snprintf(js, sizeof(js),
"(function(){"
"var links=document.querySelectorAll('a');"
"for(var i=0;i<links.length;i++){"
"if(links[i].href&&links[i].href.indexOf('%s')!==-1){"
"links[i].scrollIntoView({behavior:'smooth',block:'center'});"
"links[i].click();"
"return true;"
"}"
"}"
"return false;"
"})()",
escaped_domain);
return cdp_evaluate(ws_url, js);
}
int main(int argc, char *argv[])
{
const char *query = (argc > 1 && argv[1][0]) ? argv[1] : DEFAULT_QUERY;
const char *domain = (argc > 2 && argv[2][0]) ? argv[2] : DEFAULT_DOMAIN;
char browser[1024];
char ws_url[512];
char ch[8];
srand((unsigned)time(NULL));
if (find_browser(browser, sizeof(browser)) != 0) {
fprintf(stderr, "Browser not found.\n");
return 1;
}
if (launch_browser(browser) != 0) {
fprintf(stderr, "Failed to launch browser.\n");
return 1;
}
sleep_ms(3000);
if (cdp_get_ws_url(ws_url, sizeof(ws_url)) != 0) {
fprintf(stderr, "CDP endpoint not available on port %d.\n", CDP_PORT);
return 1;
}
cdp_evaluate(ws_url, "document.querySelector('input[name=\"text\"]').focus()");
for (const char *p = query; p && *p; ) {
p = next_utf8(p, ch, sizeof(ch));
if (!p && !ch[0])
break;
cdp_key_char(ws_url, ch);
sleep_ms(100 + (rand() % 100));
}
cdp_key_enter(ws_url);
sleep_ms(4000);
click_target_link(ws_url, domain);
sleep_ms(5000);
cdp_evaluate(ws_url, "window.scrollBy(0, 350)");
sleep_ms(2000);
cdp_evaluate(ws_url, "window.scrollBy(0, 350)");
return 0;
}