web-dev-qa-db-fra.com

Quel est le moyen le plus rapide de gratter une page Web HTML sur Android?

J'ai besoin d'extraire des informations d'une page Web non structurée dans Android. Les informations que je veux sont intégrées dans une table qui n'a pas d'identifiant.

<table> 
<tr><td>Description</td><td></td><td>I want this field next to the description cell</td></tr> 
</table>

Dois-je utiliser

  • Correspondance de motif?
  • Utilisez BufferedReader pour extraire les informations?

Ou existe-t-il un moyen plus rapide d'obtenir ces informations?

27
unj2

Je pense que dans ce cas, cela n'a aucun sens de chercher un moyen rapide pour extraire l'information car il n'y a pratiquement aucune différence de performance entre les méthodes déjà suggérées dans répond quand vous le comparez au temps qu'il faudra pour télécharger le HTML.

Donc, en supposant que par le plus rapide vous voulez dire le code le plus pratique, lisible et maintenable, je vous suggère d'utiliser un DocumentBuilder pour analyser le HTML pertinent et extraire les données en utilisant XPathExpression s:

Document doc = DocumentBuilderFactory.newInstance()
  .newDocumentBuilder().parse(new InputSource(new StringReader(html)));

XPathExpression xpath = XPathFactory.newInstance()
  .newXPath().compile("//td[text()=\"Description\"]/following-sibling::td[2]");

String result = (String) xpath.evaluate(doc, XPathConstants.STRING);

S'il vous arrive de récupérer du HTML non valide, je recommande d'isoler la partie pertinente (par exemple en utilisant substring(indexOf("<table")..) et si nécessaire de corriger les erreurs HTML restantes avec les opérations String avant d'analyser. Si cela devient trop complexe cependant (c'est-à-dire très mauvais HTML), optez simplement pour l'approche de correspondance de motifs hacky comme suggéré dans d'autres réponses.

Remarques

  • XPath est disponible depuis l'API niveau 8 (Android 2.2). Si vous développez pour des niveaux d'API inférieurs, vous pouvez utiliser des méthodes et des conditions DOM pour naviguer jusqu'au nœud que vous souhaitez extraire
47
Josef Pfleger

Le moyen le plus rapide analysera vous-même les informations spécifiques. Vous semblez connaître la structure HTML précisément à l'avance. Les méthodes BufferedReader , String et StringBuilder devraient suffire. Voici un exemple de lancement qui affiche le premier paragraphe de votre propre question:

public static void main(String... args) throws Exception {
    URL url = new URL("http://stackoverflow.com/questions/2971155");
    BufferedReader reader = null;
    StringBuilder builder = new StringBuilder();
    try {
        reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
        for (String line; (line = reader.readLine()) != null;) {
            builder.append(line.trim());
        }
    } finally {
        if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
    }

    String start = "<div class=\"post-text\"><p>";
    String end = "</p>";
    String part = builder.substring(builder.indexOf(start) + start.length());
    String question = part.substring(0, part.indexOf(end));
    System.out.println(question);
}

L'analyse est dans presque tous les cas nettement plus rapide que la correspondance de motifs. La correspondance de modèles est plus facile, mais il existe un certain risque qu'elle puisse donner des résultats inattendus, certainement lors de l'utilisation de modèles d'expression régulière complexes.

Vous pouvez également envisager d'utiliser un analyseur HTML tiers plus flexible au lieu d'en écrire un vous-même. Ce ne sera pas aussi rapide que de vous analyser avec des informations connues à l'avance. Il sera cependant plus concis et flexible. Avec des analyseurs HTML décents, la différence de vitesse est assez négligeable. Je recommande fortement Jsoup pour cela. Il prend en charge sélecteurs CSS de type jQuery . Extraire le premier paragraphe de votre question serait alors aussi simple que:

public static void main(String... args) throws Exception {
    Document document = Jsoup.connect("http://stackoverflow.com/questions/2971155").get();
    String question = document.select("#question .post-text p").first().text();
    System.out.println(question);
}

La page Web dont vous parlez n'est pas claire, je ne peux donc pas donner un exemple plus détaillé de la façon dont vous pouvez sélectionner les informations spécifiques de la page spécifique à l'aide de Jsoup. Si vous ne pouvez toujours pas le comprendre par vous-même en utilisant Jsoup et sélecteurs CSS , n'hésitez pas à publier l'URL dans un commentaire et je vous suggérerai comment le faire.

19
BalusC

Lorsque vous supprimez la page Web Html. Vous pouvez faire deux choses pour cela. Le premier utilise REGEX. Un autre est les analyseurs HTML.

L'utilisation de Regex n'est pas préférable pour tous. Parce qu'il provoque une exception logique au Runtime.

L'utilisation de l'analyseur HTML est plus compliquée à faire. vous ne pouvez pas être sûr que la sortie sera correcte. son trop fait une exception d'exécution par mon expérience.

Il vaut donc mieux faire la réponse de l'url au fichier Xml. et faire analyse XML est très simple et efficace.

2
Praveen

Pourquoi n'écris-tu pas

int start = data.indexOf ("Description");

Après cela, prenez la sous-chaîne requise.

1
Fedor

Pourquoi ne créez-vous pas un script qui effectue le grattage avec cURL et simple analyseur dom html et récupérez simplement la valeur dont vous avez besoin sur cette page? Ces outils fonctionnent avec PHP, mais d'autres outils existent pour exister pour n'importe quel langage dont vous avez besoin.

0
Oren Hizkiya

Une façon de procéder consiste à placer le code HTML dans une chaîne, puis à rechercher et à analyser manuellement la chaîne. Si vous savez que les balises viendront dans un ordre spécifique, vous devriez pouvoir les parcourir et trouver les données. Cependant, c'est un peu bâclé, donc c'est une question de voulez-vous que cela fonctionne maintenant? ou travailler enfin?

int position = (String)html.indexOf("<table>");  //html being the String holding the html code
String field = html.substring(html.indexOf("<td>",html.indexOf("<td>",position)) + 4, html.indexOf("</td>",html.indexOf("</td>",position)));

comme je l'ai dit ... vraiment bâclé. Mais si vous ne faites cela qu'une seule fois et que vous en avez besoin pour fonctionner, cela pourrait bien faire l'affaire.

0
mtmurdock