Como “digitalizar” um site (ou página) para obter informações e trazê -lo para o meu programa?

StackOverflow https://stackoverflow.com/questions/2835505

  •  26-09-2019
  •  | 
  •  

Pergunta

Bem, estou praticamente tentando descobrir como extrair informações de uma página da web e trazê -las para o meu programa (em Java).

Por exemplo, se eu souber a página exata de que quero informações, por uma questão de simplicidade, uma página de item de Best Buy, como obteria as informações apropriadas que preciso dessa página? Como o título, preço, descrição?

Como esse processo seria chamado? Não tenho idéia de começar a pesquisar isso.

EDIT: Ok, estou executando um teste para o JSUP (o postado por Balusc), mas continuo recebendo este erro:

Exception in thread "main" java.lang.NoSuchMethodError: java.util.LinkedList.peekFirst()Ljava/lang/Object;
at org.jsoup.parser.TokenQueue.consumeWord(TokenQueue.java:209)
at org.jsoup.parser.Parser.parseStartTag(Parser.java:117)
at org.jsoup.parser.Parser.parse(Parser.java:76)
at org.jsoup.parser.Parser.parse(Parser.java:51)
at org.jsoup.Jsoup.parse(Jsoup.java:28)
at org.jsoup.Jsoup.parse(Jsoup.java:56)
at test.main(test.java:12)

Eu tenho Apache Commons

Foi útil?

Solução

Use um analisador HTML como JSUP. Isso tem minha preferência acima do Outros analisadores HTML disponíveis em Java desde que apoia jQuery Curti Seletores CSS. Além disso, sua classe representando uma lista de nós, Elements, implementos Iterable para que você possa itera sobre isso em um aprimorado para loop (Portanto, não há necessidade de incomodar com verbosos Node e NodeList como classes no analisador médio de java dom).

Aqui está um exemplo básico de pontapé inicial (basta colocar o Último arquivo JSOUP JAR em ClassPath):

package com.stackoverflow.q2835505;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Test {

    public static void main(String[] args) throws Exception {
        String url = "https://stackoverflow.com/questions/2835505";
        Document document = Jsoup.connect(url).get();

        String question = document.select("#question .post-text").text();
        System.out.println("Question: " + question);

        Elements answerers = document.select("#answers .user-details a");
        for (Element answerer : answerers) {
            System.out.println("Answerer: " + answerer.text());
        }
    }

}

Como você deve ter adivinhado, isso imprime sua própria pergunta e os nomes de todos os responsáveis.

Outras dicas

Isso é referido como raspagem de tela, a Wikipedia tem este artigo sobre o mais específico Raspagem da web. Pode ser um grande desafio, porque há algum html feio, bagunçado e quebrado, não para o navegador, por aí, tão boa sorte.

eu usaria Jtidy - É Simlar para Jsoup, mas não conheço bem o JSUP. O JTIDY lida com HTML quebrado e retorna um documento W3C, para que você possa usá -lo como fonte para XSLT para extrair o conteúdo em que está realmente interessado. Se você não conhece o XSLT, então poderá ir com o JSUP, como o documento O modelo é mais agradável de trabalhar que o W3C.

Editar: Uma rápida olhada no site do JSUP mostra que o JSUP pode realmente ser a melhor escolha. Parece suportar os seletores CSS para fora da caixa para extrair coisas do documento. Isso pode ser muito mais fácil de trabalhar do que entrar no XSLT.

Você pode usar um analisador HTML (muitos links úteis aqui: Java HTML Parser).

O processo é chamado de 'conteúdo do site pegando'. Pesquise 'Grab Website Content Java' para obter mais invertigação.

O JSUP suporta Java 1.5

https://github.com/tburch/jsoup/commit/d8ea84f46e009a7f144ee414a9fa73ea187019a3

parece que essa pilha foi um bug e foi corrigida

A solução jsoup é ótima, mas se você precisar extrair algo realmente simples, pode ser mais fácil usar regex ou string.indexof

Como outros já mencionaram, o processo é chamado de raspagem

Você provavelmente gostaria de olhar para o HTML para ver se você pode encontrar strings únicos e próximos ao seu texto, então você pode usar a linha/char-oftsets para acessar os dados.

Pode ser estranho em Java, se não houver classes XML semelhantes às encontradas em System.XML.Linq em c#.

Você também pode tentar jarvest.

É baseado em um JRUBY DSL em um mecanismo de Java puro em sites de transformação de aranha-clapear.

Exemplo:

Encontre todos os links dentro de uma página da web (wget e xpath são construções da linguagem do Jarvest):

wget | xpath('//a/@href')

Dentro de um programa Java:

Jarvest jarvest = new Jarvest();
  String[] results = jarvest.exec(
    "wget | xpath('//a/@href')", //robot! 
    "http://www.google.com" //inputs
  );
  for (String s : results){
    System.out.println(s);
  }

Minha resposta provavelmente não será útil para o escritor desta pergunta (estou com 8 meses de atraso, então não é o momento certo, eu acho), mas acho que provavelmente será útil para muitos outros desenvolvedores que podem encontrar essa resposta.

Hoje, acabei de lançar (em nome da minha empresa) um HTML para Pojo Complete Framework que você pode usar para mapear o HTML para qualquer aula de Pojo com simplesmente algumas anotações. A biblioteca em si é bastante útil e apresenta muitas outras coisas o tempo todo muito flugable. Você pode dar uma olhada aqui aqui: https://github.com/whimtrip/jwht-htmltopojo

Como usar: básico

Imagine que precisamos analisar a seguinte página HTML:

<html>
    <head>
        <title>A Simple HTML Document</title>
    </head>
    <body>
        <div class="restaurant">
            <h1>A la bonne Franquette</h1>
            <p>French cuisine restaurant for gourmet of fellow french people</p>
            <div class="location">
                <p>in <span>London</span></p>
            </div>
            <p>Restaurant n*18,190. Ranked 113 out of 1,550 restaurants</p>  
            <div class="meals">
                <div class="meal">
                    <p>Veal Cutlet</p>
                    <p rating-color="green">4.5/5 stars</p>
                    <p>Chef Mr. Frenchie</p>
                </div>

                <div class="meal">
                    <p>Ratatouille</p>
                    <p rating-color="orange">3.6/5 stars</p>
                    <p>Chef Mr. Frenchie and Mme. French-Cuisine</p>
                </div>

            </div> 
        </div>    
    </body>
</html>

Vamos criar os Pojos que queremos mapeá -lo:

public class Restaurant {

    @Selector( value = "div.restaurant > h1")
    private String name;

    @Selector( value = "div.restaurant > p:nth-child(2)")
    private String description;

    @Selector( value = "div.restaurant > div:nth-child(3) > p > span")    
    private String location;    

    @Selector( 
        value = "div.restaurant > p:nth-child(4)"
        format = "^Restaurant n\*([0-9,]+). Ranked ([0-9,]+) out of ([0-9,]+) restaurants$",
        indexForRegexPattern = 1,
        useDeserializer = true,
        deserializer = ReplacerDeserializer.class,
        preConvert = true,
        postConvert = false
    )
    // so that the number becomes a valid number as they are shown in this format : 18,190
    @ReplaceWith(value = ",", with = "")
    private Long id;

    @Selector( 
        value = "div.restaurant > p:nth-child(4)"
        format = "^Restaurant n\*([0-9,]+). Ranked ([0-9,]+) out of ([0-9,]+) restaurants$",
        // This time, we want the second regex group and not the first one anymore
        indexForRegexPattern = 2,
        useDeserializer = true,
        deserializer = ReplacerDeserializer.class,
        preConvert = true,
        postConvert = false
    )
    // so that the number becomes a valid number as they are shown in this format : 18,190
    @ReplaceWith(value = ",", with = "")
    private Integer rank;

    @Selector(value = ".meal")    
    private List<Meal> meals;

    // getters and setters

}

E agora o Meal classe também:

public class Meal {

    @Selector(value = "p:nth-child(1)")
    private String name;

    @Selector(
        value = "p:nth-child(2)",
        format = "^([0-9.]+)\/5 stars$",
        indexForRegexPattern = 1
    )
    private Float stars;

    @Selector(
        value = "p:nth-child(2)",
        // rating-color custom attribute can be used as well
        attr = "rating-color"
    )
    private String ratingColor;

    @Selector(
        value = "p:nth-child(3)"
    )
    private String chefs;

    // getters and setters.
}

Fornecemos mais algumas explicações sobre o código acima em nossa página do Github.

No momento, vamos ver como descartar isso.

private static final String MY_HTML_FILE = "my-html-file.html";

public static void main(String[] args) {


    HtmlToPojoEngine htmlToPojoEngine = HtmlToPojoEngine.create();

    HtmlAdapter<Restaurant> adapter = htmlToPojoEngine.adapter(Restaurant.class);

    // If they were several restaurants in the same page, 
    // you would need to create a parent POJO containing
    // a list of Restaurants as shown with the meals here
    Restaurant restaurant = adapter.fromHtml(getHtmlBody());

    // That's it, do some magic now!

}


private static String getHtmlBody() throws IOException {
    byte[] encoded = Files.readAllBytes(Paths.get(MY_HTML_FILE));
    return new String(encoded, Charset.forName("UTF-8"));

}

Outro pequeno exemplo pode ser encontrado aqui

Espero que isso ajude alguém lá fora!

Olhe para a biblioteca Curl. Eu nunca o usei em Java, mas tenho certeza de que deve haver ligações para isso. Basicamente, o que você fará é enviar uma solicitação de curl para qualquer página que você deseja 'raspar'. A solicitação retornará uma string com o código -fonte para a página. A partir daí, você usará Regex para analisar os dados que desejar do código -fonte. Geralmente é assim que você vai fazer isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top