🎯 Trình duyệt đám mây tùy chỉnh, chống phát hiện được hỗ trợ bởi Chromium tự phát triển, thiết kế dành cho trình thu thập dữ liệu web và tác nhân AI. 👉Dùng thử ngay
Kể từ đầu năm nay, chiến lược SEO của nhiều công ty đã trải qua những thay đổi cơ bản.
Ngày càng nhiều người dùng không mở tìm kiếm Google khi họ cần thông tin. Thay vào đó, họ hỏi về sản phẩm, dịch vụ và thương hiệu trực tiếp trong ChatGPT, Claude hoặc Gemini.
Điều này có nghĩa là: tính khả thi của bạn trong ChatGPT đang trở thành tiêu chuẩn mới cho sự cạnh tranh thương hiệu.
Vấn đề là — ChatGPT không có tính năng "xếp hạng" và không có "công cụ phân tích từ khóa."
Bạn đơn giản không thể biết:
Thương hiệu của tôi có xuất hiện trong câu trả lời của ChatGPT không?
ChatGPT có đề xuất các đối thủ cạnh tranh của tôi không?
Các câu trả lời có khác nhau giữa các quốc gia hoặc ngôn ngữ không?
Để giải quyết những câu hỏi này, bước đầu tiên là:
👉 Thực hiện các truy vấn hàng loạt các câu trả lời của ChatGPT để thu thập dữ liệu và rút ra những hiểu biết có thể hành động
GEO là gì?
Tối ưu hóa Động cơ Sinh ra (GEO) là thực tiễn tạo ra và tối ưu hóa nội dung để nó xuất hiện trong các câu trả lời do AI sinh ra trên các nền tảng như Google AI Overviews, AI Mode, ChatGPT và Perplexity.
Trong quá khứ, thành công có nghĩa là xếp hạng cao trên các trang kết quả của công cụ tìm kiếm (SERPs). Nhìn về tương lai, có thể sẽ không còn khái niệm "xếp hạng cao nhất." Thay vào đó, bạn cần trở thành sự đề xuất ưu tiên—giải pháp mà các công cụ AI chọn trình bày trong câu trả lời của họ.
Các mục tiêu cốt lõi của tối ưu hóa GEO không còn chỉ giới hạn ở số lần nhấp chuột mà còn tập trung vào ba chỉ số chính:
Tiềm năng thương hiệu: Tăng xác suất thương hiệu của bạn xuất hiện trong các câu trả lời do AI sinh ra.
Uy tín nguồn: Đảm bảo miền, nội dung, hoặc dữ liệu của bạn được chọn làm tham chiếu đáng tin cậy bởi AI.
Sự nhất quán trong câu chuyện và vị trí tích cực: Đảm bảo AI mô tả thương hiệu của bạn một cách chuyên nghiệp, chính xác và tích cực.
Điều này có nghĩa là logic SEO truyền thống dựa trên "xếp hạng từ khóa" đang dần nhường chỗ cho các cơ chế trích dẫn nguồn AI.
Các thương hiệu phải tiến hóa từ việc "có thể tìm kiếm" thành đáng tin cậy, được trích dẫn và được đề xuất một cách chủ động.
Tại sao nên tự động hóa các truy vấn hàng loạt ChatGPT?
Từ góc độ tiếp thị và SEO, ChatGPT đã trở thành một kênh mới cho việc khám phá và tiếp cận nội dung.
Tuy nhiên, có ba điểm yếu chính:
Không có khả năng nhìn thấy phạm vi thương hiệu
Các công ty không thể biết liệu sản phẩm của mình có được lập chỉ mục, đề cập hoặc được ChatGPT đề xuất hay không. Thiếu dữ liệu, không thể tạo ra các chiến lược tối ưu hóa hoặc phân phối nội dung nhắm mục tiêu.
Thiếu hiểu biết ở cấp độ GEO
Các câu trả lời của ChatGPT thay đổi tùy thuộc vào khu vực, ngôn ngữ, và thậm chí cả múi giờ. Một sản phẩm được đề xuất cho người dùng tại Mỹ có thể không xuất hiện cho người dùng Nhật Bản. Đối với các chiến lược quốc tế, các công ty phải hiểu những khác biệt này.
Các công cụ SEO truyền thống không thể cung cấp dữ liệu này
Các công cụ SEO hiện tại (ví dụ: Ahrefs, Semrush) có khả năng hạn chế và không thể theo dõi hoàn toàn các câu trả lời của ChatGPT. Điều này có nghĩa là một cách tiếp cận mới là cần thiết để theo dõi sự tiếp cận thương hiệu trong các kênh tìm kiếm AI.
Do đó, mục tiêu cốt lõi của truy vấn hàng loạt ChatGPT là thu thập, phân tích và tối ưu hóa một cách hệ thống sự hiện diện của thương hiệu bạn trong các câu trả lời của ChatGPT. Điều này giúp các công ty:
Xác định các câu hỏi tiềm năng cao đã được ChatGPT đề cập;
Khám phá những thiếu sót nội dung chưa được đề cập;
Phát triển các chiến lược tối ưu hóa GEO có mục tiêu.
Tại sao chọn Scrapeless Cloud Browser?
Nhiều người có thể cân nhắc việc gọi trực tiếp API OpenAI để thực hiện các truy vấn hàng loạt.
Tuy nhiên, trên thực tế, cách tiếp cận API có những hạn chế rõ ràng:
Kết quả dễ bị ảnh hưởng bởi sở thích lịch sử và ngữ cảnh, làm cho chúng mất khách quan.
Rất khó để nhanh chóng chuyển đổi IP để mô phỏng việc truy cập từ các vị trí địa lý khác nhau.
Chi phí truy vấn hàng loạt rất cao (tính theo token, trở nên đắt đỏ khi quy mô lớn).
Scrapeless Browser là một trình duyệt đám mây được thiết kế cho các tác vụ trích xuất dữ liệu và tự động hóa. Nó cho phép bạn truy cập ChatGPT từ đám mây theo cách mô phỏng hành vi của người dùng thực, cung cấp kết quả chính xác và toàn diện hơn.
So với các cuộc gọi API truyền thống, Scrapeless Cloud Browser nổi bật ở một số điểm:
Không có sự can thiệp từ sở thích tài khoản
Tất cả các truy vấn đều được thực hiện trong các môi trường trình duyệt độc lập, không có đăng nhập, đảm bảo kết quả khách quan và đáng tin cậy.
Mô phỏng GEO đa vùng
Các proxy dân cư tích hợp từ hơn 195 quốc gia, ISP tĩnh và IP không giới hạn cho phép dễ dàng mô phỏng người dùng từ các địa điểm khác nhau.
Tính tương tác cao và chi phí thấp
Hỗ trợ hơn 1.000 phiên đồng thời cho mỗi nhiệm vụ, tính phí theo thời gian, với chi phí thấp hơn nhiều so với các API truyền thống.
Tương thích gốc với các framework chính
Di chuyển các dự án Puppeteer hoặc Playwright hiện có chỉ với một dòng mã—không cần thích ứng thêm.
Chống phát hiện thông minh và gỡ lỗi trực quan
Xử lý tích hợp cho Cloudflare, reCAPTCHA và các bảo vệ khác, với hỗ trợ gỡ lỗi Live View và ghi lại phiên.
Tóm lại, Scrapeless Cloud Browser cho phép bạn thực hiện các truy vấn "ChatGPT từ góc độ người dùng" hàng loạt một cách hiệu quả, tiết kiệm chi phí và chính xác—không cần đăng ký hàng trăm tài khoản ChatGPT—và tự động trích xuất kết quả có cấu trúc.
Ví dụ: Truy vấn hàng loạt ChatGPT sử dụng Scrapeless Browser
Scrapeless Browser là dịch vụ trình duyệt headless dựa trên đám mây tương thích với các framework tự động hóa lớn như Puppeteer và Playwright. Sử dụng nó, bạn không cần duy trì trình duyệt cục bộ, proxy hay nút; bạn có thể khởi động chỉ với một dòng mã kết nối.
Ở đây, việc làm sạch HTML được thực hiện: các thẻ <script>, <style>, <svg>, <img> bị loại bỏ để thu được nội dung cơ thể sạch sẽ.
💡 Lợi Thế Scrapeless #3: Khai Thác Kết Quả Nhiều Loại
Một yêu cầu duy nhất có thể lấy nhiều loại thông tin cấu trúc mà không cần nhiều cuộc gọi hoặc kết hợp các công cụ khác nhau.
Không chỉ văn bản, mà còn hình ảnh, sản phẩm, trích dẫn, liên kết đính kèm và HTML sạch đều có thể được khai thác.
Mỗi loại dữ liệu được đóng gói dưới dạng mảng đối tượng (ví dụ, ChatgptResponse['products']), giúp dễ dàng xuất trực tiếp sang JSON, CSV hoặc Webhooks, và hỗ trợ quy trình tự động hóa ở phía sau.
5. Bối Cảnh & Phiên Trình Duyệt Độc Lập
5.1 Tách Biệt Mức Phiên
tsCopy
const { session_name, task_id, ... } = input;
browser = await this.connectToBrowser({
session_name, // Mỗi nhiệm vụ có thể chỉ định một tên phiên riêng biệt
session_ttl: 600, // Thời gian sống của phiên
session_recording,
proxy_url,
// ...
});
Sử dụng tham số session_name, các truy vấn khác nhau có thể sử dụng các phiên trình duyệt riêng biệt, đạt được tách biệt mức phiên.
5.2 Tách Biệt Phiên Bản Trình Duyệt
tsCopy
async solver(input: QueryChatgptRequest, ...): Promise<BaseOutput> {
let browser: Browser;
try {
// Tạo một kết nối trình duyệt mới cho mỗi lần gọi
browser = await this.connectToBrowser(...);
const page = await browser.newPage();
// Thực hiện các nhiệm vụ
} finally {
// Đóng trình duyệt sau khi nhiệm vụ hoàn tất
await page.close();
await browser.close();
}
}
Mỗi cuộc gọi solver() sẽ:
Tạo một phiên bản trình duyệt độc lập
Tự động dọn dẹp sau khi sử dụng trong khối finally
5.3 Tách Biệt Proxy
tsCopy
const { proxy_url } = input;
browser = await this.connectToBrowser({
proxy_url, // Mỗi nhiệm vụ có thể sử dụng một proxy khác nhau
// ...
});
const proxy_country = /-country_([A-Z]{2,3})/.exec(proxy_url)?.[1] || 'ANY';
Các nhiệm vụ khác nhau có thể đạt được tách biệt mức mạng bằng cách sử dụng các giá trị proxy_url khác nhau.
💡 Lợi Thế Scrapeless #5: 195+ Nút Quốc Gia, Proxy Tự Động & Mô Phỏng Địa Phương
Lựa Chọn IP Quốc Gia Tự Động
Mã quốc gia được phân tích từ proxy_url (ví dụ, -country_US, -country_JP), và Scrapeless tự động định tuyến các yêu cầu đến các IP dân cư trong khu vực tương ứng.
Không Cần Bảo Trì Hồ Bơi Proxy
Backend tự động quản lý các nút toàn cầu, vì vậy người dùng không cần thiết lập hoặc cập nhật danh sách proxy cho bản thân.
Môi Trường Trình Duyệt Địa Phương fingerprint.localization.timezone có thể đặt múi giờ. Kết hợp với các phiên độc lập, nó mô phỏng môi trường khu vực mục tiêu, ảnh hưởng đến cách hiển thị nội dung và kết quả tìm kiếm cụ thể theo khu vực.
Nhận Kết Quả Địa Phương Thực Tế ChatgptResponse.country_code được trả về cho biết vị trí địa lý của yêu cầu, giúp tối ưu hóa SEO quốc tế, giám sát thương hiệu, hoặc phân tích nội dung nhạy cảm theo khu vực chính xác hơn.
7. Khai Thác Kết Quả và Hỗ Trợ Nhiều Định Dạng Đầu Ra
7.1 Đầu Ra Cấu Trúc
Trong phương thức startChat, dữ liệu đã được nắm bắt được đóng gói vào một đối tượng ChatgptResponse thống nhất:
tsCopy
resolve({
prompt,
success: true,
answer: answerResponse, // văn bản / html / thô
country_code: proxy_country, // thông tin địa lý
citations: gptCitations,
links_attached: gptLinksAttached,
image_cards: gptImageCards,
products: gptRecommendProducts,
url: _url,
});
💡 Lợi Thế Scrapeless #6: Đầu Ra Cấu Trúc
Mỗi nhiệm vụ truy vấn tạo ra một đối tượng cấu trúc.
Bao gồm các trường như câu trả lời văn bản, liên kết đính kèm, hình ảnh, sản phẩm được đề xuất, trích dẫn, mã quốc gia và URL.
Các đối tượng cấu trúc có thể được sử dụng trực tiếp cho tự động hóa, mà không cần phân tích thêm.
7.2 Nhiều Phương Pháp Đầu Ra
Trong phương thức solver, kết quả có thể được đẩy hoặc trả về:
async format(data: Uint8Array): Promise<QueryChatgptRequest> {
if (!data) {
throw new Error('Không có dữ liệu đầu vào hợp lệ');
}
const input = JSON.parse(data.toString()) as QueryChatgptRequest;
if (!input.prompt) {
this.logger.error(`prompt là bắt buộc`);
throw new Error('prompt là bắt buộc');
}
return {
...input,
timeout: input.timeout || this.defaultTimeout,
web_search: input.web_search ?? true,
session_name: input.session_name || 'Trả lời của Chatgpt',
session_recording: input.session_recording || false,
answer_type: input.answer_type || 'văn bản',
};
}
private startChat(params: StartChatParams): Promise<ChatgptResponse> {
return new Promise(async (resolve, reject: (reason: ChatgptResponse) => void) => {
const { prompt, answer_type, web_search, timeout, page, browser, proxy_url } = params;
let action: string;
let isAborted = false;
let rawResponse: string;
this.logger.debug((action = 'Đang kết nối với Trình duyệt'));
const proxy_country = /-country_([A-Z]{2,3})/.exec(proxy_url)?.[1] || 'BẤT KỲ';
const query = new URLSearchParams({ q: prompt });
if (web_search) {
query.set('hints', 'tìm kiếm');
}
const baseUrl = 'https://chatgpt.com';
const _url = `${baseUrl}/?${query.toString()}`;
function waitForChatGPTResponse(page: Page): Promise<string> {
return new Promise((resolve, reject) => {
let retryCount = 0;
const CHECK_INTERVAL = 500; // Kiểm tra mỗi 500ms
const checkResponse = async () => {
try {
if (isAborted) {
resolve('hết thời gian chờ');
return;
}
const currentContent = await page.evaluate(() => {
const assistantMessage = '[data-message-author-role="assistant"]';
const $assistantMessages = document.querySelectorAll(assistantMessage);
const lastMessage = $assistantMessages[$assistantMessages.length - 1];
if (!lastMessage) return null;
// Khi có nhiều hơn một nút sao chép xuất hiện, điều đó có nghĩa là câu trả lời của gpt đã hoàn thành
const $answerCopyButtons = document.querySelectorAll('button[data-testid="copy-turn-action-button"]');
if ($answerCopyButtons.length > 1) {
return lastMessage.textContent || 'Không có nội dung';
} else {
return null;
}
});
// Nếu nội dung chưa thay đổi và không rỗng
if (currentContent) {
retryCount++;
// Nếu nội dung ổn định và không rỗng, phản hồi được coi là hoàn thành
if (retryCount >= 3) {
// Nội dung ổn định trong 1.5 giây
resolve(currentContent);
return;
}
}
// Tiếp tục kiểm tra
setTimeout(checkResponse, CHECK_INTERVAL);
} catch (error) {
reject(error);
}
};
// Bắt đầu kiểm tra
checkResponse();
});
}
async function receiveChatGPTStream() {
const client = await page.createCDPSession();
await client.send('Fetch.enable', {
patterns: [
{
urlPattern: '*conversation',
requestStage: 'Phản hồi',
},
],
});
client.on('Fetch.requestPaused', async (event) => {
const { requestId, request, responseHeaders } = event;
const isSSE = responseHeaders?.some(
(h) => h.name?.toLowerCase() === 'content-type' && h.value?.includes('text/event-stream'),
);
if (request.url.includes('/conversation') && isSSE) {
try {
const { body, base64Encoded } = await client.send('Fetch.getResponseBody', { requestId });
rawResponse = base64Encoded ? Buffer.from(body, 'base64').toString('utf-8') : body;
} catch (err) {
console.warn('Không thể lấy phản hồi của luồng', err.message);
}
}
await client.send('Fetch.continueRequest', { requestId });
});
}
function throwError(errorReason: string) {
const error: ChatgptResponse = {
prompt,
success: false,
country_code: proxy_country,
error_reason: errorReason,
url: _url,
};
reject(error);
}
const timeoutId = setTimeout(() => {
isAborted = true;
throwError(`Thời gian chờ Chat hết sau ${timeout}ms`);
}, timeout);
try {
this.logger.debug((action = 'Đăng ký CDP để ghi lại dữ liệu luồng GPT (raw_response)'));
await receiveChatGPTStream();
this.logger.debug((action = 'Đang điều hướng đến chatgpt.com'));
const navigateTimeout = 25_000 * this.timeoutMultiplier;
try {
await page.goto(_url, { timeout: navigateTimeout });
} catch {
throwError(Thời gian chờ khi điều hướng đến chatgpt.com (${navigateTimeout}ms));
return;
}
Copy
// Thêm listener thay đổi URL
page.on('framenavigated', async (frame) => {
if (frame !== page.mainFrame()) return;
const url = frame.url();
if (!url.startsWith('https://auth.openai.com')) return;
isAborted = true;
throwError(`Chuyển hướng đến trang đăng nhập OpenAI khi <<${_url}>> - ${action}`);
return;
});
if (isAborted) return;
await this.wait(50, 150);
this.logger.debug((action = 'Đảm bảo rằng input tồn tại'));
const inputs = ['#prompt-textarea', '[placeholder="Hỏi bất kỳ điều gì"]'];
try {
await Promise.race(
inputs.map(async (input) => {
await page.waitForSelector(input, {
timeout: 20_000 * this.timeoutMultiplier,
visible: true,
});
return input;
}),
);
} catch {
throwError('Khu vực hiện tại không khả dụng hoặc đã chuyển hướng đến trang đăng nhập');
return;
}
if (isAborted) return;
await this.wait(150, 250);
this.logger.debug((action = 'Đợi phản hồi từ GPT'));
let gptAnswer: string;
try {
gptAnswer = await waitForChatGPTResponse(page);
this.logger.debug((action = 'Đã nhận phản hồi GPT'));
} catch (error: any) {
this.logger.error(`Không thể nhận phản hồi: ${error.message}`);
throwError(`Lấy phản hồi từ chatgpt thất bại`);
return;
}
if (isAborted) return;
await this.wait(150, 250);
this.logger.debug((action = 'Lấy thẻ hình ảnh của chatgpt'));
const imageCardsSelector = 'div.no-scrollbar:has(button img) img';
const imageCardsLightBoxSelector = 'div[data-testid="modal-image-gen-lightbox"] ol li img';
const imageCardsLightBoxCloseSelector = 'div[data-testid="modal-image-gen-lightbox"] button';
let gptImageCards: ChatgptResponse['image_cards'] = [];
try {
const firstImageCard = await page.$(imageCardsSelector);
if (firstImageCard) {
firstImageCard.click();
await page.waitForSelector(imageCardsLightBoxSelector);
gptImageCards = await page.$$eval(imageCardsLightBoxSelector, (elements) => {
return elements.map((element, index) => {
const url = element.getAttribute('src') || '';
return { url, position: index + 1 };
});
});
await page.waitForSelector(imageCardsLightBoxCloseSelector);
await page.click(imageCardsLightBoxCloseSelector);
} else {
this.logger.debug((action = 'Không tìm thấy thẻ hình ảnh'));
}
} catch (error: any) {
this.logger.debug((action = `Lấy thẻ hình ảnh chatgpt: ${error.toString()}`));
}
if (isAborted) return;
await this.wait(300, 450);
this.logger.debug((action = 'Lấy sản phẩm gợi ý của chatgpt'));
const closeButtonSelector = `button[data-testid="close-button"]`;
const recommendProductsSelector = 'div.markdown div.relative > div.flex.flex-row:has(img):not(a) > div img';
const recommendProductDetailsSelector = `section[screen-anchor="top"] div[slot="content"]`;
const detailLinkSelector = `${recommendProductDetailsSelector} span a`;
const gptRecommendProducts: ChatgptResponse['products'] = [];
try {
const recommendProducts = await page.$$(recommendProductsSelector);
if (recommendProducts.length) {
let lastUrl = '';
for (const [index] of recommendProducts.entries()) {
// Chuyển hướng liên kết bên ngoài có thể được kích hoạt
let newPage: Page = null as unknown as Page;
const targetCreatedHandler = async (target: Target) => {
this.logger.debug((action = `Lấy sản phẩm gợi ý của chatgpt: ${target.type()}`));
try {
if (target.type() === 'page') {
const pageTarget = await target.page();
const opener = await target.opener();
if (opener && (opener as any)?._targetId === (page.target() as any)?._targetId) {
newPage = pageTarget as Page;
}
}
} catch (e) {}
};
browser.once('targetcreated', targetCreatedHandler);
// Nhấp vào mục gợi ý
await page.evaluate(
(selector, index) => {
const currentProduct = document.querySelectorAll(selector)?.[index];
javascriptCopy
(currentProduct as HTMLElement)?.click();
},
recommendProductsSelector,
index,
);
await this.wait(750, 950);
browser.off('targetcreated', targetCreatedHandler);
if (newPage) {
const url = newPage.url();
const title = await newPage.title();
gptRecommendProducts.push({ url, title, image_urls: [] });
await newPage.close();
continue;
}
await page.waitForSelector(detailLinkSelector, { timeout: 20_000 * this.timeoutMultiplier });
// Chờ để thông tin thay đổi
let maxRetry = 30;
while (maxRetry-- > 0) {
const currentUrl = await page.$eval(detailLinkSelector, (el) => el.getAttribute('href') || '');
if (currentUrl && currentUrl !== lastUrl) {
lastUrl = currentUrl;
break;
}
await this.wait(200, 300);
}
const info = await page.$eval(
recommendProductDetailsSelector,
(element, currentUrl) => {
const title = element.querySelector('div.text-xl')?.textContent || '';
const image_urls = Array.from(element.querySelectorAll('.no-scrollbar img')).map((img) =>
img.getAttribute('src'),
);
return { url: currentUrl, title, image_urls };
},
lastUrl,
);
gptRecommendProducts.push(info);
}
await page.click(closeButtonSelector);
} else {
this.logger.debug((action = 'Không tìm thấy sản phẩm gợi ý'));
}
} catch (error: any) {
this.logger.debug((action = `Lấy sản phẩm gợi ý của chatgpt: ${error.toString()}`));
}
if (isAborted) return;
await this.wait(500, 1000);
this.logger.debug((action = 'Lấy trích dẫn của chatgpt'));
const citationsEntranceSelector = `button.group\\/footnote`;
const citationsContentLinkSelector = `section[screen-anchor="top"] div[slot="content"] a`;
let gptCitations: ChatgptResponse['citations'] = [];
await page.bringToFront();
try {
const citationsButton = await page.waitForSelector(citationsEntranceSelector, {
timeout: 3_000,
});
if (citationsButton) {
await citationsButton.click();
const citationsContent = await page.waitForSelector(citationsContentLinkSelector, {
timeout: 20_000 * this.timeoutMultiplier,
});
if (citationsContent) {
gptCitations = await page.$$eval(citationsContentLinkSelector, (elements) => {
return elements.map((element) => {
const url = element.href || '';
const icon = element.querySelector('img')?.getAttribute?.('src');
const title = element.querySelector('div:nth-child(2)')?.textContent || '';
const description = element.querySelector('div:nth-child(3)')?.textContent || '';
return { url, icon, title, description };
});
});
await page.click(closeButtonSelector);
}
} else {
this.logger.debug((action = 'Không tìm thấy trích dẫn'));
}
} catch (error: any) {
this.logger.debug((action = `Lấy trích dẫn của chatgpt: ${error.toString()}`));
}
// Trong một số trường hợp, cần thêm một phần tử cố định vào trang
// để ngăn puppeteer nhấp vào các phần tử ngẫu nhiên
if (isAborted) return;
this.logger.debug((action = 'Thêm các phần tử cố định để tránh nhấp chuột không mong muốn'));
await page.evaluate(() => {
const element = document.createElement('div');
element.style.position = 'fixed';
element.style.top = '0';
element.style.left = '0';
element.style.width = '100%';
element.style.height = '100%';
element.style.zIndex = '1000';
document.body.appendChild(element);
});
if (isAborted) return;
await this.wait(150, 250);
this.logger.debug((action = 'Lấy các liên kết đính kèm của chatgpt'));
const markdownLinksSelector = 'div.markdown a';
let gptLinksAttached: ChatgptResponse['links_attached'] = [];
try {
gptLinksAttached = await page.$$eval(markdownLinksSelector, (elements) => {
return elements.map((element, index) => {
const url = element.href || '';
const title = element.textContent || '';
return { url, title, position: index + 1 };
});
});
} catch (error: any) {
this.logger.debug((action = 'Không tìm thấy liên kết đính kèm'));
}
Copy
this.logger.debug((action = 'Đang lấy nội dung'));
const body = await page.evaluate(() => document.body.innerHTML);
const cleanBody = body
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '') // Xóa thẻ script
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '') // Xóa thẻ style
.replace(/<svg[^>]*>[\s\S]*?<\/svg>/gi, '') // Xóa thẻ svg
.replace(/<img[^>]*\/?>/gi, '') // Xóa thẻ img
.replace(/style="[^"]*"/gi, '') // Xóa tất cả các thuộc tính style
.replace(/class="[^"]*"/gi, '') // Xóa tất cả các thuộc tính class
.replace(/<!--[\s\S]*?-->/g, '') // Xóa các bình luận
// Chuyển đổi các thay thế liên quan
.replace(/<span>·<\/span>/g, '') // Xóa thẻ span có ·
.replace(/<a href="https:\/\/www\.google\.com\/maps\/[^"]*"[^>]*>[\s\S]*?<\/a>/g, '') // Xóa tất cả các liên kết google maps
.replace(/<a href="tel:+[^"]*"[^>]*>[\s\S]*?<\/a>/g, '') // Xóa tất cả các liên kết điện thoại
.replace(/\s+/g, ' ') // Chuẩn hóa khoảng trắng
.trim();
this.logger.debug((action = 'Kiểm tra phản hồi lỗi'));
const hasError = [
'Đã có sự cố xảy ra khi tạo phản hồi.',
'Hoạt động bất thường đã được phát hiện từ thiết bị của bạn.',
'Đã xảy ra lỗi. Hoặc động cơ bạn yêu cầu không tồn tại hoặc có vấn đề khác trong việc xử lý yêu cầu của bạn.',
].some((message) => cleanBody.includes(message));
if (hasError) {
throwError(`ChatGPT hiện không khả dụng`);
return;
}
this.logger.log((action = 'Trò chuyện thành công'));
const answerMap: Record<QueryChatgptRequest['answer_type'], string> = {
html: cleanBody,
raw: rawResponse,
text: gptAnswer,
};
const answerResponse = answerMap[answer_type] ?? answerMap.text;
resolve({
prompt,
success: true,
answer: answerResponse,
country_code: proxy_country,
citations: gptCitations,
links_attached: gptLinksAttached,
image_cards: gptImageCards,
products: gptRecommendProducts,
url: _url,
});
} catch (error: any) {
if (!isAborted) {
throwError(this.internalErrorSymbol + (error.message || String(error)));
}
} finally {
clearTimeout(timeoutId);
try {
await page.close();
await browser.close();
} catch {}
}
});
}
private async connectToBrowser(opt: PuppeteerLaunchOptions, checkTimeout: () => boolean) {
let browser;
try {
const { browserWSEndpoint } = await this.scrapeless.browser.createSession(opt);
browser = await Promise.race([
puppeteer.connect({ browserWSEndpoint, defaultViewport: null }),
new Promise((_, reject) => {
const interval = setInterval(() => {
if (checkTimeout()) {
clearInterval(interval);
browser?.close();
reject(new Error('Thời gian kết nối trình duyệt đã hết'));
}
}, 1000);
}),
]);
return browser;
} catch (error) {
this.logger.error(Kết nối trình duyệt không thành công: ${error.message});
throw error;
}
}
private async fakePageDate(page: Page) {
await page.evaluateOnNewDocument(() => {
// Bắt ngày mới
const fixedDate = new Date();
// ngẫu nhiên đặt ngày thành 1-3 năm trước
const days = 100 + Math.floor(Math.random() * 365 * 3 - 100);
fixedDate.setDate(fixedDate.getDay() - days);
// const fixedDate = new Date('2022-01-01T00:00:00Z');
const OriginalDate = Date;
return OriginalDate.UTC(...args);
}
}
Object.getOwnPropertyNames(OriginalDate).forEach((prop) => {
FakeDate[prop as keyof typeof FakeDate] = OriginalDate[prop as keyof typeof OriginalDate] as any;
});
(window.Date as typeof FakeDate) = FakeDate;
});
}
private async wait(fromMs: number, toMs: number) {
const ms = fromMs + Math.random() * (toMs - fromMs);
await new Promise((resolve) => setTimeout(resolve, ms));
}
}
## Sau khi truy vấn: Biến phản hồi thô thành chiến lược hoạt động GEO có thể hành động trong 30 phút
Hiểu nhanh các kết quả tìm kiếm và xác định các chủ đề nội dung:
1. Sao chép JSON kết quả → Mở [https://csvjson.com/json2csv](https://csvjson.com/json2csv) → lấy CSV → dán vào Excel.
2. Thêm hai cột mới:
- `brandCount` = `=IF(ISNUMBER(SEARCH("YourBrand",D2)),1,0)`
- `gap` = `F2-E2` (Cột F là số lần xuất hiện của đối thủ, Cột E là `brandCount`)

👉 **Kết luận:** Hiện tại, không ai đã "đưa ra chủ đề này," vì vậy bạn có thể ngay lập tức viết một bài viết như *“ABCProxy là gì?”* để chiếm lĩnh không gian câu trả lời.
**Mẹo:** Sau khi thực hiện 100 truy vấn hàng loạt lần tới, sắp xếp theo `gap` giảm dần → 20 kết quả hàng đầu trở thành ý tưởng nội dung ưu tiên.
| Trường | Ý nghĩa kinh doanh |
|--------------|----------------|
| prompt | Truy vấn gốc của người dùng |
| answer_text | Phản hồi đầy đủ từ ChatGPT |
| brandCount | Số lần thương hiệu của bạn xuất hiện trong câu trả lời |
| rivalCount | Số lần đối thủ xuất hiện |
| gap | `rivalCount - brandCount` → `0` = chưa được chiếm lĩnh, nội dung ưu tiên; `>0` = chọn chủ đề ngay lập tức, viết bài so sánh/xếp hạng; `<0` = duy trì cập nhật, tiếp tục tối ưu hóa |
---
## Kết luận
Với Scrapeless Cloud Browser, bạn có thể tự động hóa các truy vấn ChatGPT để đạt được tối ưu hóa GEO xuyên quốc gia, vượt thời gian và dễ dàng có được kết quả tìm kiếm chính xác, địa phương hóa. Dù cho SEO quốc tế, giám sát thương hiệu hay phân tích thông tin thị trường, Scrapeless giúp bạn nhanh chóng xây dựng một hệ thống truy vấn tự động ổn định, hiệu quả, và có thể mở rộng.
Scrapeless không chỉ cung cấp tự động hóa trình duyệt cho dữ liệu GEO mà còn cung cấp các công cụ tiên tiến và chiến lược dữ liệu để kiểm soát hoàn toàn cơ chế trích dẫn AI. Liên hệ với chúng tôi để mở khóa giải pháp dữ liệu GEO hoàn chỉnh!
Nhìn về phía trước, Scrapeless sẽ tiếp tục tập trung vào công nghệ trình duyệt đám mây, cung cấp cho doanh nghiệp các giải pháp khai thác dữ liệu hiệu suất cao, quy trình tự động và hỗ trợ cơ sở hạ tầng đại lý AI. Phục vụ các ngành như tài chính, bán lẻ, thương mại điện tử, SEO và marketing, Scrapeless cung cấp các giải pháp tùy chỉnh, dựa trên kịch bản để giúp doanh nghiệp đi trước trong kỷ nguyên dữ liệu thông minh.
Scrapeless Browser không chỉ là một công cụ tự động hóa - nó là:
> **Cơ sở hạ tầng thu thập dữ liệu “hệ sinh thái tìm kiếm AI” có thể mở rộng**
Cho phép bạn thực sự định lượng khả năng hiển thị thương hiệu ChatGPT, phạm vi từ khóa và xu hướng nội dung.
---
<div style="padding: 20px 0; text-align: center;">
<a
style="
margin: 8px;
display: inline-block;
text-decoration: none;
"
href="https://www.goproxy.com/register?link=https://app.scrapeless.com/passport/login?utm_source=official&utm_medium=blog&utm_campaign=chatgpt-geo"
>
<div
style="
font-weight: bold;
width: 100%;
max-width: 400px;
padding: 12px 40px;
background: #12A594;
border-radius: 5px;
border: 2px solid #12A594;
color: #fff;
cursor: pointer;
box-sizing: border-box;
font-size: 18px;
"
>
👉 Đăng nhập vào Scrapeless Browser >
</div>
</a>
</div>
Tại Scrapless, chúng tôi chỉ truy cập dữ liệu có sẵn công khai trong khi tuân thủ nghiêm ngặt các luật, quy định và chính sách bảo mật trang web hiện hành.
Nội dung trong blog này chỉ nhằm mục đích trình diễn và không liên quan đến bất kỳ hoạt động bất hợp pháp hoặc vi phạm nào.
Chúng tôi không đảm bảo và từ chối mọi trách nhiệm đối với việc sử dụng thông tin từ blog này hoặc các liên kết của bên thứ ba.
Trước khi tham gia vào bất kỳ hoạt động cạo nào, hãy tham khảo ý kiến cố vấn pháp lý của bạn và xem xét các điều khoản dịch vụ của trang web mục tiêu hoặc có được các quyền cần thiết.