PDFBox - Aplicativo Java para baixar o DOU completo

O DOU - Diário Oficial da União - é um periódico muito importante, que divulga informações valiosas para os profissionais da área de consultoria, advocacia e contabilidade, como Legislação, por exemplo. Vamos baixar o DOU da forma que normalmente seria possível e, depois, usar essa API para juntar os arquivos PDF baixados em um único arquivo.

[ Hits: 17.318 ]

Por: Pedro Ferrarezi em 20/11/2013


Codificação final



Para deixar o código principal mais limpo e fácil de entender, vamos criar algumas funções auxiliares e deixá-las antes do fim da classe principal, ou seja, antes da ultima chave (}).

Insira as funções abaixo:

//########### funções auxiliares ############

    private void downloadDow(int jornal, final String DATA){

        //variável tipo bool para apagar os arquivos individuais
        boolean delFiles = !jCheckBox6.isSelected();
        //objeto tipo Lista para guardar o caminho e nome de cad arquivo baixado
        ArrayList<String> downloadedFiles = new ArrayList();

        //link para o site da imprensa nacional que mostra o número de páginas de cada caderno
        String link = "http://www.in.gov.br/visualiza/index.jsp?jornal="+jornal+"&pagina=1&data="+DATA;
        //captura o código fonte HTML do link acima, algo como vizualizar o código fonte da página no browser.
        String fonte_html = getHtmlCode(link).toString();
        //pega número de páginas do jornal
        int numPgs = Integer.parseInt(
                fonte_html.substring(fonte_html.indexOf("totalArquivos=")+14, fonte_html.indexOf("\" scrolling")).trim()
            );

        //Download página por página
        try{
            for(int i=1; i<numPgs+1; i++){
                //atualiza o label3 com o progresso atual
                jLabel3.setText("Baixando DOU "+jornal+" página "+i+" de "+numPgs);
                //nome do arquivo invidual
                String fileName = jTextField2.getText()+"pg_"+i+"_dou_"+jornal+".pdf";
                //stream para o arquivo PDF do site
                FileOutputStream output = new FileOutputStream(fileName);
                //link para o site da imprensa nacional de onde os cadernos/jornais serão baixados
                String site = "http://www.in.gov.br/servlet/INPDFViewer?jornal="+jornal+"&pagina="+i+"&data="+DATA+"&captchafield=firistAccess";
                URL url = new URL(site);

                //cria uma conexão HTTP e um buffer de dados contendo o PDF em si
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                BufferedInputStream input = new BufferedInputStream(conn.getInputStream());

                byte[] buf = new byte[4096];
                int len;
                //baixa o PDF
                while ( (len = input.read(buf)) > 0 )
                    output.write(buf, 0, len);

                conn.disconnect();
                input.close();
                output.close();

                //adiciona o nome do PDF baixado a uma lista de exclusão
                if(delFiles)
                    downloadedFiles.add(fileName);
            }

            //Mescla os arquivos em 1 único
            List<InputStream> sourcePDFs = new ArrayList<InputStream>();
            final String OUTPT_FILENAME = "DOU_"+DATA.replace("/", ".")+"_Jornal_"+jornal+".pdf";

            for(int i=1; i<numPgs+1; i++){
                 jLabel3.setText("Aguarde... Criando "+OUTPT_FILENAME);
                 String fileName = jTextField2.getText()+"pg_"+i+"_dou_"+jornal+".pdf";
                 sourcePDFs.add(new FileInputStream(new File(fileName)));
            }

            //mescla
            PDFMergerUtility mergerUtility = new PDFMergerUtility();
            mergerUtility.addSources(sourcePDFs);
            mergerUtility.setDestinationFileName(jTextField2.getText()+OUTPT_FILENAME);
            mergerUtility.mergeDocuments();

            //Apaga os arquivos individuais se o jCheckBox6 estiver desmarcado
            for(String sfile: downloadedFiles){
                new File(sfile).delete();
            }
        }catch(Exception e){e.printStackTrace();}
    }

    final public File chooseFolder(){
        //seleciona a pasta onde os arquivos PDF serão baixados
        File file = null;
        JFileChooser fc = new JFileChooser();
        fc.setDialogTitle("Selecione o diretório.");
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fc.setMultiSelectionEnabled(false);
        if (fc.showOpenDialog(null) != JFileChooser.CANCEL_OPTION)
            file = fc.getSelectedFile();
        else file = null;
        return file;
    }

    public static StringBuilder getHtmlCode(String endereco) {
        //pega o "código fonte" em HTML da página e salva em um objeto tipo StringBuilder
        BufferedReader in = null;
        StringBuilder ret = new StringBuilder("");
        try {
            URL url = new URL(endereco);
            in = new BufferedReader(new InputStreamReader(url.openStream()));
            String str;
            while ((str = in.readLine()) != null) {
                ret.append(str);
            }
        } catch (Exception ex) {  ex.printStackTrace(); }
        finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
        return ret;
    }

    private void ajeitaForm(){
        this.setLocationRelativeTo(null);
        jLabel3.setVisible(false);
        jProgressBar1.setVisible(false);
    }

    private void marcaTodos() {
        if(jCheckBox1.isSelected()){
            jCheckBox2.setSelected(true);
            jCheckBox3.setSelected(true);
            jCheckBox4.setSelected(true);
            jCheckBox5.setSelected(true);
        } else{
            jCheckBox2.setSelected(false);
            jCheckBox3.setSelected(false);
            jCheckBox4.setSelected(false);
            jCheckBox5.setSelected(false);
        }
    }

     private void terminado() {
        jProgressBar1.setVisible(false);
        jLabel3.setVisible(false);
        jTextField1.setEditable(true);
        jPanel2.setVisible(true);
        jButton1.setEnabled(true);
        jButton2.setVisible(true);
        jCheckBox6.setVisible(true);
        JOptionPane.showMessageDialog(rootPane, "Processo concluído!");
    }

     private void preparaFrame() {
        jProgressBar1.setValue(0);
        jProgressBar1.setVisible(true);
        jLabel3.setVisible(true);
        //não queremos que o usuário clique nisso durante o processo:
        jTextField1.setEditable(false);
        jPanel2.setVisible(false);
        jButton1.setEnabled(false);
        jButton2.setVisible(false);
        jCheckBox6.setVisible(false);
    }

    private boolean verificaFrame() {
        //verifica se a data do DOU foi informada
        if(jTextField1.getText().equals("")){
            JOptionPane.showMessageDialog(null, "Primeiro informe a data!");
            jTextField1.grabFocus();
            return false;
            //verifica se pelo menos 1 caderno foi selecionado
        } else if(jCheckBox2.isSelected()==false && jCheckBox3.isSelected()==false &&
                jCheckBox4.isSelected()==false && jCheckBox5.isSelected()==false){
            JOptionPane.showMessageDialog(null, "Informe uma seção do DOU para baixar!");
            return false;
        } else if(jTextField2.getText().equals("Selecione a pasta:")){
            JOptionPane.showMessageDialog(null, "Informe a pasta de destino!");
            return false;
        }
        return true;
    }



Depois de colado este código, vá até o construtor da classe a chame a função ajeitaForm(). Seu construtor deve ficar como abaixo:

/** Creates new form frame */
    public frame() {
        initComponents();
        ajeitaForm();
    }

Agora, queremos que quando o usuário clique no botão BAIXAR D.O.U, todo o processo aconteça automaticamente:
  • Download dos DOU 1 por 1;
  • Criação de 1 pra cada jornal selecionado;
  • Apagamento ou não dos PDFs individuais, com barra de progresso e status.

Para isso, volte até a parte visual do seu projeto e dê um duplo clique no botão BAIXAR D.O.U. O NetBeans deve criar uma função automaticamente, conforme abaixo, e te mandar para o código de volta:

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
               // TODO add your handling code here:
}

Dentro da função acima, vamos chamar a função verificaFrame() e depois criar um SwingWorker, para que a barra de progresso possa funcionar, caso contrário, ela ficará congelada durante todo o processo e será inútil.

Antes de iniciar o processo, precisamos esconder/desabilitar tudo o que não queremos que o usuário mexa enquanto o programa estiver funcionando, pois a curiosidade matou o gato, por isso, chamaremos a função preparaFrame(). Depois de tudo terminado, habilitaremos tudo para que ele possa baixar outro DOU caso queira.

Seu código dentro da função jButton2ActionPerformed(), gerada automaticamente deve ser conforme abaixo:

// checa o preenchimento
       if( verificaFrame() == false)
           return;

        //começa proceço:
        new SwingWorker() {
            @Override
            protected Object doInBackground() throws Exception {
                try{
                    preparaFrame();
                    final String DATA = jTextField1.getText();
                    boolean jn1= false, jn2= false, jn3= false, jn1000= false;
                    if(jCheckBox2.isSelected()) jn1 = true;
                    if(jCheckBox3.isSelected()) jn2 = true;
                    if(jCheckBox4.isSelected()) jn3 = true;
                    if(jCheckBox5.isSelected()) jn1000 = true;

                    //faz download dos DOU selecionados
                    if(jn1){ downloadDow(1, DATA); }
                    jProgressBar1.setValue(25);
                    if(jn2){ downloadDow(2, DATA); }
                    jProgressBar1.setValue(50);
                    if(jn3){ downloadDow(3, DATA); }
                    jProgressBar1.setValue(75);
                    if(jn1000){ downloadDow(1000, DATA); }
                    jProgressBar1.setValue(100);
                }catch(Exception e ){
                    e.printStackTrace();
                    jProgressBar1.setValue(100);
                }
                return null;
            }
            @Override
            protected void done() {
                terminado();
            }
        }.execute();

Por último, faça o mesmo que foi feito com o jButton2 com o jButton1, e insira este código para que o usuário possa escolher onde salvar os DOUs baixados:

        File f = chooseFolder();
                if(f!=null) jTextField2.setText(f.getAbsolutePath()+"\\");

E chame marcaTodos() na jCheckBox1, quando for marcada ou desmarcada.

Seu código entre a função jButton2ActionPerformed() e as declarações de variáveis globais geradas automaticamente pelo NetBeans, deve se parecer com isso:

   private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
        File f = chooseFolder();
        if(f!=null) jTextField2.setText(f.getAbsolutePath()+"\\");
   }

   private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {
        marcaTodos();
   }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new frame().setVisible(true);
            }
        });
    }

Feito isso, basta compilar o programa e distribuí-lo com cada API PDFBox. Para facilitar o processo de distribuição, sugiro ver minha dica:
Para visualizar o código fonte completo deste artigo, visite meu blog:
Abraço a todos e muito obrigado.

Página anterior    

Páginas do artigo
   1. Introdução / Projeto
   2. Codificação final
Outros artigos deste autor

Monitorando produtos no ML com Python 3 via BeautifulSoup

Leitura recomendada

Trabalhando com classes e métodos em Java (parte 2)

Testes unitários em Java com JUnit

GCJ – Conhecendo o compilador Java Livre

Desenvolvendo aplicações Web 2.0 com Java e AJAX (FrameWork DWR)

Funções Completas - Comunicação entre aplicações Android e FTP

  
Comentários
[1] Comentário enviado por removido em 20/11/2013 - 14:33h

Chatinho pra configurar.
Mas depois, vai! E muito bem.

Facilitou a vida!

[2] Comentário enviado por Lisandro em 21/11/2013 - 07:24h

Gostei muito. Valeu!

[3] Comentário enviado por Buckminster em 02/12/2013 - 01:52h

Muito bom. Parabéns.

Vou testar.

[4] Comentário enviado por leorocco em 12/02/2014 - 15:23h

Muito obrigado!!!

Porém, ao clicar no botão para baixar o DOU recebo o seguinte erro no console:

java.io.FileNotFoundException: http://portal.in.gov.br/visualiza/index.jsp?jornal=1&pagina=1&data=14/10/2013
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1624)


tem alguma coisa errada com o código ou eles mudaram algum parâmetro para visualizar as páginas?

Valeu! :)

[5] Comentário enviado por leorocco em 17/02/2014 - 15:00h

Eles mudaram a URL da página. Resolvei o problema alterando a variável "Link". Porém os PDFs estão vindo corrompidos, impossível de visualizar. Estou usando a versão 1.8.3 do PDFBox. Será que é isso? Muito obrigado por compartilhar :]

[6] Comentário enviado por Alexsander71 em 16/01/2015 - 17:42h


Está muito TOP !! Mas queria uma ajudinha mais... Preciso baixar o DOU de um período, tipo... queria baixar todos os DOU do mês de NOV / 2014. Alguém pode dar uma ajuda!?


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts