Surveiller Google News
Mettez en place un pipeline d'alertes d'actualités par marque ou mot-clé qui collecte et déduplique les articles Google News en temps réel avec l'API Autom.
Vue d'ensemble
Ce guide construit un pipeline de veille médiatique : interrogez Google News pour un nom de marque, un produit ou un sujet et collectez tous les titres d'articles, sources et dates de publication. Exécutez-le sur un cron pour détecter la couverture presse dès qu'elle apparaît.
Prérequis
- Une clé API Autom — obtenez-en une sur app.autom.dev
- Installez les dépendances pour votre langage :
pip install requestsAucune dépendance supplémentaire — utilise l'API native fetch (Node 18+).
Extension curl activée (par défaut dans la plupart des installations PHP).
Aucune dépendance supplémentaire — utilise la bibliothèque standard net/http (Go 1.18+).
Aucune dépendance supplémentaire — utilise java.net.http (Java 11+).
Aucune dépendance supplémentaire — utilise System.Net.Http (.NET 6+).
# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"Étapes
Récupérer les derniers articles
Appelez GET /v1/google/news avec le mot-clé que vous souhaitez surveiller.
import requests
API_KEY = "YOUR_API_KEY"
response = requests.get(
"https://api.autom.dev/v1/google/news",
headers={"x-api-key": API_KEY},
params={"q": "OpenAI", "gl": "us", "hl": "en"},
)
data = response.json()const API_KEY = "YOUR_API_KEY";
const params = new URLSearchParams({ q: "OpenAI", gl: "us", hl: "en" });
const response = await fetch(`https://api.autom.dev/v1/google/news?${params}`, {
headers: { "x-api-key": API_KEY },
});
const data = await response.json();<?php
$apiKey = "YOUR_API_KEY";
$params = http_build_query(["q" => "OpenAI", "gl" => "us", "hl" => "en"]);
$ch = curl_init("https://api.autom.dev/v1/google/news?{$params}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-api-key: {$apiKey}"]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);package main
import (
"encoding/json"
"io"
"net/http"
"net/url"
)
func main() {
params := url.Values{"q": {"OpenAI"}, "gl": {"us"}, "hl": {"en"}}
req, _ := http.NewRequest("GET", "https://api.autom.dev/v1/google/news?"+params.Encode(), nil)
req.Header.Set("x-api-key", "YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var data map[string]any
json.Unmarshal(body, &data)
}import java.net.URI;
import java.net.http.*;
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.autom.dev/v1/google/news?q=OpenAI&gl=us&hl=en"))
.header("x-api-key", "YOUR_API_KEY")
.GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());using System.Net.Http;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY");
var body = await client.GetStringAsync(
"https://api.autom.dev/v1/google/news?q=OpenAI&gl=us&hl=en");
Console.WriteLine(body);#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let data = reqwest::Client::new()
.get("https://api.autom.dev/v1/google/news")
.header("x-api-key", "YOUR_API_KEY")
.query(&[("q", "OpenAI"), ("gl", "us"), ("hl", "en")])
.send().await?
.json::<serde_json::Value>().await?;
println!("{:#?}", data);
Ok(())
}Extraire et afficher les articles
Chaque élément dans organic_results possède title, link, source, date et snippet.
for article in data.get("organic_results", []):
print(f"[{article['date']}] {article['title']}")
print(f" Source : {article['source']}")
print(f" URL : {article['link']}\n")for (const article of data.organic_results ?? []) {
console.log(`[${article.date}] ${article.title}`);
console.log(` Source : ${article.source}`);
console.log(` URL : ${article.link}\n`);
}foreach ($data["organic_results"] ?? [] as $article) {
echo "[{$article['date']}] {$article['title']}\n";
echo " Source : {$article['source']}\n";
echo " URL : {$article['link']}\n\n";
}results := data["organic_results"].([]any)
for _, r := range results {
a := r.(map[string]any)
fmt.Printf("[%s] %s\n Source : %s\n URL : %s\n\n",
a["date"], a["title"], a["source"], a["link"])
}import org.json.*;
var json = new JSONObject(response.body());
var results = json.getJSONArray("organic_results");
for (int i = 0; i < results.length(); i++) {
var a = results.getJSONObject(i);
System.out.printf("[%s] %s%n Source : %s%n URL : %s%n%n",
a.getString("date"), a.getString("title"),
a.getString("source"), a.getString("link"));
}using System.Text.Json;
var json = JsonDocument.Parse(body);
var results = json.RootElement.GetProperty("organic_results").EnumerateArray();
foreach (var a in results)
{
Console.WriteLine($"[{a.GetProperty("date")}] {a.GetProperty("title")}");
Console.WriteLine($" Source : {a.GetProperty("source")}");
Console.WriteLine($" URL : {a.GetProperty("link")}\n");
}if let Some(articles) = data["organic_results"].as_array() {
for a in articles {
println!("[{}] {}", a["date"].as_str().unwrap_or(""), a["title"].as_str().unwrap_or(""));
println!(" Source : {}", a["source"].as_str().unwrap_or(""));
println!(" URL : {}\n", a["link"].as_str().unwrap_or(""));
}
}Construire un pipeline de surveillance avec déduplication
Stockez les URLs d'articles déjà vus pour que les exécutions répétées ne produisent pas d'alertes en double.
import json, requests
from pathlib import Path
API_KEY = "YOUR_API_KEY"
KEYWORDS = ["OpenAI", "Anthropic", "Mistral AI"]
SEEN_FILE = Path("seen_articles.json")
def load_seen() -> set:
return set(json.loads(SEEN_FILE.read_text())) if SEEN_FILE.exists() else set()
def save_seen(seen: set) -> None:
SEEN_FILE.write_text(json.dumps(list(seen)))
def fetch_news(query: str) -> list:
r = requests.get("https://api.autom.dev/v1/google/news",
headers={"x-api-key": API_KEY}, params={"q": query, "gl": "us", "hl": "en"})
return r.json().get("organic_results", [])
seen = load_seen()
new_articles = []
for keyword in KEYWORDS:
for article in fetch_news(keyword):
if article["link"] not in seen:
seen.add(article["link"])
new_articles.append({**article, "keyword": keyword})
save_seen(seen)
print(f"Trouvé {len(new_articles)} nouvel(s) article(s) :")
for a in new_articles:
print(f" [{a['keyword']}] {a['title']} — {a['source']}")import { readFileSync, writeFileSync, existsSync } from "fs";
const API_KEY = "YOUR_API_KEY";
const KEYWORDS = ["OpenAI", "Anthropic", "Mistral AI"];
const SEEN_FILE = "seen_articles.json";
function loadSeen(): Set<string> {
return existsSync(SEEN_FILE)
? new Set(JSON.parse(readFileSync(SEEN_FILE, "utf-8")))
: new Set();
}
async function fetchNews(query: string): Promise<any[]> {
const params = new URLSearchParams({ q: query, gl: "us", hl: "en" });
const res = await fetch(`https://api.autom.dev/v1/google/news?${params}`, {
headers: { "x-api-key": API_KEY },
});
return (await res.json()).organic_results ?? [];
}
const seen = loadSeen();
const newArticles: any[] = [];
for (const keyword of KEYWORDS) {
for (const article of await fetchNews(keyword)) {
if (!seen.has(article.link)) {
seen.add(article.link);
newArticles.push({ ...article, keyword });
}
}
}
writeFileSync(SEEN_FILE, JSON.stringify([...seen]));
console.log(`Trouvé ${newArticles.length} nouvel(s) article(s) :`);
for (const a of newArticles) console.log(` [${a.keyword}] ${a.title} — ${a.source}`);<?php
$apiKey = "YOUR_API_KEY";
$keywords = ["OpenAI", "Anthropic", "Mistral AI"];
$seenFile = "seen_articles.json";
$seen = file_exists($seenFile) ? array_flip(json_decode(file_get_contents($seenFile), true)) : [];
$newArticles = [];
foreach ($keywords as $keyword) {
$params = http_build_query(["q" => $keyword, "gl" => "us", "hl" => "en"]);
$ch = curl_init("https://api.autom.dev/v1/google/news?{$params}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-api-key: {$apiKey}"]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
foreach ($data["organic_results"] ?? [] as $article) {
if (!isset($seen[$article["link"]])) {
$seen[$article["link"]] = true;
$newArticles[] = array_merge($article, ["keyword" => $keyword]);
}
}
}
file_put_contents($seenFile, json_encode(array_keys($seen)));
echo "Trouvé " . count($newArticles) . " nouvel(s) article(s) :\n";
foreach ($newArticles as $a) echo " [{$a['keyword']}] {$a['title']} — {$a['source']}\n";package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
)
func fetchNews(apiKey, query string) []map[string]any {
params := url.Values{"q": {query}, "gl": {"us"}, "hl": {"en"}}
req, _ := http.NewRequest("GET", "https://api.autom.dev/v1/google/news?"+params.Encode(), nil)
req.Header.Set("x-api-key", apiKey)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var data map[string]any
json.Unmarshal(body, &data)
var out []map[string]any
for _, r := range data["organic_results"].([]any) {
out = append(out, r.(map[string]any))
}
return out
}
func main() {
apiKey := "YOUR_API_KEY"
keywords := []string{"OpenAI", "Anthropic", "Mistral AI"}
seen := map[string]bool{}
if b, err := os.ReadFile("seen_articles.json"); err == nil {
var links []string
json.Unmarshal(b, &links)
for _, l := range links { seen[l] = true }
}
var newCount int
for _, kw := range keywords {
for _, a := range fetchNews(apiKey, kw) {
link := a["link"].(string)
if !seen[link] {
seen[link] = true
fmt.Printf(" [%s] %s — %s\n", kw, a["title"], a["source"])
newCount++
}
}
}
links := make([]string, 0, len(seen))
for l := range seen { links = append(links, l) }
b, _ := json.Marshal(links)
os.WriteFile("seen_articles.json", b, 0644)
fmt.Printf("Trouvé %d nouvel(s) article(s).\n", newCount)
}import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import org.json.*;
public class Main {
static HttpClient client = HttpClient.newHttpClient();
static String API_KEY = "YOUR_API_KEY";
public static void main(String[] args) throws Exception {
var keywords = List.of("OpenAI", "Anthropic", "Mistral AI");
var seenPath = Path.of("seen_articles.json");
var seen = new HashSet<String>();
if (Files.exists(seenPath)) {
var arr = new JSONArray(Files.readString(seenPath));
for (int i = 0; i < arr.length(); i++) seen.add(arr.getString(i));
}
int newCount = 0;
for (var kw : keywords) {
var q = URLEncoder.encode(kw, StandardCharsets.UTF_8);
var url = "https://api.autom.dev/v1/google/news?q=" + q + "&gl=us&hl=en";
var req = HttpRequest.newBuilder().uri(URI.create(url))
.header("x-api-key", API_KEY).GET().build();
var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
var results = new JSONObject(resp.body()).getJSONArray("organic_results");
for (int i = 0; i < results.length(); i++) {
var a = results.getJSONObject(i);
var link = a.getString("link");
if (!seen.contains(link)) {
seen.add(link);
System.out.printf(" [%s] %s — %s%n", kw, a.getString("title"), a.getString("source"));
newCount++;
}
}
}
Files.writeString(seenPath, new JSONArray(seen).toString());
System.out.println("Trouvé " + newCount + " nouvel(s) article(s).");
}
}using System.Net.Http;
using System.Text.Json;
var apiKey = "YOUR_API_KEY";
var keywords = new[] { "OpenAI", "Anthropic", "Mistral AI" };
var seenFile = "seen_articles.json";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", apiKey);
var seen = File.Exists(seenFile)
? JsonSerializer.Deserialize<HashSet<string>>(File.ReadAllText(seenFile))!
: new HashSet<string>();
int newCount = 0;
foreach (var keyword in keywords)
{
var url = $"https://api.autom.dev/v1/google/news?q={Uri.EscapeDataString(keyword)}&gl=us&hl=en";
var body = await client.GetStringAsync(url);
var json = JsonDocument.Parse(body).RootElement;
foreach (var a in json.GetProperty("organic_results").EnumerateArray())
{
var link = a.GetProperty("link").GetString()!;
if (seen.Add(link))
{
Console.WriteLine($" [{keyword}] {a.GetProperty("title")} — {a.GetProperty("source")}");
newCount++;
}
}
}
File.WriteAllText(seenFile, JsonSerializer.Serialize(seen));
Console.WriteLine($"Trouvé {newCount} nouvel(s) article(s).");use reqwest::Client;
use serde_json::Value;
use std::{collections::HashSet, fs, path::Path};
async fn fetch_news(client: &Client, api_key: &str, query: &str) -> Vec<Value> {
let data = client
.get("https://api.autom.dev/v1/google/news")
.header("x-api-key", api_key)
.query(&[("q", query), ("gl", "us"), ("hl", "en")])
.send().await.unwrap().json::<Value>().await.unwrap();
data["organic_results"].as_array().cloned().unwrap_or_default()
}
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let api_key = "YOUR_API_KEY";
let keywords = ["OpenAI", "Anthropic", "Mistral AI"];
let seen_path = Path::new("seen_articles.json");
let mut seen: HashSet<String> = if seen_path.exists() {
serde_json::from_str::<Vec<String>>(&fs::read_to_string(seen_path).unwrap())
.unwrap().into_iter().collect()
} else { HashSet::new() };
let mut new_count = 0;
for keyword in &keywords {
for article in fetch_news(&client, api_key, keyword).await {
let link = article["link"].as_str().unwrap_or("").to_string();
if seen.insert(link) {
println!(" [{}] {} — {}", keyword, article["title"].as_str().unwrap_or(""), article["source"].as_str().unwrap_or(""));
new_count += 1;
}
}
}
let seen_vec: Vec<&String> = seen.iter().collect();
fs::write(seen_path, serde_json::to_string(&seen_vec).unwrap()).unwrap();
println!("Trouvé {new_count} nouvel(s) article(s).");
Ok(())
}Planifiez ce script avec un cron (ex. toutes les heures) ou un planificateur de tâches pour une surveillance continue. Combinez plusieurs mots-clés en une seule exécution pour minimiser la consommation de crédits.