Frage

Ich habe versucht, Funktionen zu erstellen, um von der HTML -Seite zu kratzen und zu taggen, deren URL ich für eine Funktion zur Verfügung stelle, und dies funktioniert so wie es sollte. Ich bekomme Sequenz von <h3> und <table> Elemente, wenn ich versuche, die ausgewählte Funktion zu verwenden, um nur Tabellen- oder H3 -Tags aus der resultierenden Sequenz zu extrahieren, erhalten ich () oder wenn ich versuche, diese Tags zuzuordnen, die ich bekomme (nil nil nil ...).

Könnten Sie mir bitte helfen, dieses Problem zu lösen oder mir zu erklären, was ich falsch mache?

Hier ist der Code:

(ns Test2 
  (:require [net.cgrand.enlive-html :as html]) 
  (:require [clojure.string :as string])) 

(defn get-page 
  "Gets the html page from passed url" 
  [url] 
  (html/html-resource (java.net.URL. url))) 

(defn h3+table       
    "returns sequence of <h3> and <table> tags"
  [url] 
  (html/select (get-page url) 
{[:div#wrap :div#middle :div#content :div#prospekt :div#prospekt_container :h3] 
[:div#wrap :div#middle :div#content :div#prospekt :div#prospekt_container :table]} 
               )) 

(def url "http://www.belex.rs/trgovanje/prospekt/VZAS/show")

Diese Zeile bereitet mir Kopfschmerzen:

(html/select (h3+table url) [:table])

Könnten Sie mir bitte sagen, was ich falsch mache?

Nur um meine Frage zu klären: Ist es möglich, die Auswahlfunktion von Enlive zu verwenden, um nur Tabellen -Tags aus Ergebnis von (H3+Tabellen -URL) zu extrahieren?

War es hilfreich?

Lösung

Wie @julien betonte, müssen Sie wahrscheinlich mit der tief verschachtelten Baumstruktur arbeiten, die Sie durch die Bewerbung erhalten (html/select raw-html selectors) auf der rohen HTML. Es scheint, als ob Sie versuchen, sich zu bewerben html/select Mehrmals, aber das funktioniert nicht. html/select Pariert HTML in eine Clojure -Datenstruktur, sodass Sie sie nicht wieder auf diese Datenbauteile anwenden können.

Ich fand heraus, dass das Parsen der Website tatsächlich ein wenig involviert war, aber ich dachte, es könnte ein netter Anwendungsfall für Multimethods sein, also habe ich etwas zusammengehackt.

(Der Code ist hier hässlich, Sie können dies auch auschecken Kern)

(ns tutorial.scrape1
  (:require [net.cgrand.enlive-html :as html]))

(def *url* "http://www.belex.rs/trgovanje/prospekt/VZAS/show")

(defn get-page [url] 
  (html/html-resource (java.net.URL. url))) 

(defn content->string [content]
  (cond
   (nil? content)    ""
   (string? content) content
   (map? content)    (content->string (:content content))
   (coll? content)   (apply str (map content->string content))
   :else             (str content)))

(derive clojure.lang.PersistentStructMap ::Map)
(derive clojure.lang.PersistentArrayMap  ::Map)
(derive java.lang.String                 ::String)
(derive clojure.lang.ISeq                ::Collection)
(derive clojure.lang.PersistentList      ::Collection)
(derive clojure.lang.LazySeq             ::Collection)

(defn tag-type [node]
  (case (:tag node) 
   :tr    ::CompoundNode
   :table ::CompoundNode
   :th    ::TerminalNode
   :td    ::TerminalNode
   :h3    ::TerminalNode
   :tbody ::IgnoreNode
   ::IgnoreNode))

(defmulti parse-node
  (fn [node]
    (let [cls (class node)] [cls (if (isa? cls ::Map) (tag-type node) nil)])))

(defmethod parse-node [::Map ::TerminalNode] [node]
  (content->string (:content node)))
(defmethod parse-node [::Map ::CompoundNode] [node]
  (map parse-node (:content node)))
(defmethod parse-node [::Map ::IgnoreNode] [node]
  (parse-node (:content node)))
(defmethod parse-node [::String nil] [node]
  node)
(defmethod parse-node [::Collection nil] [node]
  (map parse-node node))

(defn h3+table [url] 
 (let [ws-content (get-page url)
       h3s+tables (html/select ws-content #{[:div#prospekt_container :h3]
                                            [:div#prospekt_container :table]})]
   (for [node h3s+tables] (parse-node node)))) 

Ein paar Worte darüber, was los ist:

content->string Nimmt eine Datenstruktur und sammelt ihren Inhalt in eine Zeichenfolge und gibt diese zurück, damit Sie diese auf Inhalte anwenden können <br/>) Das wollen Sie ignorieren.

Die abgeleiteten Aussagen legen eine Ad-hoc-Hierarchie fest, die wir später im Multimethod-Parse-Knoten verwenden werden. Dies ist praktisch, da wir nie genau wissen, auf welche Datenstrukturen wir begegnen werden, und wir könnten später noch mehr Fälle hinzufügen.

Das tag-type Funktion ist eigentlich ein Hack, der die Hierarchie -Aussagen nachahmt - Afaik Sie können keine Hierarchie aus nicht -namePace qualifizierten Schlüsselwörtern erstellen, also habe ich es so gemacht.

Der Multi-Methode parse-node Versand auf der Klasse des Knotens und wenn der Knoten eine Karte zusätzlich auf dem ist tag-type.

Jetzt müssen wir nur noch die entsprechenden Methoden definieren: Wenn wir an einem Terminalknoten sind . Die Methode für ::String wird eigentlich nicht einmal benutzt, aber ich habe es aus Sicherheitsgründen gelassen.

Das h3+table Die Funktion ist so ziemlich das, was Sie zuvor hatten. Ich habe die Selektoren ein wenig vereinfacht und sie in einen Satz gestellt, nicht sicher, ob ich sie wie beabsichtigt in eine Karte einfügt, wie Sie es getan haben.

Viel Spaß beim Scraping!

Andere Tipps

Ihre Frage ist schwer zu verstehen, aber ich denke, Ihre letzte Zeile sollte einfach sein

(h3+table url)

Dadurch wird eine tief verschachtelte Datenstruktur zurückgegeben, die abgeschrutzt HTML enthält, in die Sie dann mit den üblichen Clojure -Sequenz -APIs eintauchen können. Viel Glück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top