ChartQuery

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 requests

Aucune 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.

Sur cette page