RPG-Maker Quartier
http://forum.rpg2000.4players.de/phpBB3/

In Java buch.de ansprechen und auslesen
http://forum.rpg2000.4players.de/phpBB3/viewtopic.php?f=9&t=98856
Seite 1 von 1

Autor:  Skogtrollet [ So Mär 10, 2013 17:05 ]
Betreff des Beitrags:  In Java buch.de ansprechen und auslesen

Hallo allerseits,

Ich soll im Rahmen des Softwareprojektes bei uns in Java Artikel auf buch.de finden und auslesen.
Ich denke mal, dass es so schwer nicht sein kann, aber ich habe noch nie was mit .html (oder .xml!?) in der Richtung gemacht und kenne mich überhaupt nicht aus, 0 Vorerfahrung, keine zugehörige Lehrveranstaltung, Autodikaktik*10^23. Hat jemand ein Beispielprogramm parat? An Beispielen lerne ich für gewöhnlich am Besten.

Wäre cool, wenn jemand sowas in der ungefähren Art oder in Teilstücken rumliegen hat und mit mir teilt. :)
Sonst muss ich mir das kleinfummelig aus dem Internet zusammenpuzzlen.

Gruß

Autor:  Xardas der Dunkle [ So Mär 10, 2013 22:00 ]
Betreff des Beitrags:  Re: In Java buch.de ansprechen und auslesen

Normalerweise bedient man sich für so etwas einer Schnittstelle (API) die der Anbieter bereit stellen muss. Ich habe bei buch.de jetzt allerdings keinen Hinweis auf eine solche gefunden.

Es gibt verschiedene Wege eine solche API umzusetzen.
Beispiele dafür sind SOAP und REST. Ersteres wird meist direkt als Modul von der jeweiligen Programmiersprache bereitgestellt und basiert rein auf XML.

Allerdings kommt mittlerweile mehr die zweite Variante zum Einsatz, dieses Protokoll basiert auf einfachen HTTP Anfragen die an eine festgelegte URL gesendet werden, als Ergebnis erhält man anstatt HTML Dokumente die reinen Daten als JSON, XML, YML, CSV, etc.

Falls buch.de eine solche Schnittstelle nicht bereitstellen sollte, bleibt dir nichts anderes über als die HTML Dokumente zu parsen.
Hierzu müsstest du dir erst einmal das Suchen-Formular auf deren Webseite angucken:

- An welche URL wird das Formular gesendet
- GET oder POST?
- Welche Parameter werden übermittelt

Diesen Aufruf müsstest du dann über Java durchführen und würdest eben das HTML Dokument zurückbekommen welches du dann mit einem XML Parser (funktioniert leider bei HTML Seiten nicht immer korrekt) oder mit Regulären Ausdrücken zerlegen musst.


Am besten guckst du dir wirklich mal REST an, dass hilft dir nämlich auch beim letzten Punkt.

Autor:  Askr [ Mo Mär 11, 2013 19:12 ]
Betreff des Beitrags:  Re: In Java buch.de ansprechen und auslesen

Ich kann dir leider nicht helfen, würde mich aber dennoch für die Lösung interessieren. :D

Autor:  Skogtrollet [ Di Mär 12, 2013 16:16 ]
Betreff des Beitrags: 

Vielen Dank für die Tipps, Xardas. Leider bietet buch.de nichts Hübsches (oder zumindest fand ich nichts), im Endeffekt habe ich jetzt was geschrieben, das einen Link zusammenbaut und das HTML-Dokument nach charakteristischen Elementen abgrast.

Ziemlich hässliche Sache also. :D
Hier ist der (relevante) Code. Es wird ausschließlich BuchDeReader.read angesprochen, der Rest klickert von da an von selbst runter.

Code:
package v3.model;

import java.sql.Timestamp;

/**
 * ReadInformation is a kind of Transport Object to return search information
 * from provider searches in one format.
 *
 */
public class ReadInformation {
   private String name;
   private String picture;
   private String filter;
   private String EAN;
   private String ISBN;
   private int price;
   private Timestamp readTimestamp;
   
   
   public ReadInformation (String name, String picture, String filter, String EAN, String ISBN, int price, Timestamp timestamp) {
      setName(name);
      setPicture(picture);
      setFilter(filter);
      setEAN(EAN);
      setISBN(ISBN);
      setPrice(price);
      setReadTimestamp(timestamp);
   }
   
   
   /* TEN MIRRION GETTER AND SETTER */
}


Code:
package v3.model;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;

/**
 * buchDeReader searches buch.de for the user's input and returns an
 * array of standardized ReadInformation.
 */
public class BuchDeReader {
   public static ArrayList<ReadInformation> read(String searchText, String filter) {
      String buchDeURL = buildURL(searchText, filter);
      String wholePage = readURL(buchDeURL);
      ArrayList<ReadInformation> readInformation = evaluateURL(wholePage, filter);

      return readInformation;
   }


   // builds the URL we want to use
   private static String buildURL(String searchText, String filter) {
      // build buchDeURL - default link plus searchText
      String buchDeURL = "http://www.buch.de/shop/home/suche/?sq=" + searchText;

      // build buchDeURL - additional searchText (filters, if not available in category)
      if (filter.equals("CD")) {
         buchDeURL = buchDeURL + " CD";
      } else if (filter.equals("DVD")) {
            buchDeURL = buchDeURL + " DVD";
      } else if (filter.equals("Blu-ray")) {
            buchDeURL = buchDeURL + " Blu-ray";
      }

      // build buchDeURL - search category (filter, if available)
      if (filter.equals("Buch")) {
            buchDeURL = buchDeURL + "&sswg=BUCH";
      } else if (filter.equals("eBook")) {
            buchDeURL = buchDeURL + "&sswg=EBOOK";
      } else {
               buchDeURL = buchDeURL + "&sswg=ANY";
      }
      
      buchDeURL = buchDeURL.replace(' ', '+');
      
      return buchDeURL;
   }


   private static String readURL(String buchDeURL) {
      // call buchDeURL, save HTML as String
      String wholePage = "";
      
      try {
         URL url = new URL(buchDeURL);
         URLConnection urlConnection = url.openConnection();
         InputStream result = urlConnection.getInputStream();

         BufferedReader reader = new BufferedReader(new InputStreamReader(result));
         String line = null;
         while ((line = reader.readLine()) != null) {
            wholePage = wholePage + line;
            // System.out.println(line);
         }
         reader.close();
      } catch (Exception e) {
         // PANIC MODE ENGAGE
         e.printStackTrace();
      }

      return wholePage;
   }
   
   
   private static ArrayList<ReadInformation> evaluateURL(String wholePage, String filter) {
      ArrayList<ReadInformation> readInformationArray = new ArrayList<ReadInformation>();
      
      if (wholePage.contains("</span>keine Treffer.")) {
         // "keine Treffer" in wholePage - no hits, nothing to do
         
      } else if (wholePage.contains("OpenGraph")) {
         // "OpenGraph" in wholePage - one hit
         addOneElement(readInformationArray, filter, wholePage);
      } else {
         // else - multiple hits
         addMultipleElements(readInformationArray, filter, wholePage);
      }
      
      return readInformationArray;
   }


   private static void addOneElement(ArrayList<ReadInformation> readInformationArray, String filter, String wholePage) {
      
      String name = wholePage;
      name = cutText(name, "og:title\" content=\"", 19, "\" />");
      
      String picture = wholePage;
      picture = cutText(picture, "og:image\" content=\"", 19, "\"/>");
      
      String EAN = wholePage;
      EAN = cutText(EAN, "eanNumber : '", 13, "'");
      
      String ISBN = wholePage;
      ISBN = cutText(ISBN, "isbnNumber : '", 14, "'");
      
      String priceText = wholePage;
      priceText = cutText(priceText, "<span class=\"pm_preis b9Value\">", 31, "</span>");
      int price = deleteComma(priceText);
      
      readInformationArray.add(new ReadInformation(name, picture, filter, EAN, ISBN, price, new Timestamp(new Date().getTime())));
   }
   
   
   private static int deleteComma(String priceText) {
      StringBuffer stringBuffer = new StringBuffer(priceText);
      int i;
      
      while ((i = stringBuffer.indexOf(",")) > -1) {
         stringBuffer.deleteCharAt(i);
      }
      
      int price = new Integer(stringBuffer.toString());
      return price;
   }
   
   
   private static String cutText(String textToCut, String startPhrase, int startPhraseLength, String endPhrase) {
      textToCut = textToCut.substring(textToCut.indexOf(startPhrase) + startPhraseLength);   // cut left
      textToCut = textToCut.substring(0, textToCut.indexOf(endPhrase));                  // cut right
      return textToCut;
   }


   private static void addMultipleElements(ArrayList<ReadInformation> readInformationArray, String filter, String wholePage) {
      String currentLink = null;
      String currentPage = null;
      // read all articles like single articles by calling their page
      while (wholePage.contains("col1\"><a href=\"")) {
         wholePage = wholePage.substring(wholePage.indexOf("col1\"><a href=\"") + 15);
         currentLink = cutText(wholePage, "h", 0, "\" style=");
         currentPage = readURL(currentLink);
         addOneElement(readInformationArray, filter, currentPage);
      }
   }
}

Autor:  Fryie [ Di Mär 12, 2013 16:40 ]
Betreff des Beitrags:  Re: In Java buch.de ansprechen und auslesen

nennt sich auch "scrapen".

Tipp #1: Regular Expressions

Tipp #2 (längerfristig): Nutz Groovy und spar dir die 10000 getter und setter. Auch nice: die Syntax für RegExes

Autor:  Skogtrollet [ Di Mär 12, 2013 16:45 ]
Betreff des Beitrags: 

Groovy ist geil, ja. :D
Ich benutze das grad nicht, weil ... ja warum eigentlich. Kenne ich erst seit ein paar Wochen und habe es hier wohl irgendwo unter den Tisch fallen lassen. Bad Fran.

Das andere lese ich mir mal durch, danke.

Autor:  KD [ Fr Mär 15, 2013 1:35 ]
Betreff des Beitrags:  Re: In Java buch.de ansprechen und auslesen

Wenn es auf die Sprache nicht ankommt, würde ich definitiv zu einer Scriptsprache (ruby oder groovy) raten. Beides kann notfalls auch in Java Bytecode kompiliert werden. Dann besorgst du dir einen HTML-Parser (viele XML-Parser unterstützen auch HTML) und schaust dir an wie xpath oder (etwas einfacher und meistens ausreichend) css query funktionieren. Der Rest ist dann in wenigen Zeilen programmiert.

Autor:  Fryie [ Fr Mär 15, 2013 7:16 ]
Betreff des Beitrags:  Re: In Java buch.de ansprechen und auslesen

Oder jsoup - Vorteil: benutzt JQuery-ähnliche Syntax. (Im Java-Umfeld)
Für Python gibt es BeautifulSoup, bei Ruby Nokogiri, aber das ist jetzt ja erst einmal nicht so relevant.

Autor:  Skogtrollet [ Sa Mär 16, 2013 10:32 ]
Betreff des Beitrags: 

Wir sind mittlerweile von unserer ursprünglichen Projektumgebung abgesprungen, weil die Firma, mit der wir zusammenarbeiten sollten (/auf deren Framework, das sowieso scheiße ist, wir aufbauen sollten) uns hat hängen lassen. Schon bitter, wenn es nach drei Wochen immer noch schneller ist neu anzufangen.

Stattdessen benutzen wir jetzt die groovy&grailstoolsuite als Rahmen. Bis Mittwochabend soll dann ein Vergleichsportal fertig sein. Mal gucken, ich bin zuversichtlich. Ist ja eigentlich nur eine Pippifax-Aufgabe, das einzige Problem ist alle Sachen zusammenzubauen, sodass sie auch zusammen funktionieren.

Die Suchfunktion habe ich jetzt trotzdem nicht neu geschrieben, sondern einfach reinpastiert. :chingrin:

Seite 1 von 1 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/