1 min read
AutomatisierungBrowser Extensions für Automation & Productivity
Browser Extensions entwickeln für Automation. Manifest V3, Content Scripts, Background Workers und Cross-Browser Kompatibilität.
Browser ExtensionChrome ExtensionManifest V3Content ScriptAutomationWeb Extension API

Browser Extensions für Automation & Productivity
Meta-Description: Browser Extensions entwickeln für Automation. Manifest V3, Content Scripts, Background Workers und Cross-Browser Kompatibilität.
Keywords: Browser Extension, Chrome Extension, Manifest V3, Content Script, Automation, Web Extension API
Einführung
Browser Extensions erweitern die Browser-Funktionalität direkt. Mit Manifest V3 und der WebExtensions API können Sie Workflows automatisieren, Daten extrahieren und Produktivität steigern.
Extension Architecture
┌─────────────────────────────────────────────────────────────┐
│ BROWSER EXTENSION ARCHITECTURE │
├─────────────────────────────────────────────────────────────┤
│ │
│ Components: │
│ ├── Manifest (manifest.json) │
│ │ └── Extension Metadata & Permissions │
│ │ │
│ ├── Service Worker (Background) │
│ │ └── Event Handling, API Calls, State │
│ │ │
│ ├── Content Scripts │
│ │ └── DOM Manipulation auf Web Pages │
│ │ │
│ ├── Popup (UI) │
│ │ └── Toolbar Button Interface │
│ │ │
│ └── Options Page │
│ └── Extension Settings │
│ │
│ Communication: │
│ Content Script ←→ Service Worker ←→ Popup │
│ (chrome.runtime.sendMessage / onMessage) │
│ │
└─────────────────────────────────────────────────────────────┘Manifest V3 Setup
// manifest.json
{
"manifest_version": 3,
"name": "Automation Helper",
"version": "1.0.0",
"description": "Automate repetitive browser tasks",
"permissions": [
"activeTab",
"storage",
"alarms",
"contextMenus"
],
"host_permissions": [
"https://*.example.com/*"
],
"background": {
"service_worker": "background.js",
"type": "module"
},
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"js": ["content.js"],
"css": ["content.css"],
"run_at": "document_idle"
}
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"options_page": "options.html",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}Service Worker (Background)
// background.ts
chrome.runtime.onInstalled.addListener(() => {
console.log('Extension installed');
// Context Menu erstellen
chrome.contextMenus.create({
id: 'extract-data',
title: 'Daten extrahieren',
contexts: ['selection']
});
// Default Settings
chrome.storage.sync.set({
autoExtract: true,
extractInterval: 5
});
});
// Context Menu Handler
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === 'extract-data' && info.selectionText) {
processSelectedText(info.selectionText);
}
});
// Message Handler
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'EXTRACT_PAGE') {
handleExtraction(message.data)
.then(result => sendResponse({ success: true, data: result }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // Async Response
}
if (message.type === 'GET_SETTINGS') {
chrome.storage.sync.get(['autoExtract', 'extractInterval'], (settings) => {
sendResponse(settings);
});
return true;
}
});
// Alarm für wiederkehrende Tasks
chrome.alarms.create('sync-data', { periodInMinutes: 5 });
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'sync-data') {
syncDataToServer();
}
});
async function handleExtraction(data: any) {
// API Call oder Datenverarbeitung
const response = await fetch('https://api.example.com/extract', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return response.json();
}
async function syncDataToServer() {
const { extractedData } = await chrome.storage.local.get('extractedData');
if (extractedData && extractedData.length > 0) {
await fetch('https://api.example.com/sync', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(extractedData)
});
// Clear nach Sync
await chrome.storage.local.set({ extractedData: [] });
}
}Content Script
// content.ts
// DOM Ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
function init() {
console.log('Content script loaded on', window.location.href);
// UI Element einfügen
injectUI();
// Page Observer für dynamische Inhalte
observePageChanges();
// Auto-Extract wenn aktiviert
chrome.storage.sync.get('autoExtract', ({ autoExtract }) => {
if (autoExtract) {
extractPageData();
}
});
}
function injectUI() {
const container = document.createElement('div');
container.id = 'extension-helper';
container.innerHTML = `
<button id="ext-extract-btn" class="ext-btn">
Daten extrahieren
</button>
`;
document.body.appendChild(container);
document.getElementById('ext-extract-btn')?.addEventListener('click', () => {
extractPageData();
});
}
async function extractPageData() {
const data = {
url: window.location.href,
title: document.title,
timestamp: new Date().toISOString(),
content: extractContent()
};
// An Background Script senden
const response = await chrome.runtime.sendMessage({
type: 'EXTRACT_PAGE',
data
});
if (response.success) {
showNotification('Daten erfolgreich extrahiert!');
} else {
showNotification('Fehler: ' + response.error, 'error');
}
}
function extractContent() {
// Beispiel: Produkt-Daten extrahieren
const products: any[] = [];
document.querySelectorAll('.product-item').forEach((el) => {
products.push({
name: el.querySelector('.product-name')?.textContent?.trim(),
price: el.querySelector('.price')?.textContent?.trim(),
image: el.querySelector('img')?.getAttribute('src')
});
});
return products;
}
function observePageChanges() {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length > 0) {
// Neue Elemente verarbeiten
handleNewElements(mutation.addedNodes);
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
function handleNewElements(nodes: NodeList) {
nodes.forEach((node) => {
if (node instanceof HTMLElement) {
// Highlight neue Produkte
const products = node.querySelectorAll('.product-item');
products.forEach((product) => {
product.classList.add('ext-highlighted');
});
}
});
}
function showNotification(message: string, type: 'success' | 'error' = 'success') {
const notification = document.createElement('div');
notification.className = `ext-notification ext-${type}`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
}Popup UI
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="popup-container">
<h1>Automation Helper</h1>
<div class="status">
<span id="status-indicator" class="indicator"></span>
<span id="status-text">Bereit</span>
</div>
<div class="actions">
<button id="extract-btn" class="btn primary">
Aktuelle Seite extrahieren
</button>
<button id="batch-extract-btn" class="btn secondary">
Batch-Extraktion
</button>
</div>
<div class="stats">
<div class="stat">
<span class="stat-value" id="extracted-count">0</span>
<span class="stat-label">Extrahiert</span>
</div>
<div class="stat">
<span class="stat-value" id="synced-count">0</span>
<span class="stat-label">Synchronisiert</span>
</div>
</div>
<a href="options.html" target="_blank" class="settings-link">
Einstellungen
</a>
</div>
<script src="popup.js" type="module"></script>
</body>
</html>// popup.ts
document.addEventListener('DOMContentLoaded', async () => {
// Stats laden
await updateStats();
// Event Listeners
document.getElementById('extract-btn')?.addEventListener('click', extractCurrent);
document.getElementById('batch-extract-btn')?.addEventListener('click', batchExtract);
});
async function updateStats() {
const { extractedCount = 0, syncedCount = 0 } = await chrome.storage.local.get([
'extractedCount',
'syncedCount'
]);
document.getElementById('extracted-count')!.textContent = extractedCount.toString();
document.getElementById('synced-count')!.textContent = syncedCount.toString();
}
async function extractCurrent() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab.id) return;
// Message an Content Script
const response = await chrome.tabs.sendMessage(tab.id, { type: 'EXTRACT' });
if (response.success) {
setStatus('success', 'Extrahiert!');
await updateStats();
} else {
setStatus('error', 'Fehler');
}
}
async function batchExtract() {
const tabs = await chrome.tabs.query({ url: 'https://*.example.com/*' });
setStatus('loading', `Extrahiere ${tabs.length} Tabs...`);
for (const tab of tabs) {
if (tab.id) {
await chrome.tabs.sendMessage(tab.id, { type: 'EXTRACT' });
}
}
setStatus('success', `${tabs.length} Seiten extrahiert`);
await updateStats();
}
function setStatus(type: 'success' | 'error' | 'loading', text: string) {
const indicator = document.getElementById('status-indicator')!;
const statusText = document.getElementById('status-text')!;
indicator.className = `indicator ${type}`;
statusText.textContent = text;
}Storage API
// Sync Storage (zwischen Geräten synchronisiert, 100KB Limit)
await chrome.storage.sync.set({
settings: {
autoExtract: true,
theme: 'dark'
}
});
const { settings } = await chrome.storage.sync.get('settings');
// Local Storage (nur lokal, 5MB Limit)
await chrome.storage.local.set({
extractedData: largeDataArray
});
// Storage Change Listener
chrome.storage.onChanged.addListener((changes, areaName) => {
for (const [key, { oldValue, newValue }] of Object.entries(changes)) {
console.log(`${areaName}.${key} changed from`, oldValue, 'to', newValue);
}
});Cross-Browser Kompatibilität
// Browser Detection
const isChrome = typeof chrome !== 'undefined' && chrome.runtime;
const isFirefox = typeof browser !== 'undefined';
// Unified API
const browserAPI = isFirefox ? browser : chrome;
// Polyfill für Firefox Promise-based API
function promisify<T>(chromeMethod: (...args: any[]) => void): (...args: any[]) => Promise<T> {
return (...args) => new Promise((resolve, reject) => {
chromeMethod(...args, (result: T) => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else {
resolve(result);
}
});
});
}
// webextension-polyfill verwenden
import browser from 'webextension-polyfill';
// Unified API für alle Browser
const tabs = await browser.tabs.query({ active: true });Fazit
Browser Extensions bieten:
- Tiefe Integration: Direkter DOM-Zugriff
- Automation: Wiederkehrende Tasks automatisieren
- Produktivität: Workflows optimieren
- Cross-Platform: Chrome, Firefox, Edge
Mächtige Tools für Power-User und Entwickler.
Bildprompts
- "Browser with extension icon showing automation, productivity concept"
- "Extension popup interacting with webpage, data extraction"
- "Multiple browser windows synchronized, cross-browser extension"