Saudi Print & Pack Website Scraper

A new extension

Size

12.4 KB

Version

1.1.1

Created

Nov 15, 2025

Updated

28 days ago

1// ==UserScript==
2// @name		Saudi Print & Pack Website Scraper
3// @description		A new extension
4// @version		1.1.1
5// @match		https://*.saudi-pp.com/*
6// @icon		https://saudi-pp.com/wp-content/uploads/2023/11/print-icon-180x180.png
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Saudi Print & Pack Website Scraper loaded');
12
13    // Function to scrape all website URLs from the table
14    async function scrapeWebsites() {
15        console.log('Starting website scraping...');
16        
17        const table = document.querySelector('table[data-footable_id="23093"]');
18        if (!table) {
19            console.error('Table not found');
20            return [];
21        }
22
23        const rows = table.querySelectorAll('tbody tr[data-row_id]');
24        console.log(`Found ${rows.length} rows to process`);
25        
26        // Limit to first 50 rows
27        const maxRows = Math.min(50, rows.length);
28        console.log(`Scraping first ${maxRows} rows`);
29        
30        const websites = [];
31        
32        for (let i = 0; i < maxRows; i++) {
33            const row = rows[i];
34            
35            // Get company name
36            const companyNameCell = row.querySelector('.ninja_column_1');
37            const companyName = companyNameCell ? companyNameCell.textContent.trim() : 'Unknown';
38            
39            // Check if row is already expanded
40            const isExpanded = row.classList.contains('footable-detail-show');
41            
42            if (!isExpanded) {
43                // Click to expand the row
44                const toggleButton = row.querySelector('.footable-toggle');
45                if (toggleButton) {
46                    toggleButton.click();
47                    // Wait for the details to load
48                    await new Promise(resolve => setTimeout(resolve, 100));
49                }
50            }
51            
52            // Find the details row - it's the next sibling element
53            const detailsRow = row.nextElementSibling;
54            
55            if (detailsRow && detailsRow.classList.contains('footable-detail-row')) {
56                // Look for website link in the details
57                const websiteCell = detailsRow.querySelector('.ninja_column_8 a');
58                
59                if (websiteCell) {
60                    const websiteUrl = websiteCell.textContent.trim();
61                    const websiteHref = websiteCell.getAttribute('href');
62                    
63                    websites.push({
64                        company: companyName,
65                        website: websiteUrl,
66                        link: websiteHref
67                    });
68                    
69                    // Log progress every 10 rows
70                    if ((i + 1) % 10 === 0) {
71                        console.log(`Progress: ${i + 1}/${maxRows} rows processed, ${websites.length} websites found`);
72                    }
73                } else {
74                    // Log when no website is found
75                    if ((i + 1) % 10 === 0) {
76                        console.log(`Progress: ${i + 1}/${maxRows} rows processed, ${websites.length} websites found`);
77                    }
78                }
79            }
80            
81            // Collapse the row to keep the page clean
82            if (!isExpanded) {
83                const toggleButton = row.querySelector('.footable-toggle');
84                if (toggleButton) {
85                    toggleButton.click();
86                }
87            }
88        }
89        
90        console.log(`Scraping complete! Found ${websites.length} websites out of ${maxRows} companies`);
91        return websites;
92    }
93
94    // Function to display results in a modal
95    function displayResults(websites) {
96        // Remove existing modal if any
97        const existingModal = document.getElementById('scraper-modal');
98        if (existingModal) {
99            existingModal.remove();
100        }
101
102        // Create modal
103        const modal = document.createElement('div');
104        modal.id = 'scraper-modal';
105        modal.style.cssText = `
106            position: fixed;
107            top: 50%;
108            left: 50%;
109            transform: translate(-50%, -50%);
110            background: white;
111            color: black;
112            padding: 30px;
113            border-radius: 10px;
114            box-shadow: 0 4px 20px rgba(0,0,0,0.3);
115            z-index: 10000;
116            max-width: 800px;
117            max-height: 80vh;
118            overflow-y: auto;
119            width: 90%;
120        `;
121
122        // Create content
123        let content = `
124            <h2 style="margin-top: 0; color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px;">
125                Scraped Websites (${websites.length} found)
126            </h2>
127            <div style="margin: 20px 0;">
128        `;
129
130        if (websites.length > 0) {
131            content += '<ul style="list-style: none; padding: 0;">';
132            websites.forEach((item, index) => {
133                content += `
134                    <li style="margin: 10px 0; padding: 10px; background: #f8f9fa; border-left: 3px solid #007bff; border-radius: 3px;">
135                        <strong style="color: #333;">${index + 1}. ${item.company}</strong><br>
136                        <a href="${item.link}" target="_blank" style="color: #007bff; text-decoration: none; word-break: break-all;">
137                            ${item.website}
138                        </a>
139                    </li>
140                `;
141            });
142            content += '</ul>';
143        } else {
144            content += '<p style="color: #666;">No websites found in the table.</p>';
145        }
146
147        content += '</div>';
148
149        // Add buttons
150        content += `
151            <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px;">
152                <button id="copy-websites-btn" style="
153                    background: #28a745;
154                    color: white;
155                    border: none;
156                    padding: 10px 20px;
157                    border-radius: 5px;
158                    cursor: pointer;
159                    font-size: 14px;
160                    font-weight: bold;
161                ">Copy All URLs</button>
162                <button id="download-csv-btn" style="
163                    background: #17a2b8;
164                    color: white;
165                    border: none;
166                    padding: 10px 20px;
167                    border-radius: 5px;
168                    cursor: pointer;
169                    font-size: 14px;
170                    font-weight: bold;
171                ">Download CSV</button>
172                <button id="close-modal-btn" style="
173                    background: #dc3545;
174                    color: white;
175                    border: none;
176                    padding: 10px 20px;
177                    border-radius: 5px;
178                    cursor: pointer;
179                    font-size: 14px;
180                    font-weight: bold;
181                ">Close</button>
182            </div>
183        `;
184
185        modal.innerHTML = content;
186
187        // Create overlay
188        const overlay = document.createElement('div');
189        overlay.id = 'scraper-overlay';
190        overlay.style.cssText = `
191            position: fixed;
192            top: 0;
193            left: 0;
194            width: 100%;
195            height: 100%;
196            background: rgba(0,0,0,0.5);
197            z-index: 9999;
198        `;
199
200        document.body.appendChild(overlay);
201        document.body.appendChild(modal);
202
203        // Add event listeners
204        document.getElementById('close-modal-btn').addEventListener('click', () => {
205            modal.remove();
206            overlay.remove();
207        });
208
209        document.getElementById('copy-websites-btn').addEventListener('click', async () => {
210            const urlList = websites.map(item => item.website).join('\n');
211            try {
212                await GM.setClipboard(urlList);
213                alert('All website URLs copied to clipboard!');
214            } catch (error) {
215                console.error('Failed to copy to clipboard:', error);
216                // Fallback to textarea method
217                const textarea = document.createElement('textarea');
218                textarea.value = urlList;
219                document.body.appendChild(textarea);
220                textarea.select();
221                document.execCommand('copy');
222                document.body.removeChild(textarea);
223                alert('All website URLs copied to clipboard!');
224            }
225        });
226
227        document.getElementById('download-csv-btn').addEventListener('click', () => {
228            let csv = 'Company Name,Website URL,Link\n';
229            websites.forEach(item => {
230                csv += `"${item.company}","${item.website}","${item.link}"\n`;
231            });
232
233            const blob = new Blob([csv], { type: 'text/csv' });
234            const url = URL.createObjectURL(blob);
235            const a = document.createElement('a');
236            a.href = url;
237            a.download = 'saudi-pp-websites.csv';
238            document.body.appendChild(a);
239            a.click();
240            document.body.removeChild(a);
241            URL.revokeObjectURL(url);
242        });
243
244        overlay.addEventListener('click', () => {
245            modal.remove();
246            overlay.remove();
247        });
248    }
249
250    // Function to create and add the scrape button
251    function addScrapeButton() {
252        // Check if button already exists
253        if (document.getElementById('scrape-websites-btn')) {
254            return;
255        }
256
257        // Find the table wrapper
258        const tableWrapper = document.querySelector('#footable_parent_23093');
259        if (!tableWrapper) {
260            console.log('Table wrapper not found, will retry...');
261            return;
262        }
263
264        // Create button container
265        const buttonContainer = document.createElement('div');
266        buttonContainer.style.cssText = `
267            margin: 20px 0;
268            text-align: right;
269        `;
270
271        // Create scrape button
272        const scrapeButton = document.createElement('button');
273        scrapeButton.id = 'scrape-websites-btn';
274        scrapeButton.textContent = '🌐 Scrape All Websites';
275        scrapeButton.style.cssText = `
276            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
277            color: white;
278            border: none;
279            padding: 12px 24px;
280            border-radius: 8px;
281            cursor: pointer;
282            font-size: 16px;
283            font-weight: bold;
284            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
285            transition: all 0.3s ease;
286        `;
287
288        scrapeButton.addEventListener('mouseenter', () => {
289            scrapeButton.style.transform = 'translateY(-2px)';
290            scrapeButton.style.boxShadow = '0 6px 12px rgba(0,0,0,0.15)';
291        });
292
293        scrapeButton.addEventListener('mouseleave', () => {
294            scrapeButton.style.transform = 'translateY(0)';
295            scrapeButton.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
296        });
297
298        scrapeButton.addEventListener('click', async () => {
299            scrapeButton.disabled = true;
300            scrapeButton.textContent = '⏳ Scraping...';
301            
302            try {
303                const websites = await scrapeWebsites();
304                displayResults(websites);
305            } catch (error) {
306                console.error('Error during scraping:', error);
307                alert('An error occurred while scraping. Check the console for details.');
308            } finally {
309                scrapeButton.disabled = false;
310                scrapeButton.textContent = '🌐 Scrape All Websites';
311            }
312        });
313
314        buttonContainer.appendChild(scrapeButton);
315        tableWrapper.parentNode.insertBefore(buttonContainer, tableWrapper);
316        
317        console.log('Scrape button added successfully');
318    }
319
320    // Initialize the extension
321    function init() {
322        console.log('Initializing Saudi Print & Pack Website Scraper...');
323        
324        // Wait for the table to be loaded
325        const checkTable = setInterval(() => {
326            const table = document.querySelector('table[data-footable_id="23093"]');
327            if (table) {
328                clearInterval(checkTable);
329                console.log('Table found, adding scrape button...');
330                addScrapeButton();
331            }
332        }, 1000);
333
334        // Stop checking after 30 seconds
335        setTimeout(() => {
336            clearInterval(checkTable);
337        }, 30000);
338    }
339
340    // Run when DOM is ready
341    if (document.readyState === 'loading') {
342        document.addEventListener('DOMContentLoaded', init);
343    } else {
344        init();
345    }
346
347})();
Saudi Print & Pack Website Scraper | Robomonkey