Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    Rilevare duplicati o pseudo-duplicati tra pagine web con url differente

    Salve a tutti. (è il mio primo messaggio)

    La mia richiesta d'aiuto è un po' oscura se non si premette una piccola introduzione.
    Sto cominciando la progettazione di un social network relativo ai contenuti per adulti. Essendo allievo ingegnere informatico naturalmente non sono all'asciutto di programmazione (programmazione ad oggetti, Java, C++, piccoli sistemi di controllo per robot, conoscenze "libresche" di SQL e basi di dati) ma riguardo lo sviluppo web conosco poco. Comunque sono abituato a leggere documentazione e studiare mi interessa.

    Per il mio progetto so che avrò bisogno di PHP, un DBMS e semplice design CSS. Tutti argomenti su quali qui ci sono un sacco di articoli e guide. Per questo motivo comincio un po' "al contrario": rilevo le problematiche che mi sembrano più spinose e vedo un po' se è roba che sono capace di risolvere. Diciamo che siamo in una fase di studio di fattibilità.

    Veniamo al problema tecnico.
    Nel nostro scenario abbiamo degli URL sottomessi dagli utenti e aggiunti ad un db. In fase di inserimento si fa in primo luogo una verifica degli url duplicati, più o meno raffinata. Tuttavia è possibile, anzi probabile, che avvengano inserimenti di URL "sporcati" variamente da querystring, codici referrer etc, che si riferiscono a pagine già presenti.
    L'inghippo sta nel fatto che non è possibile sapere a priori quali parametri siano rilevanti per il contenuto e quali altri inutili, perché l'uso che i vari (tantissimi) siti possono fare della querystring è il più disparato.
    Per questo motivo ho puntato ad interpretare il contenuto. Uno script prende l'url e si scarica la pagina: a quel punto estrae il contenuto di body e lo ripulisce da tutti i tag (tranne il tag img*). Sul risultato si applica una funzione hash e si salva il digest. Per rilevare i duplicati verrà fatto un confronto tra i digest.

    Il metodo vi sembra buono? Qual è l'algoritmo di hash più adatto? :master:
    Lo script dovrebbe essere di basso uso, quindi non dovrebbe essere critico per le prestazioni.

    *Faccio notare che senza ripulire il codice della pagina dai tag non si riesce a rilevare duplicati. Le differenze in genere sono presenti in parametri di script contenuti nell'header, nonché in svariati collegamenti che propagano il referrer. Ripulire tutto tranne le immagini mi è sembrato un buon compromesso: il falso positivo è abbastanza remoto, il falso negativo è tollerabile (ci sono pure gli utenti).
    Ma naturalmente anche su questo punto sono ben accetti i suggerimenti.

    EDIT

    Dimenticavo di dire che con questo metodo ho già fatto dei file di test php funzionanti. Ma non fanno niente più di ciò che ho spiegato...

  2. #2
    Mi sono trovato in un problema analogo: avevo URL tutti di uno stesso sito e dovevo ragruppare li uguali. Ho risolto con un sistema a mappe: prendo gli URL, separe le Query, ordino le query, riallaccio Query e URL, riverifico congruenza, prendo gli URL, li confronto uno ad uno, verifico la similitudine percentuale, li collego ad una mappa per similitudine.
    A questo punto è l'utente finale che deve impostare la vera somiglianza.

    Per il tuo problema devi fare una cosa un po diversa:
    [list=1][*]Caricare ogni pagina in una variabile PHP file_get_contents() [*]Rimuovere tutti i tag strip_tags() [*]Confrontare tutte le variabili embro a membro e una ad una per trovare la somiglianza percentuale con quelle già nel DB similar-text() [/list=1]

    Per il confronto con silar-text, la parte più difficile, ti propongo la mia soluzione (lascia perdere il contesto che è completamente diverso)
    Codice PHP:
    function like($url) {
    global 
    $settings;
        
    $url model_url($url);            # model_url() ordina i parametri dell'url dopo il ? ed elimina cose come 'http' e 'www'
        
    $url2 model_url($urlfalse); # model_url() non ordina dopo il ? 
        
        
    $sql query("SELECT id FROM " PREFIX "map WHERE address = '" $url "' LIMIT 1");
        if(
    rows($sql) == 1) { $sql assoc($sql); return $sql['id']; } //No problems, subito trovato...
            
        
    $url_array explode('?'$url); //Separo stringa e URL

        //Eseguo prima interrogazione: cerco pagine mappa che cotengono interrogazioni    
        
    $sql query("SELECT id, address FROM " PREFIX "map WHERE address LIKE '" $url_array[0] . "%'");
            if(
    rows($sql) != 0)
            {
                
    /* Questa parte � abbastanza astrusa: lo scopo � trovare la maggiore corrispondenza possibile fra due URL per
                maggior numero di parametri; ovvero, ad esempio, localhost/page.php?a=1&b=2 � simile a localhost/page.php?a=1.
                    1. Faccio un ciclo con tutti i possiili valori che assomigliano
                    2. Separo Query e URL (imposto sempre come chiave array l'id per $sql)
                    3. Il valore ottenuto entra in un ciclo dove separo tutti i parametri della query
                    4. Se un valore non viene trovato, passo al valore di $sql successivo
                    5. Se sono stati trovati e mi trovo all'ultimo valore possibile; imposto questa variabile come possibile. */
                
    if($settings['queryaspage'] == 1)
                {
                    while(
    $fetch assoc($sql)) {
                        
    $mii[$fetch['id']] = explode('?'$fetch['address']);
                            if(!empty(
    $mii[$fetch['id']][1]))
                            {
                            
    $mii[$fetch['id']] = $mii[$fetch['id']][1];
                            
    $values[$fetch['id']] = explode('&'$mii[$fetch['id']]);
                                foreach((array)
    $values[$fetch['id']] as $key => $value) {
                                    if(! 
    strstr($url_array[1], $value)) break;
                                    elseif(
    count($values[$fetch['id']])-== $key) {
                                        
    $videor[$fetch['id']] = $fetch['address'];
                                    }
                                }
                            }    
                    }
                
                
    /*
                    PARTE CHE TI INTERESSA: CONFRONTO FRA STRINGHE MEMBRO A MEMBRO
                /*
                
                /* $videor contiene tutti i possibili valori reputati veri. Li analizzo con un contronto percentuale
                fra stringhe. La più simile corrisponde all'URL esatto. */
                    
    if(is_array($videor))
                    {
                    
    $url_len strlen($url);
                        foreach((array)
    $videor as $key => $value) {
                            
    $value_len strlen($value);
                            
    $is_it[$key] = similar_text($value$url);
                            if(
    $value_len >= $url_len)
                                
    $is_it[$key] = (100*$is_it[$key])/$value_len;
                            else 
    $is_it[$key] = (100*$is_it[$key])/$url_len;
                        }
                        
    $real_address max($is_it);
                        return 
    $real_id array_search($real_address$is_it);
                    }
                } else
                {
                    while(
    $fetch assoc($sql)) {
                        
    $mii[$fetch['id']] = explode('?'$fetch['address']);
                        
    $mii[$fetch['id']] = $mii[$fetch['id']][0];
                        if(
    $url2 == $mii[$fetch['id']]) return $fetch['id'];
                    }
                }    
            }    
        
    //Se non esistono pagine simili, contenenti un'interrogazione, cerco almeno la pagina esatta.    
        
    $sql assoc(query("SELECT id FROM " PREFIX "map WHERE address = '" $url "' LIMIT 1"));                        #PLUG
        
    if(count($sql) == 1) return $sql['id'];
        
    $sql assoc(query("SELECT id FROM " PREFIX "map WHERE address LIKE '" $url "' LIMIT 1"));                        #PLUG
        
    if(count($sql) == 1) return $sql['id'];
        
            
    return 
    false;        

    Cristiano
    ---
    Originariamente inviato da rebelia : solo un nerd puo' pensare di tacchinare in un forum di informatica

  3. #3
    Allora, piano piano... io sono un newbie di questa roba.

    Il primo caso che mi hai illustrato mi sembra che non metta mano ai contenuti e punti a realizzare una mappa per similitudine (ma che cosa è, una specie di grafo?) solo sulla base degli url, per poi lasciare la decisione all'utente.

    Come dici tu la cosa si adatta poco alla mia situazione. Da me se non si vanno a guardare i contenuti si rimane in alto mare, perché una variazione di un numeretto nella querystring (che tralaltro non è strettamente di tipo PHP) può essere molto più rilevante di un intero nome o codice di referrer che cambia... e poi non mi posso permettere di lasciare all'utente un compito particolarmente oneroso: l'utente deve trovarsi al massimo di fronte ad un messaggio che lo avvisa di un possibile (o quasi sicuro) inserimento duplicato e lo invita a verificare.

    Veniamo a cosa mi proponi tu.
    Tu dici di caricare il codice della pagina in una variabile, poi di usare striptags. Intanto strip_tags() devo dire che non funziona molto bene: se la uso sull'intero codice della pagina si becca un sacco di spazzatura (probabilmente per colpa di chi scrive le pagine, ma tant'è...), per questo prima di usarla nell'esempio ripulivo le pagine delle parti esterne al body.
    Poi dovrei confrontare membro a membro la stringa risultante con quelle nel db, misurare la similarità con la funzione apposita e inventarmi una politica per individuare i possibili duplicati.

    (Il tuo codice per adesso mi risulta comprensibile solo in parte: i costrutti del linguaggio non li conosco tutti così come le istruzioni per interagire con il db. Comunque mi sembra di aver capito che fai il confronto membro a membro, rapporti le similitudini alla lunghezza della stringa, ordini e tiri fuori il massimo.
    Ok, bastava che me lo dicevi a parole... ...tanto appena mi addentro nello studio del linguaggio non avrò problemi a implementare quello di cui discutiamo qua )

    Il problema è: ma con questo metodo devo salvarmi migliaia di pagine nel DB!? E poi devo chiamare la funzione similar-text() tante volte quante sono le pagine salvate... e infine devo stabilire una politica per decidere se queste vadano o meno mostrate all'utente come possibili duplicati, dato che non posso sempre disturbare l'utente mostrandogli le pagine più simili.

    Premettendo che i duplicati che cerco io sono duplicati veri e propri e non pagine "simili", in cosa il metodo che proponevo era deficitario? :master: Alla fine usa meno spazio su DB, meno calcolo e ha già una sua politica definita.


    Grazie per il tuo aiuto, e scusa la lunghezza.

  4. #4
    Questo è il codice completo della mia pagina di prova (il codice fa un po' schifo, non c'è gestione degli errori e uso grossolano del resto... sorvolate su queste cose )

    Crea un form con due campi in cui inserire gli URL da testare.

    Con queste coppie (sono pagine raggiunte dalle pubblicità di questo forum) sembra funzionare

    http://www.ehiweb.it/servizi_gratis.php?PID=html
    http://www.ehiweb.it/servizi_gratis.php

    http://www.adwordsitalia.com/2008010...m_medium=50x50
    http://www.adwordsitalia.com/20080106.php


    Codice PHP:
    <html>
    <head>
    <title>Prova duplicati</title>
    </head>

    <body>
    <h1>Test duplicati</h1>


    <?php

    if ($_POST[url1] & $_POST[url2]) 
    {

    //assegna gli url

    $url1$_POST[url1];  
    $url2$_POST[url2];

    //scarica il codice delle pagine

    $codicePagina1=file_get_contents($url1);   
    $codicePagina2=file_get_contents($url2);

    //estrae il titolo

    preg_match("/<title[^<>]*>([^<]*)<\/title>/is"$codicePagina1$matches);
    $title1 $matches[1];

    preg_match("/<title[^<>]*>([^<]*)<\/title>/is"$codicePagina2$matches);
    $title2 $matches[1];

    //estrae il body e lo ripulisce dai tags

    eregi("<body([^>]*)>(.*)</body>",$codicePagina1,$regs);
    $bodyPagina1=$regs[2];
    eregi("<body([^>]*)>(.*)</body>",$codicePagina2,$regs);
    $bodyPagina2=$regs[2];

    $testoPagina1=strip_tags($bodyPagina1,'<img>');
    $testoPagina2=strip_tags($bodyPagina2,'<img>');

    //calcola gli hash e li confronta

    $hash1=hash('ripemd160'$testoPagina1);
    $hash2=hash('ripemd160'$testoPagina2);

    echo 
    "Pagina 1: $title1 
     Pagina 2: 
    $title2 

    "
    ;

    if (
    $hash1==$hash2)
    echo 
    "[b]INDIVIDUATO un duplicato[/b]

    "
    ;

    echo 
    "Fai un'altra prova
    "
    ;

    }

    echo 
    '<form name="urls"action="test_duplicati.php" method="POST">
      <label>Url 1: <input type="text" name="url1" maxlength="256" size=100></label>

      <label>Url 2: <input type="text" name="url2" maxlength="256" size=100></label>

      <input type="submit" value="Invia">
    </form>'
    ;
    15.04 05/08/2008
    ?>


    </body>
    </html>

  5. #5
    Credo di non aver ben capito, nel post di argomento, quello che tu intendevi...
    Io pensavo tu avessi una specie di robot-directory che dovesse evitare i duplicati: io ti ho proposto un algoritmo che ti consente di fare confronti membro a membro via db (utile nel caso in cui tu abbia un circuito di link).

    Ti espongo cosa ho capito del tuo problema.
    Dati x, y due pagine e z un utente.
    z entra nel sito alla ricerca sito web nel circuito (le pagine del circuito sono in un database (...?)). Il circuito, gestito da un robot, è riempito (in che modo?) da varie pagine. Si trovano nel circuito n pagine, di cui 2 o più propabilmente simili. Il robot admin-front (o il robot user-front?) deve eliminare i doppioni (o comunque segnalare una similitudine).

    A me manca un'importante informazione: le pagine del circuito devono essere inevitabilmente inserite in un db (o un file): il mio consiglio è quello di fare un confronto membro a membro su TUTTE le pagine già presenti (con un consumo di query forse non trascurabile) per ottenere una verifica migliore.

    La pagina che tu mi hai postata PHP fa un confronto semplicemente fra 2 URL: è inevitabile che tu debba fare un controllo globale, qualora gli url siano più di 2... (il problema del numero delle query può essere raggirato con un sistema di cache).

    Io ho preferito consigliarti strip-tag() perché si tratta di una funzione banale, è evidente che se sei pratico con le espressioni regolare puoi affinare il tuo risultato (vale lo stesso per gli algoritmi di confronto hash e similar-text).

    Scusa anche tu la lunghezza!
    Cristiano
    ---
    Originariamente inviato da rebelia : solo un nerd puo' pensare di tacchinare in un forum di informatica

  6. #6
    Allora, fermi tutti, non si è capito lo scenario. Chiarisco meglio quali sono le funzioni offerte dal sito.

    Il sito deve gestire una collezione di URL (sole le url, non i contenuti) relativi a gallerie, collezione strutturata in modo opportuno. Da dove vengono queste URL? Sono esclusivamente fornite dagli utenti, che contribuiscono alla collezione in modo collaborativo.
    Il sito quindi non è un motore di ricerca e il procedimento di cui parliamo è un procedimento che vede l'utente inserire un'informazione, non richiederla.

    Il problema che stiamo affrontando è di trovare una maniera per verificare che l'utente che sta contribuendo, sottomettendo un nuovo URL alla collezione, stia fornendo effettivamente un contenuto nuovo. Per fare questo è necessario confrontare il suo contributo con quelli già presenti, ma naturalmente non dal punto di vista della sola URL (non basta, anche studiando metodi raffinati) ma piuttosto del contenuto a cui porta.
    Il confronto avviene membro a membro, tra l'URL appena inserita e tutte quelle presenti nel DB, quindi il tutto si riduce nell'inventare una funzione che date due pagine sia in grado di indicare se sono sostanzialmente uguali oppure no. Se lo fa senza costringermi a reperire ogni volta i contenuti di tutte le pagine della collezione - costringendomi quindi a conservare nel DB un dato di cui non mi importa nulla - è ancora meglio. Per questo ho scelto di usare una funzione di hash: non conservo dati inutili e non devo eseguire onerose procedure di confronto. Un hash verrà calcolato per ogni URL in fase di inserimento e conservato, e i duplicati verrano verranno individuati con una semplice query SQL.

    Spero che ora sia più chiaro il problema.

    Ah, la funzione strip_tags() la uso se vedi, con le espressioni regolari sono solo alle prime armi. L'unica cosa che ho fatto è stato dare in pasto a strip_tags() anziché l'intera pagina solamente il body.


  7. #7
    Codice PHP:
    <?php
    function isindb($sent_url $_POST['sent_url']) {
        
    /*        STRUTTURA DEL DB - tabella "url"
        #
        #        |---------------|-------------------|
        #        | titolo        |  md5mac            |
                |---------------|-------------------|
        */

        /*        AL momento di inserire una pagina nella tabella "URL" 
                calcolo il valore md5 (o hash) della pagina
        */
        
        
    $load file_get_contents($sent_url);
        
        
    //Emulo il tuo codice
        
    preg_match("/<title[^<>]*>([^<]*)</title>/is"$load$matches);
        
    $title $matches[1];
        
    eregi("<body([^>]*)>(.*)</body>"$load$regs);

        
    $bodyTAG strip_tags($regs[2],'<img>');
        
    $hash md5($bodyTAG);

        
    //Confronto le hash
        
    $check mysql_query("SELECT * FROM url WHERE md5mac = '" $hash "' LIMIT 1");
        if(
    mysql_num_rows($check == 1)) return false;
        
        
    //il link non è mai stato inserito...
        
    mysql_query("INSERT INTO url (titolo, md5mac) VALUES ('" $title "', '" $hash "')");

    return 
    true;
    }    
    ?>
    Questo?
    Cristiano
    ---
    Originariamente inviato da rebelia : solo un nerd puo' pensare di tacchinare in un forum di informatica

  8. #8
    Sì, esatto, sarà una cosa del genere... ma perché parliamo per codice PHP?
    Il problema non sarà di certo scrivere il codice. La mia domanda di apertura era rivolta ad avere un parere sul sistema ideato, su eventuali aggiustamenti o alternative... ma soprattutto non so quale algoritmo di hash usare! :master: Vorrei fare sin da subito una scelta oculata.

    A me serve per indicizzare, non c'è di mezzo la sicurezza e i contenuti di cui fare l'hash saranno di poche centinaia di caratteri. Date queste cose quale dovrei scegliere?

  9. #9
    Guarda... i problemi sono vari: facendo una rapida anlisi ti accorgerai che alcune pagine uguali differiscono fra loro per "elementi" inconsistenti (per esempio molti siti stampano l'ora o le news da altri siti via XML): calcolando un'hash (o peggio un valore md5) non puoi fare un controllo su questi element (infatti un valore md5 cambia radicalmente anche per solo un carattere).

    Cosa posso consigliarti? Per avere il risultato migliore devi fare un controllo necessariamente sul testo stesso (quindi usare similar-text, con una percentuale di almeno 90%, o levenshtein).

    Per un confronto 1:1 il tuo algoritmo va benissimo.
    Cristiano
    ---
    Originariamente inviato da rebelia : solo un nerd puo' pensare di tacchinare in un forum di informatica

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.