코드 예제

같은 검색을 여러 언어로 작성한 예제입니다. 특정 스크립트를 쓰는 사이트를 찾고, 결과를 페이지별로 넘기고, 기다리라는 응답을 받으면 정중하게 물러납니다. API 키는 파일에 직접 넣지 말고 환경 변수에 저장하세요.

같은 기능을 명령줄 도구가 포함된 작은 클라이언트로도 제공합니다(표준 라이브러리만 사용): Python, JavaScript, PHP, Go, Ruby. 스프레드시트에서는 Google Sheets, 잠재 고객 발굴 테이블에서는 Clay를 참고하세요.

curl

export PUBLICWWW_KEY=...

# One page of results
curl -H "Authorization: Bearer $PUBLICWWW_KEY" \
     --get --data-urlencode 'query="angular.min.js"' --data 'per_page=20' \
     https://api.publicwww.com/v1/search

# Every match, as a plain list of urls
curl -H "Authorization: Bearer $PUBLICWWW_KEY" \
     --get --data-urlencode 'query="angular.min.js"' \
     --data 'format=txt&per_page=100000' \
     https://api.publicwww.com/v1/search > sites.txt

# A long, multi-line query is easier as a POST
curl https://api.publicwww.com/v1/search \
     -H "Authorization: Bearer $PUBLICWWW_KEY" \
     -H "Content-Type: application/json" \
     -d '{"query": ["\"angular.min.js\"", "\"bootstrap.min.css\""], "per_page": 50}'

Python

import os, time, requests

KEY  = os.environ["PUBLICWWW_KEY"]
BASE = "https://api.publicwww.com"

def search(query, **params):
    """One page of results, waiting out the rate limit if asked to."""
    while True:
        r = requests.get(BASE + "/v1/search",
                         headers={"Authorization": "Bearer " + KEY},
                         params={"query": query, **params})
        if r.status_code == 429:
            body = r.json()["error"]
            if body["code"] != "too_many_requests":
                raise RuntimeError(body["message"])       # quota, not pace
            time.sleep(int(r.headers.get("Retry-After", 30)))
            continue
        r.raise_for_status()
        return r.json()

page = search('"angular.min.js"', per_page=20)
print(page["total"], "sites match")
for row in page["results"]:
    print(row["rank"], row["domain"], row["url"])

대용량 결과 스트리밍

import json, os, requests

r = requests.get("https://api.publicwww.com/v1/search",
                 headers={"Authorization": "Bearer " + os.environ["PUBLICWWW_KEY"]},
                 params={"query": '"angular.min.js"',
                         "format": "ndjson", "per_page": 1000000},
                 stream=True)
r.raise_for_status()

meta = None
for line in r.iter_lines():
    if not line:
        continue
    obj = json.loads(line)
    if obj.get("object") == "meta":          # always the first line
        meta = obj
        print("expecting", meta["returned"], "of", meta["total"])
        continue
    print(obj["domain"])

PHP

<?php
$key = getenv ("PUBLICWWW_KEY");

$url = "https://api.publicwww.com/v1/search?" . http_build_query (array (
	"query"    => '"angular.min.js"',
	"per_page" => 20,
));

$ch = curl_init ($url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array ("Authorization: Bearer " . $key));

$body   = curl_exec ($ch);
$status = curl_getinfo ($ch, CURLINFO_HTTP_CODE);
curl_close ($ch);

$data = json_decode ($body, true);

if ($status != 200) {
	die ($data ["error"] ["code"] . ": " . $data ["error"] ["message"] . "\n");
}

echo $data ["total"] . " sites match\n";
foreach ($data ["results"] as $r) {
	echo $r ["rank"] . "\t" . $r ["domain"] . "\t" . $r ["url"] . "\n";
}

JavaScript (Node)

const KEY  = process.env.PUBLICWWW_KEY;
const BASE = "https://api.publicwww.com";

async function search (query, params = {}) {
  const url = new URL (BASE + "/v1/search");
  url.searchParams.set ("query", query);
  for (const [k, v] of Object.entries (params)) url.searchParams.set (k, v);

  for (;;) {
    const res  = await fetch (url, { headers: { Authorization: `Bearer ${KEY}` } });
    const body = await res.json ();

    if (res.status === 429 && body.error.code === "too_many_requests") {
      await new Promise (r => setTimeout (r, body.error.retry_after * 1000));
      continue;                                   // told to wait, not refused
    }
    if (!res.ok) throw new Error (`${body.error.code}: ${body.error.message}`);
    return body;
  }
}

const page = await search ('"angular.min.js"', { per_page: 20 });
console.log (page.total, "sites match");
for (const r of page.results) console.log (r.rank, r.domain, r.url);

Go

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
)

type Result struct {
	Domain string `json:"domain"`
	URL    string `json:"url"`
	Rank   *int   `json:"rank"`          // nil when the site has no rank
}

type Page struct {
	Total   int      `json:"total"`
	Results []Result `json:"results"`
}

func main () {
	q := url.Values{}
	q.Set ("query", `"angular.min.js"`)
	q.Set ("per_page", "20")

	req, _ := http.NewRequest ("GET", "https://api.publicwww.com/v1/search?"+q.Encode (), nil)
	req.Header.Set ("Authorization", "Bearer "+os.Getenv ("PUBLICWWW_KEY"))

	res, err := http.DefaultClient.Do (req)
	if err != nil { panic (err) }
	defer res.Body.Close ()

	if res.StatusCode != 200 {
		fmt.Println ("http", res.StatusCode, res.Header.Get ("Retry-After"))
		os.Exit (1)
	}

	var page Page
	json.NewDecoder (res.Body).Decode (&page)

	fmt.Println (page.Total, "sites match")
	for _, r := range page.Results {
		fmt.Println (r.Domain, r.URL)
	}
}

Ruby

require "json"
require "net/http"

KEY = ENV.fetch ("PUBLICWWW_KEY")

uri = URI ("https://api.publicwww.com/v1/search")
uri.query = URI.encode_www_form (query: '"angular.min.js"', per_page: 20)

req = Net::HTTP::Get.new (uri)
req["Authorization"] = "Bearer #{KEY}"

res = Net::HTTP.start (uri.host, uri.port, use_ssl: true) { |http| http.request (req) }
body = JSON.parse (res.body)

abort "#{body['error']['code']}: #{body['error']['message']}" unless res.code == "200"

puts "#{body['total']} sites match"
body["results"].each { |r| puts [r["rank"], r["domain"], r["url"]].join ("\t") }

스프레드시트나 셸 파이프라인으로 불러오기

# A csv of domain and rank, ready for a spreadsheet
curl -H "Authorization: Bearer $PUBLICWWW_KEY" \
     --get --data-urlencode 'query="angular.min.js"' \
     --data 'format=csv&header=1&delimiter=,&per_page=10000' \
     https://api.publicwww.com/v1/search > sites.csv

# Just the domains, one per line, into whatever comes next
curl -H "Authorization: Bearer $PUBLICWWW_KEY" \
     --get --data-urlencode 'query="angular.min.js"' \
     --data 'format=csv&columns=domain&per_page=10000' \
     https://api.publicwww.com/v1/search | sort -u

꼭 지켜야 할 점

다음 Google Sheets