SPARQL fragt den Inhalt von HTML-Seiten ab

Guten Tag.
Nachdem ich an einer Konferenz teilgenommen hatte, bekam ich eine Idee, deren Verkörperung ich präsentiere.
Dieser Beitrag stellt ein Beispiel für die Arbeit mit Bibliotheken greifen und RDFLib sowie fertige Klasse auszuführen SPARQL - Anfragen an den Inhalt von Web-Seiten.

Mit diesem Tool sollen Informationen von Sites, die sie nicht in strukturierter Form bereitstellen (rdf-triples, xml, json), in eine Form umgewandelt werden, die für „Computer“ verständlich ist.


Um SPARQL-Abfragen zu HTML-Inhalten durchzuführen, müssen Sie ein lokales rdf-Repository erstellen und es mit Informationen füllen, die Sie mit grab von der HTML-Seite erhalten haben.

Zu Beginn importieren wir alle notwendigen Bibliotheken und registrieren auch die Verwendung des SPARQL-Plugins.

# -*- coding: utf-8 -*-
import grab
import rdflib
from rdflib import *
from rdflib import plugin
plugin.register(
    'sparql', rdflib.query.Processor,
    'rdfextras.sparql.processor', 'Processor')
plugin.register(
    'sparql', rdflib.query.Result,
    'rdfextras.sparql.query', 'SPARQLQueryResult')


Definieren Sie unsere Klasse und erstellen Sie einen Konstruktor dafür.
Der Designer kann die URL der Seite akzeptieren, die aufgelöst und im Repository abgelegt werden muss, und kann auch den nicht standardmäßigen Speicherort der Namespace-Definition bestimmen.

class SQtHD():
    '''
    sparql query to html documents
    '''
    def __init__(self,url=None,htmlNamespace='http://localhost/rdf/html#'):
        '''
        Constructor
        '''
        self.__grab__=grab.Grab()#Наш парсер
        self.__storage__=Graph()#Наше хранилище
        self.__namespace__=Namespace(htmlNamespace)#Создаем пространство имен
        self.__storage__.bind('html', URIRef(htmlNamespace))#Задаем пространству имен короткое имя
        self.__initnamespace__=dict(self.__storage__.namespace_manager.namespaces())
        if url:#Если необходимо, то загружаем содержимое указанной страницы в хранилище.
            self.__store__(url)


Als nächstes müssen Sie eine Utility-Funktion definieren, um das Repository mit dem Inhalt der Seite zu füllen.

    def __store__(self,url):
        self.__storage__.remove((None,None,None))#Очищаем хранилище
        self.__grab__.go(url)#Выполняем переход по указанному адресу средствами grab
        root=self.__grab__.tree.getroottree().getroot()
        self.__parse__(root)#Парсим содрежимое страницы.


Die folgenden Elementinformationen werden im lokalen Speicher gespeichert:
  • Informationen über die Art des Elements (welches HTML-Tag)
  • Übergeordnete Informationen
  • Informationen über die Position des Elements in Bezug auf die Brüder
  • Informationen zur Elementverschachtelung
  • Test im Element enthalten
  • Angaben zur Anzahl der Kinder
  • Verweise auf untergeordnete Elemente
  • Attributwert für einen Artikel

Die nächste Dienstprogrammfunktion durchläuft rekursiv den Baum der Elemente, sammelt die erforderlichen Informationen und fügt sie dem Repository hinzu.

    def __parse__(self,element,parent=None,children_position=None,children_level=0):
        current_element=BNode()
        children_elements=element.getchildren()
        if str(element.tag)=='':
            self.__storage__.add((current_element, RDF.type, 
                                  self.__namespace__['comment']))
        else:
            self.__storage__.add((current_element, RDF.type, 
                                  self.__namespace__[element.tag]))
        if not parent==None:
            self.__storage__.add((current_element,self.__namespace__['parent'],parent))   
            self.__storage__.add((parent,self.__namespace__['children'],
                                  current_element))    
            self.__storage__.add((current_element,self.__namespace__['children_position'],
                                  Literal(children_position)))     
        self.__storage__.add((current_element,self.__namespace__['children_level'],
                              Literal(children_level)))     
        if element.text and len(element.text.strip())>0:
            self.__storage__.add((current_element,self.__namespace__['text'],
                                  Literal(element.text.strip())))
        if element.text_content() and len(element.text_content().strip())>0:
            self.__storage__.add((current_element,self.__namespace__['text_content'],
                                  Literal(element.text_content().strip())))
        self.__storage__.add((current_element,self.__namespace__['children_count'],
                              Literal(len(children_elements))))
        for i in element.attrib:
            self.__storage__.add((current_element,self.__namespace__[i],
                                  Literal(element.attrib[i])))
        for i in range(len(children_elements)):
            self.__parse__(children_elements[i],current_element,i,children_level+1) 


Diese Funktion führt eine SPARQL-Abfrage zum lokalen Speicher aus.

    def executeQuery(self,query,url=None):
        '''
        execute query on storadge
        '''
        if url:#Если необходимо, то загружаем содержимое указанной страницы в хранилище.
            self.__store__(url)
        return self.__storage__.query(query,
                                  initNs=self.__initnamespace__)#Возвращаем результат выполнения запроса.


Diese Funktion füllt das Repository mit dem Inhalt der angegebenen Seite.

    def loadStoradge(self,url):
        '''
        load and parse html page to local rdf storadge
        '''
        self.__store__(url)


Zum Schluss einige einfache Abfragebeispiele.

if __name__ == "__main__":
    endPoint = SQtHD()#Создаем экземпляр класса SQtHD
    endPoint.loadStoradge('http://habrahabr.ru')#Загружаем страницу в хранилище
    print "All sources for images given by tag :"#Вывести все уникальные адреса картинок
    q=endPoint.executeQuery('SELECT DISTINCT ?src { ?a rdf:type html:img. ?a html:src ?src. }')
    for row in q.result:
        print row
    print
    print "All link urls:"#Вывести все уникальные адреса ссылок
    q=endPoint.executeQuery('SELECT DISTINCT ?href { ?a rdf:type html:a. ?a html:href ?href. }')
    for row in q.result:
        print row
    print
    print "All class names for elements:"#Вывести все уникальные имена классов
    q=endPoint.executeQuery('SELECT DISTINCT ?class { ?a html:class ?class. }')
    for row in q.result:
        print row
    print
    '''
    print "All scripts (without loaded by src):"#Тест всех внутристраничных скриптов.
    q=endPoint.executeQuery('SELECT ?text { ?a rdf:type html:script. ?a html:text ?text. }')
    for row in q.result:
        print row
    print'''
    print "All script srcs:"#Все ссылки на скрипты.
    q=endPoint.executeQuery('SELECT ?src { ?a rdf:type html:script. ?a html:src ?src. }')
    for row in q.result:
        print row
    print


Das Ergebnis der Ausführung einer Anforderung zum Anzeigen aller Skriptverknüpfungen:

All script srcs:
/javascripts/1341931979/all.js
/javascripts/1341931979/_parts/posts.js
/javascripts/1341931979/_parts/to_top.js
/javascripts/1341931979/_parts/shortcuts.js
/javascripts/1341931979/libs/jquery.form.js
/javascripts/1341931979/facebook_reader.js
/js/1341931979/adriver.core.2.js
/javascripts/1341931979/libs/highlight.js
/javascripts/1341931979/hubs/all.js
/javascripts/1341931979/posts/all.js


Es gibt also drei Möglichkeiten, das Repository zu füllen:
  1. Bei der Klasseninitialisierung
  2. Über die loadStoradge Funktion
  3. Für jede Speicheranfrage


Das GIST-Projekt enthält auch eine Namespace-Definition unter Verwendung von XML. Der Namespace definiert, was ein Tag ist, legt die erforderlichen Eigenschaften und Beziehungen fest und definiert Tags in HTML 4.
Empfohlene Lektüre:
„Programming the Semantic Web“ Von Toby Segaran, Colin Evans und Jamie Taylor

Jetzt auch beliebt: