-
Total de itens
3978 -
Registro em
-
Última visita
-
Dias vencidos
47
Williams Duarte venceu o dia em Novembro 2 2017
Teve o conteúdo mais curtido
Reputação
431 Incrível
Sobre Williams Duarte

- Data de Nascimento 05/17/1989
Informações Pessoais
-
Sexo
Masculino
-
Interesses
Tecnologia, Engenharia de Software, PHP, Design Pattern, JavaScript, SQL, NoSQL e Empreendedorismo
Últimos Visitantes
8830780 visualizações
-
Entendi. Como a maioria dos sites de notícias utiliza WordPress, por padrão eles já possuem a tag description nos seus feeds RSS. Sobre o MSN (e outros agregadores de notícias), eles não apenas leem o feed RSS, mas também rastreiam links, sitemaps, etc. Quando o feed fornece um elemento <link>, o MSN acessa a página completa da notícia e extrai o conteúdo (título, texto, imagens) utilizando técnicas de web scraping. Eles possuem bots especializados que analisam o HTML da página e identificam o conteúdo principal através de seletores CSS ou algoritmos de extração de conteúdo. Vale ressaltar que muitos sites de notícias mantêm acordos comerciais com o MSN, fornecendo feeds mais ricos ou APIs específicas, como o endpoint "wp/v2/posts" do WordPress, que permite acesso direto ao conteúdo completo dos artigos. Quanto ao Google News, ele opera de forma diferente, priorizando a indexação e o redirecionamento para o site original, sem armazenar o conteúdo completo em seus servidores, o que preserva o tráfego direto para os publicadores. Ao trabalhar com agregação de conteúdo web, é fundamental entender como extrair dados de diferentes fontes de forma eficiente. Quando precisei implementar isso em meus projetos, desenvolvi uma abordagem simples usando PHP que funciona bem para a maioria dos casos. A ideia básica é utilizar cURL para fazer as requisições HTTP e depois processar o HTML recebido para extrair as informações relevantes. O Simple HTML DOM Parser é perfeito para isso, pois permite navegar pelo DOM usando seletores similares ao jQuery. Um ponto importante: sempre respeite o robots.txt dos sites e adicione delays entre as requisições para não sobrecarregar os servidores alheios. Também recomendo implementar um sistema de cache para evitar requisições repetidas ao mesmo conteúdo. Aqui vai um exemplo simplificado do algoritmo que uso: Lib: https://github.com/voku/simple_html_dom <?php function buscar_conteudo($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MeuBot/1.0)'); $html = curl_exec($ch); curl_close($ch); require_once 'simple_html_dom.php'; $dom = str_get_html($html); $resultado = []; // Ajuste os seletores conforme o site alvo foreach ($dom->find('article.noticia') as $artigo) { $titulo = $artigo->find('h2', 0)->plaintext; $link = $artigo->find('a', 0)->href; $resumo = $artigo->find('p.resumo', 0)->plaintext; $resultado[] = [ 'titulo' => trim($titulo), 'link' => $link, 'resumo' => trim($resumo) ]; } $dom->clear(); return $resultado; }
-
O ponto central é: como definir e usar o $novaFrase dentro do seu loop foreach ($feeds->channel->item as $item) para verificar a similaridade antes de inserir, já que é um script de importação automático. Vou te mostrar um "exemplo" de como integrar isso diretamente no seu fluxo atual. O $novaFrase será extraído de cada $item do feed (provavelmente o título ou descrição, dependendo do que você considera o "assunto"). Depois, usaremos essa variável para comparar com os registros existentes antes de decidir se faz o INSERT. Vou assumir que o campo que você quer verificar é o título ($item->title), mas você pode ajustar isso conforme a estrutura do seu feed. <?php // Conexão ao banco $conn = new mysqli("localhost", "usuario", "senha", "banco"); if ($conn->connect_error) { die("Conexão falhou: " . $conn->connect_error); } // Supondo que $feeds já foi carregado (ex.: via SimpleXML ou outro parser) foreach ($feeds->channel->item as $item) { // Definindo $novaFrase a partir do feed (ajuste conforme o campo do seu feed) $novaFrase = (string) $item->title; // Pode ser $item->description ou outro campo, se preferir // Verificação inicial: busca registros existentes para comparar $sql = "SELECT id, assunto FROM noticias"; $result = $conn->query($sql); $fraseDuplicada = false; if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { // Compara $novaFrase com cada assunto existente similar_text($novaFrase, $row['assunto'], $percentual); // Se a similaridade for alta (ex.: > 80%), considera duplicada if ($percentual > 80) { echo "Frase semelhante encontrada: " . $row['assunto'] . " (Similaridade: $percentual%)\n"; $fraseDuplicada = true; break; // Sai do loop assim que encontra uma duplicata } } } // Se não houver duplicata, insere o registro if (!$fraseDuplicada) { $stmt = $conn->prepare("INSERT INTO noticias (assunto) VALUES (?)"); $stmt->bind_param("s", $novaFrase); $stmt->execute(); echo "Novo registro inserido: $novaFrase\n"; $stmt->close(); } else { echo "Frase ignorada (duplicada): $novaFrase\n"; } } $conn->close(); Resolvendo sua dúvida específica: Ele é definido dentro do foreach, a partir do $item. No exemplo, usei $novaFrase = (string) $item->title, assumindo que o título do feed é o "assunto". Se o campo do seu feed for diferente (ex.: $item->description), basta ajustar essa linha. $novaFrase = (string) $item->title; // Se o assunto vem do título // OU $novaFrase = (string) $item->description; // Se vem da descrição No seu código atual, você mencionou que ele insere toda vez que não encontra o registro exato. Isso provavelmente acontece porque você usa algo como: $sql = "SELECT * FROM noticias WHERE assunto = ?"; E só compara igualdade exata. Com similar_text, você verifica similaridade, não igualdade, permitindo detectar frases parecidas (ex.: "Morre David Johansen" vs. "Morre, aos 75 anos, David Johansen"). - O $novaFrase é extraído de cada $item no início do loop. - Antes de inserir, o código consulta os assuntos existentes e usa similar_text para calcular a similaridade. - Só faz o INSERT se nenhuma frase semelhante for encontrada. Testando no seu caso: <channel> <item> <title>Morre David Johansen, vocalista dos New York Dolls, aos 75 anos</title> <description>Notícia completa aqui...</description> </item> <item> <title>Morre, aos 75 anos, David Johansen, do New York Dolls</title> <description>Outra versão da notícia...</description> </item> </channel> O código acima vai: - Pegar $novaFrase = "Morre David Johansen, vocalista dos New York Dolls, aos 75 anos" no primeiro item. - Verificar no banco e inserir (se for o primeiro registro). - No segundo item, $novaFrase = "Morre, aos 75 anos, David Johansen, do New York Dolls" será comparado, detectará alta similaridade (ex.: 90%) e não inserirá. Ajustes finais: - Campo do feed: Confirme qual campo do $item contém o "assunto" no seu caso (`title`, `description`, etc.) e ajuste a linha $novaFrase = (string) $item->.... - Percentual de similaridade: O valor 80 é um exemplo. Teste com valores como 70 ou 90 para ver o que funciona melhor para o seu caso. - Log: As mensagens echo são para debug. Você pode removê-las ou substituí-las por logs em um arquivo.
-
Humm, pelo que li, a função SOUNDEX do MySQL foi criada para comparar palavras simples e sua pronúncia em inglês, não serve! Mas você pode criar um índice full-text na coluna e utilizar a função MATCH … AGAINST para buscar similaridades sem precisar que a frase seja idêntica. Uma query básica seria: SELECT *, MATCH(assunto) AGAINST('Morre 75 anos David Johansen New York Dolls' IN NATURAL LANGUAGE MODE) AS relevancia FROM noticias WHERE MATCH(assunto) AGAINST('Morre 75 anos David Johansen New York Dolls' IN NATURAL LANGUAGE MODE); Essa abordagem retorna resultados com um score de relevância, ajudando a identificar notícias similares mesmo com pequenas variações. Outra abordagem é recuperar os registros do banco e utilizar funções do PHP, como similar_text ou levenshtein, para calcular a similaridade entre a nova frase e as frases existentes. Por exemplo, usando similar_text: <?php // Conexão ao banco $conn = new mysqli("localhost", "usuario", "senha", "banco"); if ($conn->connect_error) { die("Conexão falhou: " . $conn->connect_error); } // Nova frase a ser cadastrada $novaFrase = "Morre, aos 75 anos, David Johansen, do New York Dolls"; // Consulta para buscar frases existentes $sql = "SELECT id, assunto FROM noticias"; $result = $conn->query($sql); $fraseDuplicada = false; if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { // Calcular similaridade entre a nova frase e cada registro similar_text($novaFrase, $row['assunto'], $percentual); if ($percentual > 80) { // Você pode ajustar este percentual conforme a necessidade echo "Frase semelhante encontrada: " . $row['assunto']; $fraseDuplicada = true; break; } } } if (!$fraseDuplicada) { // Inserir nova frase $stmt = $conn->prepare("INSERT INTO noticias (assunto) VALUES (?)"); $stmt->bind_param("s", $novaFrase); $stmt->execute(); echo "Nova frase cadastrada com sucesso!"; $stmt->close(); } else { echo "Frase não cadastrada para evitar duplicação."; } $conn->close();
-
O sql tem a função SOUNDEX para verificar frases similares. SELECT * FROM noticias WHERE SOUNDEX(assunto) = SOUNDEX('Morre, aos 75 anos, David Johansen, do New York Dolls'); Alguns bancos suportam funções personalizadas como LEVENSHTEIN. Você pode calcular a distância entre strings diretamente no SQL e filtrar por um limite.
-
Você pode ajustar o comportamento da div para que ela pare de ser fixa ao se aproximar do rodapé, calculando a distância entre a div e o rodapé durante o scroll. Aqui está uma solução que faz isso: <script> $(function(){ var jElement = $('.fixar_banner'); var footer = $('footer'); // Substitua 'footer' pelo seletor do seu rodapé var offsetTop = jElement.offset().top; var footerOffset = footer.offset().top; var elementHeight = jElement.outerHeight(); $(window).scroll(function(){ var scrollTop = $(this).scrollTop(); var distanceToFooter = footerOffset - (scrollTop + elementHeight + 20); // 20 é um espaçamento extra if (scrollTop > offsetTop && distanceToFooter > 0) { jElement.css({ 'position': 'fixed', 'top': '10px' }); } else if (scrollTop > offsetTop && distanceToFooter <= 0) { jElement.css({ 'position': 'absolute', 'top': footerOffset - elementHeight }); } else { jElement.css({ 'position': 'relative', 'top': 'auto' }); } }); }); </script> Explicação: Cálculo das Posições: - offsetTop: É a distância inicial da div em relação ao topo da página. - footerOffset: É a distância do rodapé em relação ao topo da página. - elementHeight: É a altura da div que você quer fixar. Lógica do Scroll: 1. Quando o scroll é maior que a posição inicial da div (offsetTop) e ainda há espaço antes do rodapé (distanceToFooter > 0): - A div é fixada na posição desejada (por exemplo, top: 10px). 2. Quando a div está próxima do rodapé (distanceToFooter <= 0): - A div é posicionada de forma absoluta, alinhando-se ao topo do rodapé. 3. Caso contrário: - A div retorna à posição relativa original. Ajustes: - Certifique-se de substituir 'footer' pelo seletor correto do seu rodapé. - O valor 20 é um espaçamento extra para evitar que a div encoste no rodapé. Ajuste conforme necessário.
-
DeepSeek, a ferramenta de IA, vai tirar suas dúvidas e é gratuita ainda: https://chat.deepseek.com/
-
DeepSeek, a ferramenta de IA, vai tirar suas dúvidas e é gratuita ainda: https://chat.deepseek.com/
-
DeepSeek, a ferramenta de IA, vai tirar suas dúvidas e é gratuita ainda: https://chat.deepseek.com/
-
Na prática, existem duas abordagens principais, cada uma com seus prós e contras: Baixa após finalização da venda (Recomendado): O estoque só é atualizado quando a venda é efetivamente concluída (pagamento confirmado) Vantagens: Evita inconsistências caso a venda seja cancelada Maior segurança nas operações Histórico mais preciso de transações Desvantagens: Necessidade de verificar disponibilidade real-time durante a venda Baixa durante a inclusão dos itens: O estoque é atualizado conforme os produtos são adicionados ao carrinho Vantagens: Reserva imediata do produto Previne vendas simultâneas do mesmo item Desvantagens: Necessidade de "desfazer" as baixas em caso de cancelamento Maior complexidade no controle de transações Risco de inconsistências em caso de falhas Recomendação: Implementar a baixa após a finalização da venda, mas com um sistema de "reserva temporária" durante o processo de venda. Isso pode ser feito: // No Controller do PDV public function adicionarItem() { // Verifica disponibilidade real-time $disponivel = $this->estoque_model->verificarDisponibilidade($produto_id, $quantidade); if ($disponivel) { // Adiciona à reserva temporária $this->reserva_model->reservarProduto($produto_id, $quantidade, $venda_id); // Adiciona ao carrinho $this->venda_model->adicionarItem($produto_id, $quantidade, $venda_id); } } public function finalizarVenda($venda_id) { // Confirma o pagamento if ($this->pagamento_model->processar($venda_id)) { // Efetua a baixa real no estoque $this->estoque_model->baixarProdutos($venda_id); // Remove as reservas $this->reserva_model->limparReservas($venda_id); return true; } return false; } Esta abordagem oferece: Segurança nas operações Controle preciso do estoque Possibilidade de cancelamento sem inconsistências Prevenção de vendas duplicadas O importante é garantir que o sistema tenha tratamento adequado para: Timeout de reservas não finalizadas Cancelamentos Falhas durante o processo Concorrência de vendas
-
PHP+Codeigniter - Dúvida em Relação a Teclas
Williams Duarte respondeu ao tópico de violin101 em PHP
Normalize a tecla para minúscula const key = evt.key.toLowerCase(); -
[Resolvido] JavaScript - Exibir logo dentro da Tabela html
Williams Duarte respondeu ao tópico de violin101 em Javascript
Para exibir um logo quando a tabela estiver vazia, você pode: 1 - Adicionar uma div com o logo abaixo da tabela: <table id="tbventas"> <tbody></tbody> </table> <div id="empty-table-logo" style="text-align:center;"> <img src="caminho/logo.png" alt="Logo empresa"> </div> 2 - Controlar a visibilidade via JavaScript: // Função para verificar se tabela está vazia function checkTableEmpty() { const tbody = document.querySelector("#tbventas tbody"); const logo = document.getElementById("empty-table-logo"); if (tbody.children.length === 0) { logo.style.display = "block"; } else { logo.style.display = "none"; } } // Chamar após remover ou adicionar itens $("#tbventas tbody").append(html); checkTableEmpty(); // Na remoção de item $('.btn-remove-produto').click(function() { $(this).closest('tr').remove(); checkTableEmpty(); }); Chame checkTableEmpty() sempre que manipular a tabela para atualizar a visibilidade do logo. -
PHP+Codeigniter - Implementar o Input CÓDIGO ou ID do Produto
Williams Duarte respondeu ao tópico de violin101 em PHP
-
PHP+Codeigniter - Implementar o Input CÓDIGO ou ID do Produto
Williams Duarte respondeu ao tópico de violin101 em PHP
Primeiro, você não está declarando a variável timeoutId <script type="text/javascript"> $(document).ready(function(){ let timeoutId; // Declaração da variável $('#idProdutos').on('input', function() { clearTimeout(timeoutId); const idprd = $(this).val(); timeoutId = setTimeout(function() { if (idprd) { $.ajax({ url: "<?php echo base_url(); ?>vendas/pdvcaixa/buscarID", type: "POST", data: { idProdutos: idprd }, // Corrigido nome do parâmetro dataType: 'json', // Importante adicionar success: function(response) { if (response.success) { // Como o resultado é um array, pegamos o primeiro item if (response.produto.length > 0) { $("#descricao").val(response.produto[0].descricao); } } }, error: function(xhr, status, error) { console.log('Erro:', error); } }); } }, 1500); }); }); </script> No Controller, ajuste para: public function buscarID() { $idprd = $this->input->post('idProdutos'); $produto = $this->pdvcaixa_model->buscarCodigo($idprd); if ($produto) { echo json_encode([ 'success' => true, 'produto' => $produto ]); } else { echo json_encode([ 'success' => false, 'message' => 'Produto não encontrado' ]); } } Se ainda assim não funcionar, você pode adicionar alguns console.log para debug: $('#idProdutos').on('input', function() { console.log('Input detectado'); clearTimeout(timeoutId); const idprd = $(this).val(); console.log('Valor digitado:', idprd); timeoutId = setTimeout(function() { console.log('Timeout executado'); if (idprd) { // ... resto do código -
PHP+Codeigniter - Implementar o Input CÓDIGO ou ID do Produto
Williams Duarte respondeu ao tópico de violin101 em PHP
Para implementar a busca automática com delay de 1-2 segundos sem precisar do ENTER, você pode usar jQuery junto com CodeIgniter. Segue um exemplo simples: $('#codigo_produto').on('input', function() { clearTimeout(timeoutId); const codigo = $(this).val(); timeoutId = setTimeout(function() { if (codigo) { $.ajax({ url: '<?= base_url("produtos/buscar") ?>', type: 'POST', data: { codigo: codigo }, success: function(response) { // Exibe o resultado if (response.success) { $('#resultado').html(response.produto.descricao); } } }); } }, 1500); // 1.5 segundos de delay }); No seu controller: public function buscar() { $codigo = $this->input->post('codigo'); $produto = $this->produtos_model->buscar_por_codigo($codigo); echo json_encode([ 'success' => true, 'produto' => $produto ]); } O código acima vai esperar 1.5 segundos após o usuário parar de digitar antes de fazer a busca. Você pode ajustar o delay alterando o valor 1500 para qualquer outro valor em milissegundos. -
PHP+Codeigniter - Adicionar Registro Plano de Contas
Williams Duarte respondeu ao tópico de violin101 em PHP