Skip to content

Commit

Permalink
Server üzerinden discord ile captcha çözümü & ESM geçişi
Browse files Browse the repository at this point in the history
  • Loading branch information
RevoLand committed May 19, 2023
1 parent e169b9b commit 1d8ece2
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 44 deletions.
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "amazon-client",
"version": "1.0.0",
"description": "",
"main": "dist/app.js",
"type": "module",
"scripts": {
"dev": "cross-env ts-node ./src/app.ts",
"postbuild": "cross-env mkdir dist -p && cp package.json dist/package.json && cp .env.example dist/.env.example && cd dist",
Expand All @@ -15,18 +15,19 @@
"cheerio": "1.0.0-rc.12",
"dayjs": "1.11.7",
"dotenv": "16.0.3",
"log-update": "5.0.1",
"puppeteer": "13.3.1",
"ws": "8.13.0"
},
"devDependencies": {
"@types/node": "18.14.6",
"@types/node": "20.2.1",
"@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "5.54.1",
"@typescript-eslint/parser": "5.54.1",
"@typescript-eslint/eslint-plugin": "5.59.6",
"@typescript-eslint/parser": "5.59.6",
"cross-env": "7.0.3",
"eslint": "8.35.0",
"eslint": "8.40.0",
"ts-node": "10.9.1",
"typescript": "4.9.5"
"typescript": "5.0.4"
},
"optionalDependencies": {
"bufferutil": "^4.0.7"
Expand Down
19 changes: 10 additions & 9 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import 'dotenv/config';
import Client from './components/Client';
import { WebSocket } from 'ws';
import { wait } from './helpers/common';
import logUpdate from 'log-update';
import Client from './components/Client.js';

export let client: Client;

const main = async () => {
client = new Client();
client.initialize();

while (client.socket.readyState !== WebSocket.OPEN) {
console.log('Socket bağlantısı gerçekleştirilene kadar bekliyoruz!');
await wait(5000);
}

console.log('Socket bağlantısı başarılı bir şekilde gerçekleşti!', client.socket.readyState);
setInterval(() => {
logUpdate(`
Server: ${client.socket.url}
Status: ${client.socket.readyState}
Products: ${client.products.length}
Captcha: ${client.captcha.size}
`);
}, 500);
};

main();
38 changes: 33 additions & 5 deletions src/components/Client.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { randomInt } from 'crypto';
import { CloseEvent, ErrorEvent, RawData, WebSocket } from 'ws';
import webSocket from '../config/webSocket';
import { wait } from '../helpers/common';
import productParser from './product/productParser';
import webSocket from '../config/webSocket.js';
import { wait } from '../helpers/common.js';
import productParser from './product/productParser.js';

class Client {
socket: WebSocket;

captcha: Map<string, string> = new Map();

products: {
productId: number,
url: string
}[] = [];

private heartbeatTimeout: NodeJS.Timeout;

private heartbeat = () => {
Expand All @@ -16,26 +24,31 @@ class Client {
}, 15000 + 2000);
};

private handleServerMessage = async (data: RawData) => {
private handleServerMessage = async (serverMessage: RawData) => {
try {
const messageObject: {
type: string;
value: string;
data: string;
channelId: string;
} = JSON.parse(data.toString());
} = JSON.parse(serverMessage.toString());

if (messageObject.type === 'begin-tracking') {
const beginTrackingObject: {
productId: number,
url: string
} = JSON.parse(messageObject.value);

this.products.push(beginTrackingObject);

this.socket.send(JSON.stringify({
type: 'begin-tracking-handshake',
value: beginTrackingObject.productId
}), async () => {
const productParserResult = await productParser(beginTrackingObject.url);

this.products = this.products.filter(product => product.productId !== beginTrackingObject.productId);

if (!productParserResult) {
return;
}
Expand All @@ -49,8 +62,20 @@ class Client {
}

if (messageObject.type === 'create-tracking') {
const beginTrackingObject: {
productId: number,
url: string
} = {
url: messageObject.value,
productId: randomInt(Number.MAX_SAFE_INTEGER - 1000, Number.MAX_SAFE_INTEGER)
};

this.products.push(beginTrackingObject);

const productParserResult = await productParser(messageObject.value);

this.products = this.products.filter(product => product.productId !== beginTrackingObject.productId);

if (!productParserResult) {
return;
}
Expand All @@ -63,6 +88,9 @@ class Client {
}));
}

if (messageObject.type === 'captcha-answer') {
this.captcha.set(messageObject.data, messageObject.value);
}
} catch (error) {
console.error('Error parsing message from Server: ', error);
}
Expand Down
64 changes: 43 additions & 21 deletions src/components/product/productParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { CheerioAPI, load } from 'cheerio';
import dayjs from 'dayjs';
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import puppeteer from 'puppeteer';
import { trimNewLines } from '../../helpers/common';
import { getTldFromUrl } from '../../helpers/productUrlHelper';
import { ProductParserInterface } from '../../interfaces/ProductParserInterface';
import { client } from '../../app.js';
import { trimNewLines, wait } from '../../helpers/common.js';
import { getTldFromUrl } from '../../helpers/productUrlHelper.js';
import { ProductParserInterface } from '../../interfaces/ProductParserInterface.js';

const getParsedProductData = ($: CheerioAPI): ProductParserInterface | undefined => {
try {
Expand Down Expand Up @@ -54,7 +55,6 @@ const getParsedProductData = ($: CheerioAPI): ProductParserInterface | undefined
};

const productParser = async (url: string): Promise<ProductParserInterface | undefined> => {
console.log(dayjs().toString() + ' | Parsing product:', url);
const browser = await puppeteer.launch({
headless: true
});
Expand Down Expand Up @@ -93,34 +93,61 @@ const productParser = async (url: string): Promise<ProductParserInterface | unde
timeout: 60_000
});

const cookiesElement = await page.$('#sp-cc-accept');
let cookiesElement = await page.$('#sp-cc-accept');
if (cookiesElement) {
// Accept cookies!
await page.click('#sp-cc-accept');
}

// Load the content into cheerio for easier parsing
const $ = load((await page.content()).replace(/\n\s*\n/gm, ''));
let $ = load((await page.content()).replace(/\n\s*\n/gm, ''));

const captchaElement = await page.$('#captchacharacters');

// TODO: Captcha
if (captchaElement) {
// const captchaImg = $('form img').attr('src') ?? '';
// // productTracker.updateCaptcha(await computerVision(captchaImg));
// captcha resim url'ini getir
const captchaImg = $('form img').attr('src') ?? '';
// bu ürün url'i için server'dan gelmiş captcha metnini getir
let captchaText = client.captcha.get(url);

// eğer captcha metni yoksa server'a resmi gönder
if (!captchaText) {
client.socket.send(JSON.stringify({
type: 'captcha',
value: captchaImg,
data: url
}));

// server'dan captcha metni gelene kadar bekle
while (!client.captcha.has(url)) {
await wait(1000);
}

// server'dan gelen captcha metnini tanımla
captchaText = client.captcha.get(url);
}

// // await page.type('#captchacharacters', productTracker.captcha);
// captcha metni gir
await page.type('#captchacharacters', captchaText + '');

// // productTracker.updateCaptcha('');
// server'dan gelmiş captcha metnini temizle
client.captcha.delete(url);

// await Promise.all([page.click('button[type="submit"]'), page.waitForNavigation()]);
// sayfa yönlendirme beklemesi
// ve captcha formu gönderimi için promise oluşturup bekle
await Promise.all([page.waitForNavigation(), page.click('button[type="submit"]')]);

// const cookieJson = JSON.stringify(await page.cookies());
// writeFileSync(cookieFileName, cookieJson);
// güncel cookie'leri sonradan kullanım için kaydet
const cookieJson = JSON.stringify(await page.cookies());
writeFileSync(cookieFileName, cookieJson);

// await page.close();
cookiesElement = await page.$('#sp-cc-accept');
if (cookiesElement) {
// Accept cookies!
await page.click('#sp-cc-accept');
}

// return await productParser(url);
$ = load((await page.content()).replace(/\n\s*\n/gm, ''));
}

const product = getParsedProductData($);
Expand All @@ -140,17 +167,12 @@ const productParser = async (url: string): Promise<ProductParserInterface | unde
url
});

await page.close();

return;
}

await page.close();

return product;
} catch (error) {
console.error('productParser error', error);
await page.close();

return undefined;
} finally {
Expand Down
9 changes: 6 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"compilerOptions": {
/* Language and Environment */
"target": "es6",
"target": "ES2021",
"lib": [
"ES6"
"ES2021"
],
"types": [
"node"
],
/* Modules */
"module": "Node16",
"moduleResolution": "node",
"moduleResolution": "node16",
"rootDir": "./src",
"outDir": "./dist",
"esModuleInterop": true,
Expand All @@ -25,6 +25,9 @@
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"ts-node": {
"esm": true
},
"include": ["./src/**/*"],
"exclude": ["node_modules", "dist"]
}

0 comments on commit 1d8ece2

Please sign in to comment.