Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Preciso fazer uma busca antes de inserir um registro no banco de dados.
No caso preciso verificar se existe uma frase no banco antes de cadastrar uma nova.
Exemplo:
Tenho no banco a coluna ASSUNTO = "Morre David Johansen, vocalista dos New York Dolls, aos 75 anos".
Quando vou cadastrar uma nova notícia "Morre, aos 75 anos, David Johansen, do New York Dolls" é parecida. Mas não quero cadastrar 2 vezes.
No like não consigo fazer esta busca.... o que posso fazer para verificar esta busca antes de cadastrar ?
Tentei colocar uma frase diferente e não encontrou...
Cheguei a retirar algumas palavras mesmo assim não encontrou.. (Só encontra colocando exatamente igual).
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$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();Muito obrigado
Boa tarde,
Via php, não estou conseguindo pegar a string da nova noticia.
Estou lendo um arquivo FEED, e quando leio ele pego o tópico (ASSUNTO) e insiro no banco.
Dessa forma não tenho um formulario para inserir a noticia e comparar a mesma.
Obs: O sql do banco tem algo errado, mas preciso resolver por php mesmo.
Obrigado
>
Em 04/03/2025 at 17:11, Williams Duarte disse:
No caso o parametro $novafrase, ficaria como no código ?
eu utilizo:
foreach ($feeds->channel->item as $item)
Faço um loop em tudo e vou gravando registro por registro. a unica verificação é se existe o assunto, se não tiver ele registra um novo na base.
No caso ele faz um INSERT toda vez que não tiver o registro encontrado.
E este é o problema, não sei onde consigo verificar o "$novafrase" para inserir. pois é só um script de importação.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:**
>
Citar
Onde o $novaFrase entra no código?
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
>
Citar
Como evitar o INSERT automático?
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").
>
Citar
Integração no loop
- 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.
Muito obrigado !
Antes de inserir no banco vou fazer um while na tabela procurando duplicidade.
Caso encronte eu controlo com break, do contrário eu insiro no banco.
Vou verificar a data tb. Para não ficar fazendo a verificação do while depois de 2h da primeira postagem.
Assim fica mais rápido a execução do script.
A maioria dos feeds rss, não tem descrição.
Não entendo como o portal msn consegue pegar a notícia e postar no site deles mesmo..
Já o google news não tem descrição, redireciona somente o tópico.
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;
}show de bola.
Por exemplo, o site do SBT. Não encontrei nenhum feed nele, porém o google consegue importar o topico.
Deve ser acordo como você postou.
Obrigado !
O sql tem a função SOUNDEX para verificar frases similares.
SELECT *
FROM noticias