Added page number question to semrush extraction.
This commit is contained in:
parent
21fdd18e07
commit
ff580ec5d5
|
|
@ -296,67 +296,215 @@
|
|||
return csv;
|
||||
}
|
||||
|
||||
// Helper function to create notification
|
||||
function createNotification(message, duration = 3000, isError = false) {
|
||||
const notification = document.createElement('div');
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
padding: 12px 24px;
|
||||
background: ${isError ? '#f44336' : '#4CAF50'};
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
z-index: 10000;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
`;
|
||||
notification.textContent = message;
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Fade out and remove
|
||||
setTimeout(() => {
|
||||
notification.style.opacity = '0';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
// Dialog class for page count input
|
||||
class PageCountDialog {
|
||||
constructor() {
|
||||
this.dialog = null;
|
||||
}
|
||||
|
||||
create() {
|
||||
// Create dialog container
|
||||
this.dialog = document.createElement('div');
|
||||
this.dialog.style.cssText = `
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
z-index: 10000;
|
||||
font-family: Arial, sans-serif;
|
||||
min-width: 300px;
|
||||
`;
|
||||
|
||||
// Create content
|
||||
this.dialog.innerHTML = `
|
||||
<h2 style="margin: 0 0 15px 0; font-size: 16px;">SEMRush Keyword Extraction</h2>
|
||||
<p style="margin: 0 0 15px 0; font-size: 14px;">How many pages would you like to scrape?</p>
|
||||
<input type="number" min="1" value="5" style="
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
">
|
||||
<div style="text-align: right;">
|
||||
<button class="cancel" style="
|
||||
padding: 8px 15px;
|
||||
margin-right: 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #f0f0f0;
|
||||
cursor: pointer;
|
||||
">Cancel</button>
|
||||
<button class="confirm" style="
|
||||
padding: 8px 15px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
">Start Extraction</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add overlay
|
||||
const overlay = document.createElement('div');
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
`;
|
||||
|
||||
// Add to document
|
||||
document.body.appendChild(overlay);
|
||||
document.body.appendChild(this.dialog);
|
||||
|
||||
// Return promise that resolves with page count or null if cancelled
|
||||
return new Promise((resolve) => {
|
||||
const input = this.dialog.querySelector('input');
|
||||
const confirmBtn = this.dialog.querySelector('.confirm');
|
||||
const cancelBtn = this.dialog.querySelector('.cancel');
|
||||
|
||||
confirmBtn.addEventListener('click', () => {
|
||||
const value = parseInt(input.value);
|
||||
if (value > 0) {
|
||||
this.close();
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
|
||||
cancelBtn.addEventListener('click', () => {
|
||||
this.close();
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
// Handle Enter key
|
||||
input.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
const value = parseInt(input.value);
|
||||
if (value > 0) {
|
||||
this.close();
|
||||
resolve(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.dialog) {
|
||||
this.dialog.previousElementSibling?.remove(); // Remove overlay
|
||||
this.dialog.remove();
|
||||
this.dialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main function to extract keywords
|
||||
async function extractKeywords() {
|
||||
const progressDialog = new KeywordGrabberUI.ProgressDialog().create();
|
||||
try {
|
||||
const options = window.keywordGrabberOptions || { includeHeaders: true };
|
||||
const allKeywords = [];
|
||||
// Show dialog to get page count
|
||||
const dialog = new PageCountDialog();
|
||||
const maxPages = await dialog.create();
|
||||
|
||||
if (!maxPages) {
|
||||
console.log('Extraction cancelled by user');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Will extract up to ${maxPages} pages`);
|
||||
|
||||
// Wait for initial page load
|
||||
await waitForElement('.sm-pagination__input input', 10000);
|
||||
|
||||
const pageInfo = getCurrentPageInfo();
|
||||
if (!pageInfo) {
|
||||
throw new Error('Could not get page information');
|
||||
}
|
||||
|
||||
progressDialog.updateProgress(`Starting extraction from page ${pageInfo.currentPage} of ${pageInfo.totalPages}`);
|
||||
console.log(`Starting extraction from page ${pageInfo.currentPage} of ${pageInfo.totalPages}`);
|
||||
|
||||
let currentPage = pageInfo.currentPage;
|
||||
const totalPages = pageInfo.totalPages;
|
||||
|
||||
while (currentPage <= totalPages) {
|
||||
|
||||
const { currentPage, totalPages } = pageInfo;
|
||||
console.log(`Starting extraction from page ${currentPage} of ${totalPages}`);
|
||||
|
||||
const allKeywords = [];
|
||||
let currentPageNum = currentPage;
|
||||
|
||||
// Create progress notification
|
||||
createNotification(`Starting extraction: Page ${currentPageNum} of ${Math.min(totalPages, maxPages)}`, 2000);
|
||||
|
||||
// Extract keywords from each page
|
||||
while (currentPageNum <= Math.min(totalPages, maxPages)) {
|
||||
console.log(`Processing page ${currentPageNum}`);
|
||||
|
||||
const keywords = await extractCurrentPage();
|
||||
if (!keywords) {
|
||||
throw new Error('Failed to extract keywords from current page');
|
||||
if (keywords && keywords.length > 0) {
|
||||
allKeywords.push(...keywords);
|
||||
console.log(`Found ${keywords.length} keywords on page ${currentPageNum}`);
|
||||
createNotification(`Extracted ${keywords.length} keywords from page ${currentPageNum}`, 1500);
|
||||
}
|
||||
|
||||
allKeywords.push(...keywords);
|
||||
progressDialog.updateProgress(`Total keywords collected: ${allKeywords.length} (Page ${currentPage} of ${totalPages})`);
|
||||
console.log(`Total keywords collected: ${allKeywords.length} (Page ${currentPage} of ${totalPages})`);
|
||||
|
||||
if (currentPage < totalPages) {
|
||||
progressDialog.updateProgress(`Navigating to page ${currentPage + 1}...`);
|
||||
const success = await goToNextPage(currentPage, totalPages);
|
||||
if (!success) {
|
||||
throw new Error('Failed to navigate to next page');
|
||||
}
|
||||
currentPage++;
|
||||
} else {
|
||||
|
||||
if (currentPageNum >= Math.min(totalPages, maxPages)) {
|
||||
console.log('Reached target page count');
|
||||
break;
|
||||
}
|
||||
|
||||
const success = await goToNextPage(currentPageNum, totalPages);
|
||||
if (!success) {
|
||||
console.log('Failed to go to next page');
|
||||
break;
|
||||
}
|
||||
|
||||
currentPageNum++;
|
||||
}
|
||||
|
||||
// Format the keywords
|
||||
const formattedKeywords = formatKeywords(allKeywords, options.includeHeaders);
|
||||
|
||||
// Copy to clipboard
|
||||
copyToClipboard(formattedKeywords);
|
||||
if (allKeywords.length === 0) {
|
||||
throw new Error('No keywords found');
|
||||
}
|
||||
|
||||
progressDialog.updateProgress(`Extraction complete. Total keywords: ${allKeywords.length}`);
|
||||
console.log(`Extraction complete. Total keywords: ${allKeywords.length}`);
|
||||
// Format and copy to clipboard
|
||||
const csvContent = formatKeywords(allKeywords, window.keywordGrabberOptions.includeHeaders);
|
||||
await copyToClipboard(csvContent);
|
||||
|
||||
// Give users time to see the completion message
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
console.log(`Successfully extracted ${allKeywords.length} keywords`);
|
||||
createNotification(`Successfully extracted ${allKeywords.length} keywords from ${currentPageNum} pages`, 4000);
|
||||
|
||||
return allKeywords;
|
||||
} catch (error) {
|
||||
console.error('Error during keyword extraction:', error);
|
||||
progressDialog.updateProgress(`Error: ${error.message}`);
|
||||
// Keep error message visible for a moment
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
throw error;
|
||||
} finally {
|
||||
progressDialog.remove();
|
||||
createNotification(`Error: ${error.message}`, 5000, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue