# Alle Werte eines Dropdown-Menüs im Quelltext anzeigen lassen



## loddarmattheus (24. Oktober 2019)

Hallo zusammen,
angenommen, ich möchte von (m)einer Webseite alle Werte eines Menus anzeigen lassen - geht das?
Hier mal ein Beispiel. Wenn ich auf Typnummer klicke, werden mir alle Ergebnisse angezeigt. Klicke ich beispieltsweise auf das erste Ergebnis (AE120), wird mir im Quelltext auch nur dieser Wert angezeigt.




Geht es irgendwie, dass ich alle Ergebnisse auf einmal auslesen kann und nicht nur einzeln?


----------



## StormChaser (24. Oktober 2019)

Wenn es so ist, wie du beschreibst, werden die Daten erst geladen, nachdem du einen Typ ausgewählt hast. Alle Daten sind also garnicht vorhanden, um sie auszulesen.


----------



## Yaslaw (25. Oktober 2019)

Schwer zu sagen ob das geht. Kommt auf den Code und die Art an, wie und wann du die Daten ausliest.


----------



## loddarmattheus (29. Dezember 2019)

Hallo nochmal,

ich möchte mein Problem mal etwas plakativer darstellen. Es handelt sich um die URL: Swirl - Staubsaugerbeutel-Finder | Staubsaugen mit Swirl

Im Opera werden mir die Werte aus dem rechten Dropdown nach Klick auf "Element untersuchen" ja alle im rechten Fenster angezeigt (Siehe roter Kasten).
Nur bekomme ich diese Werte nicht weiterverarbeitet, denn ich kann maximal eine Zeile davon kopieren und nicht alle zusammen. 

Vielleicht hat ja jemand eine Idee?


----------



## ComFreek (29. Dezember 2019)

Möchtest du einmal alle Werte statisch per Hand kopieren oder möchtest du, dass deine Website immer die aktuellsten Werte live hernimmt?


----------



## basti1012 (30. Dezember 2019)

loddarmattheus hat gesagt.:


> Im Opera werden mir die Werte aus dem rechten Dropdown nach Klick auf "Element untersuchen" ja alle im rechten Fenster angezeigt (Siehe roter Kasten).
> Nur bekomme ich diese Werte nicht weiterverarbeitet, denn ich kann maximal eine Zeile davon kopieren und nicht alle zusammen.


Du meinst jetzt da aus der Konsole rauskopiern?
Mach mal rechts klick auf das <select und klicke dann auf Copy  => Copy outerHTML.
Dann hast du den ganzen Quellcode von den <select Menü inclusive alle <option>


----------



## loddarmattheus (30. Dezember 2019)

Guten Morgen,
ich möchte ALLE Werte aus dem roten Kasten einfach rauskopieren, damit ich sie in Excel beispielsweise weiterverarbeiten kann.

Dass mit dem Rechtsklick auf einen Eintrag und Kopieren->Copy outer HTML funktioniert leider nicht, da ich dann immer nur eine Zeile erhalte, z.B. <option value="27154_268_S" data-searchdata=" ">DIV 380</option>

Ich müsste nur alle diese Zeilen irgendwie gleichzeitig markieren können, aber in der Konsole geht nur immer eine Zeile


----------



## ComFreek (30. Dezember 2019)

Du musst "copy outer HTML" natürlich auf dem <select> ausführen 

Anyway, ich habe mal die Gunst der Stunde genutzt, selbst ein bisschen wieder meine JS Promise-Skills auf Vordermann zu bringen und habe dir ein Skript geschrieben, das *alles* extrahiert.

Alle extrahierten Marken und zugehörigen Modelle findest du im Anhang als ZIP-komprimierte JSON-Datei. Das JSON ist ein großes Dictionary, wobei die Keys Marken sind und die Values Arrays von zugehörigen Modellen. Daraus solltest du sehr einfach mit JS oder einer anderen Sprache deiner Wahl ein Format aufbereiten können, das Excel versteht.


```
// Usage
// ============
// 1. Using Chrome go to https://www.swirl.de/de/Staubsaugerbeutel-Finder-Staubsaugen-mit-Swirl-648.html
// 2. Open dev console
// 3. Copy-paste and run this script in the console
// 4. Save returned JS object using JSON.stringify in the console (e.g. first call JSON.stringify, then manually copy the string to a file)

// I am sorry for mixing English and German, but I believed retaining "marke" and "modell"
// has some advantages since they directly correspond to the things on the website we scrape.

function getOptions(selectId, skip = 0) {
    return Array.from(document.getElementById(selectId).options).slice(skip)
}

function* extractAllModelle(htmlResponseText) {
    const extractingRegex = /<option[^>]*? value="(?<value>.*?)"[^>]*?>(?<innerText>[^<]*?)<\/option>/gmi;
    let match = null;
  
    let alreadySkippedFirst = false;
  
    while (match = extractingRegex.exec(htmlResponseText)) {
        // First match contains <select> "header" text
        if (!alreadySkippedFirst) {
            alreadySkippedFirst = true;
            continue;
        }
        yield match.groups;
    }
}

function getModelleForMarke(marke) {
    const url = `https://www.swirl.de/common/ajax.php?bereich=portal&modul_id=102&klasse=staubfilterbeutelsuche&com=laden_typen`;
  
    // fetch call extracted via Chrome dev tools from site by performing actual UI action on site and waiting
    // for the original request, which we're going to imitate, to fire
    return fetch(
        'https://www.swirl.de/common/ajax.php?bereich=portal&modul_id=102&klasse=staubfilterbeutelsuche&com=laden_typen', {
            'headers': {
                'accept': '*/*',
                'accept-language': 'en,de;q=0.9,en-US;q=0.8',
                'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
                'sec-fetch-dest': 'empty',
                'sec-fetch-mode': 'cors',
                'sec-fetch-site': 'same-origin',
                'x-requested-with': 'XMLHttpRequest'
            },
            'referrer': 'https://www.swirl.de/de/Staubsaugerbeutel-Finder-Staubsaugen-mit-Swirl-648.html',
            'referrerPolicy': 'no-referrer-when-downgrade',
            'body': `marke=${marke}&sprache=de&texte=staubfilterbeutelsuche%2Ftexte_modul_staubfilterbeutelsuche`,
            'method': 'POST',
            'mode': 'cors',
            'credentials': 'include'
        }
    ).then(response => response.text()).then(html => [...extractAllModelle(html)]);
}

function getModelleForMultipleMarken(marken) {
    const allModelle = marken.map(async function(marke) {
        return {marke, modelle: await getModelleForMarke(marke)};
    });
    return Promise.all(allModelle).then(arrayOfMarken => // Build a dictionary again
        arrayOfMarken.reduce((dict, {marke, modelle}) => {
            dict[marke] = modelle;
            return dict;
        }, {})
    );
}

function* batchIterable(iterable, batchSize) {
    let curBatch = [];

    for (const value of iterable) {
        if (curBatch.length == batchSize) {
            yield curBatch;
            curBatch = [];
        }
      
        curBatch.push(value);
    }
    if (curBatch.length >= 1) {
        yield curBatch;
    }
}

/**
    * promisingReduce<S, T>
    *
  * @param array An array of Promise<T>
    * @param f A function (acc: S, cur: T) => S
    * @param defaultvalue An S
    *
    * @return A Promise<S>
    */
async function promisingReduce(array, f, defaultValue) {
    let acc = defaultValue;
    for (const item of array) {
        acc = f(acc, await item);
    }
    return acc;
}

function batchProcess(array, f, combine, combineDefault) {
    const batchSize = 50;
    const batches = [...batchIterable(array, batchSize)];
    return promisingReduce(batches.map(f), combine, combineDefault);
}

const marken = getOptions('sfbs-select-seite-marken', 1).map(option => parseInt(option.value, 10));
console.log(`Gathered ${marken.length} number of marken`);

function mergeDict(dict1, dict2) {
    return Object.assign({}, dict1, dict2);
}

batchProcess(marken, getModelleForMultipleMarken, mergeDict, {})
```


----------



## basti1012 (30. Dezember 2019)

loddarmattheus hat gesagt.:


> Dass mit dem Rechtsklick auf einen Eintrag und Kopieren->Copy outer HTML funktioniert leider nicht, da ich dann immer nur eine Zeile erhalte, z.B. <option value="27154_268_S" data-searchdata=" ">DIV 380</option>


@ComFreek  hat es ja auch schon gesagt, du mußt in diesen fall das parent  Element nehmen und den Rechtsklick auf den <select> machen und da Copy outerHTML
Dann hast du den ganzen Quelltext von
<select>
<option>...</option>
....
...
</select>
bis hier hin.
Du hast ja auch gerade nee Liste bekommen wo alles drinne steht,dann weißt du es beim nächsten mal  das du bei sowas das Elternelement nehmen mußt für den Rechtsklick Copy


----------



## loddarmattheus (30. Dezember 2019)

Hallo, 
vielen Dank - das ist ja der Hammer. Die json kann ich schön in meine MySQL importieren. Klasse.
VG Loddar


----------

