Extraer resultados de Google Search
Crea un script de monitoreo SERP que rastrea posiciones de palabras clave y extrae resultados orgánicos con la API de Autom.
Descripción general
En este tutorial construirás un script que consulta Google Search y extrae resultados orgánicos estructurados — posiciones, títulos, URLs y fragmentos — para cualquier palabra clave. Un caso de uso típico es el rastreo de posiciones: ejecútalo periódicamente para monitorear dónde aparecen tus páginas para las palabras clave objetivo.
El endpoint devuelve hasta 10 resultados orgánicos por página y admite paginación, segmentación por país (gl) e idioma (hl).
Prerrequisitos
- Una clave de API de Autom — consigue una en app.autom.dev
- Instala las dependencias para tu lenguaje:
pip install requestsSin dependencias adicionales — usa la API nativa fetch (Node 18+).
Extensión curl habilitada (activa por defecto en la mayoría de instalaciones PHP).
Sin dependencias adicionales — usa la biblioteca estándar net/http (Go 1.18+).
Sin dependencias adicionales — usa java.net.http (Java 11+).
Sin dependencias adicionales — usa System.Net.Http (.NET 6+).
# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"Pasos
Realiza tu primera búsqueda
Llama a GET /v1/google/search con el parámetro q y tu clave de API en el encabezado x-api-key.
import requests
API_KEY = "YOUR_API_KEY"
response = requests.get(
"https://api.autom.dev/v1/google/search",
headers={"x-api-key": API_KEY},
params={"q": "mejores librerías Python para web scraping", "gl": "es", "hl": "es"},
)
data = response.json()
print(data)const API_KEY = "YOUR_API_KEY";
const params = new URLSearchParams({
q: "mejores librerías Python para web scraping",
gl: "es",
hl: "es",
});
const response = await fetch(
`https://api.autom.dev/v1/google/search?${params}`,
{ headers: { "x-api-key": API_KEY } },
);
const data = await response.json();
console.log(data);<?php
$apiKey = "YOUR_API_KEY";
$params = http_build_query([
"q" => "mejores librerías Python para web scraping",
"gl" => "es",
"hl" => "es",
]);
$ch = curl_init("https://api.autom.dev/v1/google/search?{$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);
print_r($data);package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
params := url.Values{}
params.Set("q", "mejores librerías Python para web scraping")
params.Set("gl", "es")
params.Set("hl", "es")
req, _ := http.NewRequest("GET",
"https://api.autom.dev/v1/google/search?"+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)
fmt.Println(data)
}import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
var apiKey = "YOUR_API_KEY";
var q = URLEncoder.encode("mejores librerías Python para web scraping", StandardCharsets.UTF_8);
var url = "https://api.autom.dev/v1/google/search?q=" + q + "&gl=es&hl=es";
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder().uri(URI.create(url))
.header("x-api-key", apiKey).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/search?q=mejores+librerias+Python&gl=es&hl=es");
Console.WriteLine(body);#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let response = reqwest::Client::new()
.get("https://api.autom.dev/v1/google/search")
.header("x-api-key", "YOUR_API_KEY")
.query(&[("q", "mejores librerías Python para web scraping"), ("gl", "es"), ("hl", "es")])
.send().await?.json::<serde_json::Value>().await?;
println!("{:#?}", response);
Ok(())
}Analiza los resultados orgánicos
La respuesta contiene un array organic_results. Cada entrada tiene position, title, link, snippet, domain y source.
for result in data["organic_results"]:
print(f"[{result['position']}] {result['title']}")
print(f" URL: {result['link']}")
print(f" {result.get('snippet', '')}")
print()for (const result of data.organic_results) {
console.log(`[${result.position}] ${result.title}`);
console.log(` URL: ${result.link}`);
console.log(` ${result.snippet ?? ""}`);
console.log();
}foreach ($data["organic_results"] as $result) {
echo "[{$result['position']}] {$result['title']}\n";
echo " URL: {$result['link']}\n";
echo " " . ($result['snippet'] ?? "") . "\n\n";
}results := data["organic_results"].([]any)
for _, r := range results {
item := r.(map[string]any)
fmt.Printf("[%.0f] %s\n", item["position"], item["title"])
fmt.Printf(" URL: %s\n", item["link"])
fmt.Printf(" %s\n\n", item["snippet"])
}import org.json.*;
var json = new JSONObject(response.body());
var results = json.getJSONArray("organic_results");
for (int i = 0; i < results.length(); i++) {
var r = results.getJSONObject(i);
System.out.printf("[%d] %s%n URL: %s%n%n",
r.getInt("position"), r.getString("title"), r.getString("link"));
}using System.Text.Json;
var json = JsonDocument.Parse(body);
var results = json.RootElement.GetProperty("organic_results").EnumerateArray();
foreach (var result in results)
{
Console.WriteLine($"[{result.GetProperty("position")}] {result.GetProperty("title")}");
Console.WriteLine($" URL: {result.GetProperty("link")}");
Console.WriteLine();
}if let Some(results) = response["organic_results"].as_array() {
for result in results {
println!("[{}] {}", result["position"], result["title"].as_str().unwrap_or(""));
println!(" URL: {}", result["link"].as_str().unwrap_or(""));
println!(" {}", result["snippet"].as_str().unwrap_or(""));
println!();
}
}Gestiona la paginación
Usa el parámetro page para obtener páginas siguientes. La respuesta incluye un objeto pagination con has_next_page y el número de página next.
import requests
API_KEY = "YOUR_API_KEY"
QUERY = "mejores librerías Python para web scraping"
def fetch_all_results(query: str, max_pages: int = 3) -> list:
all_results = []
page = 1
while page <= max_pages:
response = requests.get(
"https://api.autom.dev/v1/google/search",
headers={"x-api-key": API_KEY},
params={"q": query, "gl": "es", "hl": "es", "page": page},
)
data = response.json()
all_results.extend(data.get("organic_results", []))
if not data.get("pagination", {}).get("has_next_page"):
break
page += 1
return all_results
results = fetch_all_results(QUERY)
for r in results:
print(f"[{r['position']}] {r['title']} — {r['link']}")const API_KEY = "YOUR_API_KEY";
async function fetchAllResults(query: string, maxPages = 3) {
const allResults: any[] = [];
let page = 1;
while (page <= maxPages) {
const params = new URLSearchParams({ q: query, gl: "es", hl: "es", page: String(page) });
const res = await fetch(`https://api.autom.dev/v1/google/search?${params}`, {
headers: { "x-api-key": API_KEY },
});
const data = await res.json();
allResults.push(...(data.organic_results ?? []));
if (!data.pagination?.has_next_page) break;
page++;
}
return allResults;
}
const results = await fetchAllResults("mejores librerías Python para web scraping");
for (const r of results) {
console.log(`[${r.position}] ${r.title} — ${r.link}`);
}<?php
function fetchAllResults(string $apiKey, string $query, int $maxPages = 3): array {
$allResults = [];
$page = 1;
while ($page <= $maxPages) {
$params = http_build_query(["q" => $query, "gl" => "es", "hl" => "es", "page" => $page]);
$ch = curl_init("https://api.autom.dev/v1/google/search?{$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);
$allResults = array_merge($allResults, $data["organic_results"] ?? []);
if (!($data["pagination"]["has_next_page"] ?? false)) break;
$page++;
}
return $allResults;
}
$results = fetchAllResults("YOUR_API_KEY", "mejores librerías Python para web scraping");
foreach ($results as $r) {
echo "[{$r['position']}] {$r['title']} — {$r['link']}\n";
}package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
)
func fetchAllResults(apiKey, query string, maxPages int) []map[string]any {
var all []map[string]any
for page := 1; page <= maxPages; page++ {
params := url.Values{"q": {query}, "gl": {"es"}, "hl": {"es"}, "page": {strconv.Itoa(page)}}
req, _ := http.NewRequest("GET", "https://api.autom.dev/v1/google/search?"+params.Encode(), nil)
req.Header.Set("x-api-key", apiKey)
resp, _ := http.DefaultClient.Do(req)
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var data map[string]any
json.Unmarshal(body, &data)
if items, ok := data["organic_results"].([]any); ok {
for _, item := range items { all = append(all, item.(map[string]any)) }
}
if pag, _ := data["pagination"].(map[string]any); pag["has_next_page"] != true { break }
}
return all
}
func main() {
results := fetchAllResults("YOUR_API_KEY", "mejores librerías Python para web scraping", 3)
for _, r := range results {
fmt.Printf("[%.0f] %s — %s\n", r["position"], r["title"], r["link"])
}
}import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import org.json.*;
public class Main {
static HttpClient client = HttpClient.newHttpClient();
static String API_KEY = "YOUR_API_KEY";
static List<JSONObject> fetchAllResults(String query, int maxPages) throws Exception {
var all = new ArrayList<JSONObject>();
var q = URLEncoder.encode(query, StandardCharsets.UTF_8);
for (int page = 1; page <= maxPages; page++) {
var url = "https://api.autom.dev/v1/google/search?q=" + q + "&gl=es&hl=es&page=" + page;
var request = HttpRequest.newBuilder().uri(URI.create(url))
.header("x-api-key", API_KEY).GET().build();
var resp = client.send(request, HttpResponse.BodyHandlers.ofString());
var json = new JSONObject(resp.body());
var results = json.optJSONArray("organic_results");
if (results != null)
for (int i = 0; i < results.length(); i++) all.add(results.getJSONObject(i));
if (!json.optJSONObject("pagination").optBoolean("has_next_page")) break;
}
return all;
}
public static void main(String[] args) throws Exception {
for (var r : fetchAllResults("mejores librerías Python para web scraping", 3))
System.out.printf("[%d] %s — %s%n", r.getInt("position"), r.getString("title"), r.getString("link"));
}
}using System.Net.Http;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY");
var allResults = new List<JsonElement>();
int page = 1, maxPages = 3;
while (page <= maxPages)
{
var url = $"https://api.autom.dev/v1/google/search?q=mejores+librerias+Python&gl=es&hl=es&page={page}";
var body = await client.GetStringAsync(url);
var json = JsonDocument.Parse(body).RootElement;
foreach (var result in json.GetProperty("organic_results").EnumerateArray())
allResults.Add(result);
if (!json.GetProperty("pagination").GetProperty("has_next_page").GetBoolean()) break;
page++;
}
foreach (var r in allResults)
Console.WriteLine($"[{r.GetProperty("position")}] {r.GetProperty("title")} — {r.GetProperty("link")}");use reqwest::Client;
use serde_json::Value;
async fn fetch_all_results(client: &Client, api_key: &str, query: &str, max_pages: u32) -> Vec<Value> {
let mut all = Vec::new();
for page in 1..=max_pages {
let resp = client.get("https://api.autom.dev/v1/google/search")
.header("x-api-key", api_key)
.query(&[("q", query), ("gl", "es"), ("hl", "es"), ("page", &page.to_string())])
.send().await.unwrap().json::<Value>().await.unwrap();
if let Some(results) = resp["organic_results"].as_array() { all.extend(results.clone()); }
if !resp["pagination"]["has_next_page"].as_bool().unwrap_or(false) { break; }
}
all
}
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let results = fetch_all_results(&client, "YOUR_API_KEY", "mejores librerías Python", 3).await;
for r in &results {
println!("[{}] {} — {}", r["position"], r["title"].as_str().unwrap_or(""), r["link"].as_str().unwrap_or(""));
}
Ok(())
}Usa el parámetro gl para segmentar un país específico (p. ej. es para España, mx para México) y hl para el idioma de los resultados. Esto es esencial para el seguimiento preciso de posiciones locales.