xff.cz - mapa webu - novinky

Extrakce informací z webových stránek

Zde najdete základní informace a techniky, které budete potřebovat pro extrakci informací z webu. Při programování nikdy nepotřebujete znát vše, stačí základní přehled a vědět, kde je možné si dohledat podrobné informace. Pokud začínáte, doporučuji začít s ukázkovým kódem a adaptovat si ho na vámi řešený problém. Ukázkový kód bude v JavaScriptu pro GUI framework Electron. Oproti jiným možnostem, si můžete Electron snadno nainstalovat na Windows, MacOS, či Linuxu a využít ho jak k získávání tak i k libovolné prezentaci dat z webu bez omezení. Propojení s RDBMS je též možné. Znalosti také budete moci využít při psaní userscriptů, či rozšíření pro prohlížeče.

Extrakce informací z webu se skládá ze dvou fází: stažení stránky a její zpracování.

Ukázkový kód bude motivovaný získáním nejnovějšího obrázku na plochu z https://wallpaperscraft.com/ a jeho zobrazením.

Příprava Electron aplikace

Pro index.js:

const electron = require('electron');
const {app, BrowserWindow} = electron;

let USE_TOR = false;
let win;

function createWindow() {
        win = new BrowserWindow({
                width: 1024,
                height: 768,
                webPreferences: {
                        webSecurity: false
                }
        });

        // Po ladění zakomentujte následující řádek (aby se po startu neotevírala konzole)
        win.openDevTools();
        win.setMenu(null);
        win.on('closed', () => {
                win = null;
        });

        win.webContents.session.setUserAgent('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36', 'en');

        if (USE_TOR) {
                win.webContents.session.setProxy({
                        proxyRules: 'socks5://localhost:9050',
                        proxyBypassRules: '<local>'
                }, function() {
                        win.loadURL(`file://${__dirname}/content.html`);
                });
        } else {
                win.loadURL(`file://${__dirname}/content.html`);
        }
}

app.disableHardwareAcceleration();
app.setPath('userData', `${__dirname}/data`);

app.on('ready', createWindow);

app.on('window-all-closed', () => {
        if (process.platform !== 'darwin') {
                app.quit();
        }
});

app.on('activate', () => {
        if (!win) {
                createWindow();
        }
});

Pro lib.js:

function GET(url, type) {
        return new Promise(function(resolve, reject) {
                if (!url || !url.match(/^https?:/)) {
                        reject();
                        return;
                }

                url = url.replace(/#.*$/, '');
                type = type || 'document';

                console.log('GET ' + url);

                let r = new XMLHttpRequest();
                r.open('GET', url);
                r.overrideMimeType('text/html');
                r.responseType = type;

                Object.assign(r, {
                        timeout: 30000,

                        onload() {
                                if (r.status >= 200 && r.status < 300) {
                                        if (type == 'text') {
                                                resolve(r.responseText);
                                        } else {
                                                resolve(r.response);
                                        }
                                } else {
                                        reject(r);
                                }
                        },

                        onerror() {
                                reject(r);
                        },

                        onabort(ev) {
                                reject(r);
                        },

                        ontimeout(ev) {
                                reject(r);
                        }
                });

                r.send();
        });
}

function onReady(cb) {
        document.addEventListener('DOMContentLoaded', cb);
}

// zde budete doplňovat užitečné funkce, které využijete ve více aplikacích

Pro content.js:

// zde bude váš kód pro konkrétní aplikaci

Pro content.html:

<!DOCTYPE html>
<meta charset=utf-8>
<script src="lib.js"></script>
<script src="content.js"></script>
<title>Scraper</title>

Jde o nutný minimální základ aplikace, který otevře okno a v rámci okna spustí kód obsažený v content.js. Do tohoto souboru budete psát váš kód, který bude implementovat stahování a zpracování stránek. Zbytek kódu již zůstane beze změny.

Stažení stránky

Webová stránka je HTML dokument – tedy strukturovaný text, který si stáhnete z webového serveru přes protokol HTTP. Místo odkud se může dokument stáhnout přes HTTP se popisuje pomocí URL adresy. URL adresa určuje jak adresu počítače (web serveru), kde je dokument k dispozici, tak identifikátor (cestu k dokumentu) pomocí kterého web server rozhodne jaký dokument vrátit.

Vše tedy začíná URL adresou. URL adresa poskytuje informace pro dva účely, část je určená pro váš počítač a říká jak najít vzdálený počítač. Druhá část je určená pro vzdálený počítač a říká jak najít požadovaný dokument či zdroj. Webový server může poskytovat i jiné zdroje informací než HTML dokumenty. Jsou jimi především obrázky, videa, audio, CSS styly, skripty určené pro spuštění ve vašem prohlížeči a data určená pro strojové zpracování ve formátech JSON či XML.

URL adresu lze získat z adresního rádku webového prohlížeče. Nejprve najděte stránku, ze které budete informace získávat a pak si adresu zkopírujte. V našem případě to bude: https://wallpaperscraft.com/. Adresa serveru je wallpaperscraft.com, cesta ke stránce je /.

Do content.js vložte následující kód a spusťte vaši Electron aplikaci. Aplikace se spouští např. přetažením složky, kterou jste vytvořili pro soubory vaší aplikace, do okna Electron.

onReady(async ev => {
        let doc = await GET('https://wallpaperscraft.com/');

        console.log(doc);
});

GET je pomocná funkce, která očekává URL HTML dokumentu jako svůj první argument a vrací objekt typu Document (DOM stránky), který si uložíme do proměnné doc.

To je vše co potřebujete udělat, aby jste stáhli HTML stránku z libovolné URL adresy. Pokud jste udělali všechno správně, měli by jste vidět následující výstup:

Výstup 1

To znamená, že stránka byla úspěšně stažena a byla z ní připravena objektová reprezentace jejího obsahu, se kterou můžeme dále pracovat.

Zpracování stránky

Většina dynamicky generovaných webových stránek má nějakou fixní strukturu do které server doplňuje různý obsah z databáze. Toho využijeme, chceme totiž získat URL adresu prvního obrázku v seznamu:

Stránka seznamu

V tento moment máme k dispozici objektovou reprezentaci celé stránky. Obsah stránky je modelovaný jako stromová struktura elementů a textového obsahu. Každý element může mít nějaké atributy a obsah sestávající ze směsice dalších elementů a textu. Kliknete-li na šipku u slova #document v záložce Console, můžete si interkativně prohlédnout celou strukturu vámi stažené stránky a najít v ní místo, kde je informace, která nás zajímá.

Výstup 2

Tato stránka má hezky označené jednotlivé elementy, ze kterých se skládá, pomocí tříd (atribut class). Odkaz na stránku s tapetou je v atributu href elementu a, který je v elementu div s třídou pre_size, který je v elementu div s třídou pre_info a tak se dá pokračovat až se dostaneme k elementu html.

Nyní, když už víme co hledáme a kde to je, tak už jen musíme najít způsob jak se k té infomraci dostat programově. Pomůže nám funkce querySelector, která je dostupná na objektu Document. Tato funkce vrací první element, který odpovídá námi zadanému CSS selektoru.

Vyzkoušejte si následující kód:

onReady(async ev => {
        let doc = await GET('https://wallpaperscraft.com/');
        let el = doc.querySelector('.center .wallpapers .pre_size a');

        console.log(el);
});

Po jeho spuštění by jste měli získat výstup podobný tomuto:

Výstup 3

Jak je vidět, v proměné el nyní máme element odkazu na stránku s velkým obrázkem tapety.

Pokud předchozí postup aplikujete i na stránku schovávající se za el.href, můžete dospět např. k následují­címu kódu.

onReady(async ev => {
    let doc = await GET('https://wallpaperscraft.com/');
    let el = doc.querySelector('.center .wallpapers .pre_size a');
    let detail = await GET(el.href);
    let img = detail.querySelector('.center_wb .wb_preview .wd_zoom img');

    console.log(img.src);

    // Vytvoří element <img> v okně naší aplikace a použije pro něj nalezenou
    // adresu obrázku tapety:
    let myImg = document.body.appendChild(document.createElement('img'));
    myImg.src = img.src;
    myImg.style.width = '100%';
});

Výsledek je, že dokážeme získat poslední tapetu, tak jak jsme si dali zadání na začátku:

Výstup 4

A takto v principu funguje extrakce infomrací z webových stránek. Některé stránky mají složitější strukturu, nebo strukturu, která není tak dobře anotovaná pomocí tříd, ale většinou se lze programově dobrat informací, které nás zajímají.

Historie změn

15.7.2018 18:17První sestavení webu