diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c3c5335..fa6e091 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -135,3 +135,50 @@ jobs: results = client.search({"engine": "google", "q": "coffee"}) assert results.get("organic_results"), "No organic results returned" print(f"OK: live search returned {len(results['organic_results'])} organic results") + + build-docs: + name: Build Great Docs + needs: [smoke-test] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.13" + + - name: Install package and documentation dependencies + run: | + python -m pip install --upgrade pip + pip install -e ".[docs]" + + - name: Set up Quarto + uses: quarto-dev/quarto-actions/setup@v2 + + - name: Build documentation + run: great-docs build + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v5 + with: + path: great-docs/_site + include-hidden-files: true + + deploy-docs: + name: Deploy GitHub Pages + needs: [build-docs] + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v5 diff --git a/.gitignore b/.gitignore index 143977d..44d5b48 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ script/ .coverage -docs/build +great-docs/ dist/ build/ .pytest_cache/ diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index 7168b22..0000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# .readthedocs.yaml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Set the OS, Python version and other tools you might need -build: - os: ubuntu-22.04 - tools: - python: "3.11" - # You can also specify other tool versions: - # nodejs: "19" - # rust: "1.64" - # golang: "1.19" - -# Build documentation in the "docs/" directory with Sphinx -sphinx: - configuration: docs/conf.py - -# Optionally build your docs in additional formats such as PDF and ePub -formats: - - pdf - - epub - -# Optional but recommended, declare the Python requirements required -# to build your documentation -# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -python: - install: - - requirements: docs/requirements.txt diff --git a/README.md b/README.md index 15eb407..a6893de 100644 --- a/README.md +++ b/README.md @@ -380,4 +380,4 @@ Bug reports and pull requests are welcome on GitHub. Once dependencies are insta ``` This triggers the [release workflow](.github/workflows/release.yml), which tests, builds, and publishes to PyPI, then smoke-tests the published package. -> **Required secrets:** `PYPI_API_TOKEN` (PyPI upload token) and `API_KEY` (used in smoke-test live search). +> **Required secrets:** `PYPI_API_TOKEN` (PyPI upload token) and `API_KEY` (used in smoke-test live search). \ No newline at end of file diff --git a/assets/serpapi-icon.png b/assets/serpapi-icon.png new file mode 100644 index 0000000..e3754a2 Binary files /dev/null and b/assets/serpapi-icon.png differ diff --git a/assets/serpapi-logo-dark.svg b/assets/serpapi-logo-dark.svg new file mode 100644 index 0000000..743381b --- /dev/null +++ b/assets/serpapi-logo-dark.svg @@ -0,0 +1,15 @@ + diff --git a/assets/serpapi-logo.svg b/assets/serpapi-logo.svg new file mode 100644 index 0000000..c400e7b --- /dev/null +++ b/assets/serpapi-logo.svg @@ -0,0 +1,15 @@ + diff --git a/assets/serpapi-theme.css b/assets/serpapi-theme.css new file mode 100644 index 0000000..a405892 --- /dev/null +++ b/assets/serpapi-theme.css @@ -0,0 +1,912 @@ +:root { + --serpapi-bg-soft: #f3f3f4; + --serpapi-bg-soft-2: #ffffff; + --serpapi-surface: #ffffff; + --serpapi-surface-raised: #ffffff; + --serpapi-border: #dddfea; + --serpapi-text: #2f3030; + --serpapi-muted: #58606d; + --serpapi-footer: #2f3030; + --serpapi-purple: #6937ea; + --serpapi-blue: #377fea; + --serpapi-link: #265fb8; + --serpapi-accent: #377fea; + --serpapi-gradient: linear-gradient(135deg, var(--serpapi-blue) 0%, var(--serpapi-accent) 100%); + --serpapi-code-bg: #f6f8fa; + --serpapi-code-text: #17212b; + --serpapi-code-border: #d8e1ee; + --serpapi-code-chrome: #eef3f8; + --serpapi-code-keyword: #5932b8; + --serpapi-code-string: #075985; + --serpapi-code-number: #9a3412; + --serpapi-code-function: #0f5e9c; + --serpapi-code-variable: #7c2d83; + --serpapi-code-comment: #4b5563; + --serpapi-code-warning: #b42318; + --gd-accent: var(--serpapi-blue); +} + +body { + color: var(--serpapi-text); + background-color: #ffffff; + font-family: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} + +body.quarto-light, +html.quarto-light, +html.quarto-light body.quarto-light, +body.nav-fixed.quarto-light, +body.nav-sidebar.quarto-light, +body.gd-homepage.quarto-light, +[data-bs-theme="light"] body { + background-color: #ffffff !important; + color: var(--serpapi-text) !important; +} + +body.quarto-light main, +body.quarto-light main.content, +body.quarto-light #quarto-content, +body.quarto-light #quarto-document-content, +body.quarto-light .page-columns, +body.quarto-light .content, +body.quarto-light .quarto-container, +body.quarto-light section, +body.quarto-light section.level1, +body.quarto-light section.level2, +html.quarto-light main, +html.quarto-light main.content, +html.quarto-light #quarto-content, +html.quarto-light #quarto-document-content, +html.quarto-light .page-columns, +html.quarto-light .content, +html.quarto-light .quarto-container, +html.quarto-light section, +html.quarto-light section.level1, +html.quarto-light section.level2, +[data-bs-theme="light"] main, +[data-bs-theme="light"] main.content, +[data-bs-theme="light"] #quarto-content, +[data-bs-theme="light"] #quarto-document-content, +[data-bs-theme="light"] .page-columns, +[data-bs-theme="light"] .content, +[data-bs-theme="light"] .quarto-container, +[data-bs-theme="light"] section, +[data-bs-theme="light"] section.level1, +[data-bs-theme="light"] section.level2 { + background: transparent !important; +} + +a { + color: var(--serpapi-link); +} + +a:hover, +a:focus { + color: var(--serpapi-blue); + text-decoration-color: var(--serpapi-accent); +} + +.navbar, +.navbar.quarto-navbar { + background: #ffffff !important; + border-bottom: 1px solid var(--serpapi-border); + box-shadow: 0 1px 0 rgba(24, 33, 43, 0.04); +} + +.navbar a, +.navbar .navbar-brand, +.navbar .nav-link { + color: var(--serpapi-text) !important; +} + +.navbar .navbar-brand img, +.navbar-brand-logo img, +.navbar-logo { + height: 32px !important; + max-height: 32px; + min-width: 0; + width: auto !important; +} + +.navbar .nav-link:hover, +.navbar .nav-link:focus { + color: var(--serpapi-link) !important; +} + +.hero, +.gd-hero, +.quarto-title-banner { + background: linear-gradient(180deg, #ffffff 0%, var(--serpapi-bg-soft) 100%) !important; + border-bottom: 1px solid var(--serpapi-border); + box-shadow: inset 0 3px 0 var(--serpapi-blue); + color: var(--serpapi-text); +} + +.hero a, +.gd-hero a, +.quarto-title-banner a { + color: var(--serpapi-link); +} + +.hero p, +.gd-hero p, +.quarto-title-banner p { + color: var(--serpapi-muted); +} + +.btn-primary { + background: var(--serpapi-gradient) !important; + border-color: var(--serpapi-blue) !important; + color: #ffffff !important; +} + +.btn-primary:hover, +.btn-primary:focus { + background: linear-gradient(135deg, #215fb7 0%, #0d837f 100%) !important; + border-color: var(--serpapi-blue) !important; +} + +.btn-outline-primary { + border-color: var(--serpapi-blue) !important; + color: var(--serpapi-blue) !important; +} + +.btn-outline-primary:hover, +.btn-outline-primary:focus { + background: var(--serpapi-gradient) !important; + border-color: var(--serpapi-blue) !important; + color: #ffffff !important; +} + +pre, +div.sourceCode { + border: 1px solid var(--serpapi-code-border); + border-radius: 6px; +} + +pre, +code.sourceCode, +.sourceCode, +pre.sourceCode, +div.sourceCode { + background-color: var(--serpapi-code-bg) !important; + color: var(--serpapi-code-text) !important; +} + +pre { + padding: 0.9rem 1rem; +} + +div.sourceCode { + margin: 1rem 0; +} + +div.sourceCode pre { + border: 0; + margin: 0; + padding: 0.9rem 1rem; +} + +pre code, +pre.sourceCode code, +code.sourceCode, +div.sourceCode pre, +div.sourceCode code { + background-color: var(--serpapi-code-bg) !important; + color: var(--serpapi-code-text) !important; +} + +pre code span, +pre.sourceCode code span, +code.sourceCode span, +div.sourceCode span, +.sourceCode span { + color: var(--serpapi-code-text) !important; +} + +code.sourceCode span.kw, +code.sourceCode span.cf, +code.sourceCode span.im { + color: var(--serpapi-code-keyword) !important; + font-weight: 600; +} + +code.sourceCode span.st, +code.sourceCode span.ch, +code.sourceCode span.sc, +code.sourceCode span.ss, +code.sourceCode span.vs { + color: var(--serpapi-code-string) !important; +} + +code.sourceCode span.dv, +code.sourceCode span.bn, +code.sourceCode span.fl, +code.sourceCode span.cn { + color: var(--serpapi-code-number) !important; +} + +code.sourceCode span.bu, +code.sourceCode span.fu, +code.sourceCode span.ex { + color: var(--serpapi-code-function) !important; +} + +code.sourceCode span.va, +code.sourceCode span.at, +code.sourceCode span.dt, +code.sourceCode span.ot { + color: var(--serpapi-code-variable) !important; +} + +code.sourceCode span.co, +code.sourceCode span.do, +code.sourceCode span.an, +code.sourceCode span.cv, +code.sourceCode span.in { + color: var(--serpapi-code-comment) !important; + font-style: italic; +} + +code.sourceCode span.al, +code.sourceCode span.er, +code.sourceCode span.wa { + color: var(--serpapi-code-warning) !important; +} + +pre a, +pre.sourceCode a, +div.sourceCode a { + color: inherit !important; +} + +p code:not(.sourceCode), +li code:not(.sourceCode), +td code:not(.sourceCode) { + background: rgba(47, 115, 217, 0.08); + border: 1px solid rgba(47, 115, 217, 0.14); + border-radius: 4px; + color: #405179; + padding: 0.08rem 0.28rem; +} + +.panel-tabset { + background: var(--serpapi-code-bg); + border: 1px solid var(--serpapi-code-border); + border-radius: 8px; + box-shadow: none; + margin: 0.85rem 0 1.1rem; + overflow: hidden; +} + +.panel-tabset > .nav-tabs { + background: var(--serpapi-code-bg); + border-bottom: 1px solid var(--serpapi-code-border); + display: flex; + gap: 0.6rem; + margin: 0; + padding: 0 0.9rem; +} + +.panel-tabset > .nav-tabs .nav-link { + background: transparent; + border: 0; + border-radius: 0; + color: var(--serpapi-muted); + font-weight: 700; + padding: 0.72rem 0 0.62rem; + text-decoration: none; +} + +.panel-tabset > .nav-tabs .nav-link:hover, +.panel-tabset > .nav-tabs .nav-link:focus { + color: var(--serpapi-link); +} + +.panel-tabset > .nav-tabs .nav-link.active { + background: transparent; + box-shadow: inset 0 -2px 0 var(--serpapi-accent); + color: var(--serpapi-text); + margin-bottom: -1px; +} + +.panel-tabset > .tab-content { + background: var(--serpapi-code-bg); + border: 0 !important; + margin: 0; + padding: 0; +} + +.panel-tabset .tab-pane { + padding: 0; +} + +.panel-tabset div.sourceCode { + border: 0; + border-radius: 0; + margin: 0; +} + +.panel-tabset div.sourceCode pre { + border-radius: 0; +} + +.card, +.quarto-grid-item, +.listing-card { + border-radius: 8px; + border-color: var(--serpapi-border); + box-shadow: 0 10px 28px rgba(24, 33, 43, 0.06); +} + +.docs-home-nav { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(280px, 360px); + gap: 1.5rem; + align-items: start; + margin: 2rem 0; +} + +.docs-home-nav__intro, +.docs-home-nav__sidebar { + background: var(--serpapi-surface-raised); + border: 1px solid var(--serpapi-border); + border-radius: 8px; + box-shadow: 0 10px 28px rgba(24, 33, 43, 0.05); + padding: 1.25rem; +} + +.docs-home-nav__sidebar { + position: sticky; + top: 5.25rem; +} + +.docs-home-nav__sidebar h3:first-child { + margin-top: 0; +} + +.docs-home-nav__sidebar h3 { + color: var(--serpapi-text); + font-size: 1rem; + margin: 1.1rem 0 0.35rem; +} + +.docs-home-nav__sidebar ul { + margin-bottom: 0.75rem; + padding-left: 1.1rem; +} + +.docs-home-nav__sidebar li { + margin: 0.32rem 0; +} + +.docs-home-nav__intro p, +.docs-home-nav__sidebar p { + color: var(--serpapi-muted); +} + +.description, +.quarto-title .description, +.quarto-title .subtitle, +.listing-description, +.quarto-title-meta, +.quarto-title-meta-contents, +#quarto-margin-sidebar, +#quarto-sidebar { + color: var(--serpapi-muted); +} + +#quarto-margin-sidebar #toc-title, +.quarto-title-meta-heading { + color: var(--serpapi-text); +} + +.docs-home-actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + margin-top: 1rem; +} + +.docs-home-actions p { + display: flex; + flex-wrap: wrap; + gap: 0.65rem; + margin: 0; +} + +.docs-home-actions a { + border: 1px solid var(--serpapi-border); + border-radius: 6px; + color: var(--serpapi-link); + display: inline-flex; + font-weight: 600; + line-height: 1.2; + padding: 0.55rem 0.8rem; + text-decoration: none; +} + +.docs-home-actions a:hover, +.docs-home-actions a:focus { + background: rgba(47, 115, 217, 0.06); + border-color: var(--serpapi-blue); + color: var(--serpapi-blue); +} + +#quarto-sidebar, +.sidebar-navigation { + background: var(--serpapi-bg-soft); + border-right: 1px solid var(--serpapi-border); +} + +#quarto-sidebar .sidebar-menu-container { + padding: 1rem 0.75rem; +} + +.sidebar .sidebar-item-section > .sidebar-item-container > a, +.sidebar .sidebar-item-section > .sidebar-item-container > .sidebar-item-text { + color: var(--serpapi-muted); + font-size: 0.82rem; + font-weight: 800; + text-transform: uppercase; +} + +.sidebar .sidebar-link { + border-radius: 6px; + color: var(--serpapi-muted); + padding: 0.22rem 0.35rem; + text-decoration: none; +} + +#quarto-sidebar .sidebar-link { + min-width: 0; +} + +#quarto-sidebar .sidebar-link .menu-text { + min-inline-size: min-content; + overflow-wrap: normal; + word-break: keep-all; + hyphens: none; +} + +body:not(.gd-ref-sidebar) #quarto-sidebar .sidebar-link .menu-text wbr { + display: none; +} + +.sidebar .sidebar-link:hover, +.sidebar .sidebar-link:focus { + background: rgba(47, 115, 217, 0.08); + color: var(--serpapi-link); +} + +.sidebar .sidebar-link.active { + background: rgba(47, 115, 217, 0.1); + color: var(--serpapi-link); + font-weight: 800; +} + +#quarto-sidebar a.sidebar-item-text.sidebar-link.active, +#quarto-sidebar .sidebar-link.active { + color: var(--serpapi-link) !important; + text-decoration: none !important; +} + +#quarto-margin-sidebar { + color: var(--serpapi-muted); +} + +.doc-usage-source, +.doc-usage-source p { + color: var(--serpapi-muted) !important; +} + +.doc-usage-source a { + color: var(--serpapi-link) !important; +} + +.doc-usage-source a:hover, +.doc-usage-source a:focus { + color: var(--serpapi-blue) !important; +} + +#TOC .nav-link { + border-left: 2px solid var(--serpapi-border); + color: var(--serpapi-muted); + padding-left: 0.7rem; + text-decoration: none; +} + +#TOC .nav-link:hover, +#TOC .nav-link:focus { + color: var(--serpapi-link); +} + +#TOC .nav-link.active { + border-left-color: var(--serpapi-accent); + color: var(--serpapi-link) !important; + font-weight: 700; +} + +@media (max-width: 991.98px) { + .navbar, + .navbar.quarto-navbar { + padding: 0.65rem 0.75rem; + } + + .navbar .navbar-container { + align-items: center; + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + padding-left: 0 !important; + padding-right: 0 !important; + width: 100%; + } + + .navbar .navbar-toggler { + flex: 0 0 34px; + height: 34px; + margin: 0 !important; + order: 1; + padding: 0; + width: 34px; + } + + .navbar .navbar-brand-container, + .navbar .navbar-brand-container.mx-auto { + flex: 0 1 auto; + margin-left: 0 !important; + margin-right: auto !important; + min-width: 0; + order: 2; + } + + .navbar .navbar-brand { + align-items: center; + display: flex; + margin: 0 !important; + max-width: 36vw; + min-width: 0; + padding: 0.2rem 0 !important; + } + + .navbar .navbar-brand img, + .navbar-brand-logo img, + .navbar-logo { + height: 28px !important; + margin: 0 !important; + max-height: 28px; + max-width: min(36vw, 128px); + min-width: 0; + object-fit: contain; + width: auto !important; + } + + .navbar .quarto-navbar-tools { + align-items: center; + display: flex !important; + flex: 0 0 auto; + gap: 0.35rem; + margin-left: 0 !important; + order: 3; + padding: 0 !important; + } + + .navbar .quarto-navbar-tools button, + .navbar .quarto-navbar-tools .quarto-navigation-tool, + .navbar .dark-mode-toggle, + .navbar .gh-widget-trigger, + .navbar .nav-item.compact .nav-link, + .navbar .gd-navbar-icon { + align-items: center; + display: inline-flex; + height: 34px; + justify-content: center; + min-width: 34px; + padding: 0 !important; + width: 34px; + } + + .navbar #navbarCollapse { + flex-basis: 100%; + order: 4; + } + + .navbar #navbarCollapse.show, + .navbar #navbarCollapse.collapsing { + margin-top: 0.35rem; + } +} + +@media (max-width: 374px) { + .navbar, + .navbar.quarto-navbar { + padding: 0.55rem 0.65rem; + } + + .navbar .navbar-container { + gap: 0.4rem; + } + + .navbar .navbar-brand { + max-width: 34vw; + } + + .navbar .navbar-brand img, + .navbar-brand-logo img, + .navbar-logo { + height: 26px !important; + max-height: 26px; + max-width: min(34vw, 116px); + } + + .navbar .quarto-navbar-tools { + gap: 0.25rem; + } + + .navbar .navbar-toggler, + .navbar .quarto-navbar-tools button, + .navbar .quarto-navbar-tools .quarto-navigation-tool, + .navbar .dark-mode-toggle, + .navbar .gh-widget-trigger, + .navbar .nav-item.compact .nav-link, + .navbar .gd-navbar-icon { + height: 32px; + min-width: 32px; + width: 32px; + } +} + +@media (max-width: 991px) { + .docs-home-nav { + grid-template-columns: 1fr; + } + + .docs-home-nav__sidebar { + position: static; + } +} + +body.quarto-dark, +html.quarto-dark, +html.quarto-dark body.quarto-dark, +body.nav-fixed.quarto-dark, +body.nav-sidebar.quarto-dark, +body.gd-homepage.quarto-dark, +[data-bs-theme="dark"] body { + --serpapi-bg-soft: #111827; + --serpapi-bg-soft-2: #151c26; + --serpapi-surface: #151c26; + --serpapi-surface-raised: #1b2430; + --serpapi-border: #2a3646; + --serpapi-text: #e7edf5; + --serpapi-muted: #a9b6c8; + --serpapi-link: #67d8ef; + --serpapi-blue: #60a5fa; + --serpapi-accent: #2dd4bf; + --serpapi-code-bg: #0b1220; + --serpapi-code-text: #dbeafe; + --serpapi-code-border: #324256; + --serpapi-code-chrome: #101a29; + --serpapi-code-keyword: #93c5fd; + --serpapi-code-string: #5eead4; + --serpapi-code-number: #fbbf24; + --serpapi-code-function: #7dd3fc; + --serpapi-code-variable: #c4b5fd; + --serpapi-code-comment: #94a3b8; + --serpapi-code-warning: #fca5a5; + background-color: #0f141b !important; +} + +body.quarto-dark main, +body.quarto-dark main.content, +body.quarto-dark #quarto-content, +body.quarto-dark #quarto-document-content, +body.quarto-dark .page-columns, +body.quarto-dark .content, +body.quarto-dark .quarto-container, +body.quarto-dark section, +body.quarto-dark section.level1, +body.quarto-dark section.level2, +html.quarto-dark main, +html.quarto-dark main.content, +html.quarto-dark #quarto-content, +html.quarto-dark #quarto-document-content, +html.quarto-dark .page-columns, +html.quarto-dark .content, +html.quarto-dark .quarto-container, +html.quarto-dark section, +html.quarto-dark section.level1, +html.quarto-dark section.level2, +[data-bs-theme="dark"] main, +[data-bs-theme="dark"] main.content, +[data-bs-theme="dark"] #quarto-content, +[data-bs-theme="dark"] #quarto-document-content, +[data-bs-theme="dark"] .page-columns, +[data-bs-theme="dark"] .content, +[data-bs-theme="dark"] .quarto-container, +[data-bs-theme="dark"] section, +[data-bs-theme="dark"] section.level1, +[data-bs-theme="dark"] section.level2 { + background: transparent !important; +} + +body.quarto-dark #quarto-sidebar, +body.quarto-dark .sidebar-navigation, +html.quarto-dark #quarto-sidebar, +html.quarto-dark .sidebar-navigation, +[data-bs-theme="dark"] #quarto-sidebar, +[data-bs-theme="dark"] .sidebar-navigation { + background: #0f141b !important; + border-color: var(--serpapi-border) !important; +} + +body.quarto-dark #quarto-sidebar .sidebar-menu-container, +html.quarto-dark #quarto-sidebar .sidebar-menu-container, +[data-bs-theme="dark"] #quarto-sidebar .sidebar-menu-container { + background: transparent !important; +} + +body.quarto-dark .navbar, +html.quarto-dark .navbar, +[data-bs-theme="dark"] .navbar, +body.quarto-dark .navbar.quarto-navbar, +html.quarto-dark .navbar.quarto-navbar, +[data-bs-theme="dark"] .navbar.quarto-navbar { + background: #111827 !important; + border-bottom-color: var(--serpapi-border); +} + +body.quarto-dark .navbar a, +body.quarto-dark .navbar .navbar-brand, +body.quarto-dark .navbar .nav-link, +[data-bs-theme="dark"] .navbar a, +[data-bs-theme="dark"] .navbar .navbar-brand, +[data-bs-theme="dark"] .navbar .nav-link { + color: #ffffff !important; +} + +body.quarto-dark .hero, +html.quarto-dark .hero, +body.quarto-dark .gd-hero, +html.quarto-dark .gd-hero, +body.quarto-dark .quarto-title-banner, +html.quarto-dark .quarto-title-banner, +[data-bs-theme="dark"] .hero, +[data-bs-theme="dark"] .gd-hero, +[data-bs-theme="dark"] .quarto-title-banner { + background: linear-gradient(180deg, #111827 0%, #151c26 100%) !important; + border-bottom-color: var(--serpapi-border); + box-shadow: inset 0 3px 0 var(--serpapi-accent); + color: var(--serpapi-text); +} + +body.quarto-dark a, +html.quarto-dark a, +[data-bs-theme="dark"] a { + color: var(--serpapi-link); +} + +body.quarto-dark a:hover, +body.quarto-dark a:focus, +html.quarto-dark a:hover, +html.quarto-dark a:focus, +[data-bs-theme="dark"] a:hover, +[data-bs-theme="dark"] a:focus { + color: var(--serpapi-accent); +} + +body.quarto-dark .docs-home-nav__intro, +body.quarto-dark .docs-home-nav__sidebar, +html.quarto-dark .docs-home-nav__intro, +html.quarto-dark .docs-home-nav__sidebar, +[data-bs-theme="dark"] .docs-home-nav__intro, +[data-bs-theme="dark"] .docs-home-nav__sidebar { + background: var(--serpapi-surface-raised); + border-color: var(--serpapi-border); +} + +body.quarto-dark .docs-home-actions a, +html.quarto-dark .docs-home-actions a, +[data-bs-theme="dark"] .docs-home-actions a { + border-color: var(--serpapi-border); + color: var(--serpapi-text); +} + +body.quarto-dark .docs-home-actions a:hover, +body.quarto-dark .docs-home-actions a:focus, +html.quarto-dark .docs-home-actions a:hover, +html.quarto-dark .docs-home-actions a:focus, +[data-bs-theme="dark"] .docs-home-actions a:hover, +[data-bs-theme="dark"] .docs-home-actions a:focus { + background: rgba(103, 216, 239, 0.1); + border-color: var(--serpapi-link); + color: var(--serpapi-link); +} + +body.quarto-dark .panel-tabset, +html.quarto-dark .panel-tabset, +[data-bs-theme="dark"] .panel-tabset { + background: var(--serpapi-code-bg); + border-color: var(--serpapi-code-border); + box-shadow: none; + margin: 0.85rem 0 1.1rem; +} + +body.quarto-dark .panel-tabset > .nav-tabs, +html.quarto-dark .panel-tabset > .nav-tabs, +[data-bs-theme="dark"] .panel-tabset > .nav-tabs { + background: var(--serpapi-code-bg); + border-bottom: 1px solid var(--serpapi-code-border); + gap: 0.6rem; + padding: 0 0.9rem; +} + +body.quarto-dark .panel-tabset > .nav-tabs .nav-link, +html.quarto-dark .panel-tabset > .nav-tabs .nav-link, +[data-bs-theme="dark"] .panel-tabset > .nav-tabs .nav-link { + background: transparent; + border: 0; + border-radius: 0; + padding: 0.72rem 0 0.62rem; +} + +body.quarto-dark .panel-tabset > .nav-tabs .nav-link.active, +html.quarto-dark .panel-tabset > .nav-tabs .nav-link.active, +[data-bs-theme="dark"] .panel-tabset > .nav-tabs .nav-link.active { + background: transparent; + box-shadow: inset 0 -2px 0 var(--serpapi-accent); + color: var(--serpapi-text); +} + +body.quarto-dark .panel-tabset > .tab-content, +html.quarto-dark .panel-tabset > .tab-content, +[data-bs-theme="dark"] .panel-tabset > .tab-content { + background: var(--serpapi-code-bg); + border: 0 !important; + margin: 0; + padding: 0; +} + +body.quarto-dark .panel-tabset div.sourceCode, +html.quarto-dark .panel-tabset div.sourceCode, +[data-bs-theme="dark"] .panel-tabset div.sourceCode { + border: 0; + border-radius: 0; + margin: 0; +} + +body.quarto-dark .panel-tabset div.sourceCode pre, +html.quarto-dark .panel-tabset div.sourceCode pre, +[data-bs-theme="dark"] .panel-tabset div.sourceCode pre { + border-radius: 0; +} + +body.quarto-dark p code:not(.sourceCode), +body.quarto-dark li code:not(.sourceCode), +body.quarto-dark td code:not(.sourceCode), +html.quarto-dark p code:not(.sourceCode), +html.quarto-dark li code:not(.sourceCode), +html.quarto-dark td code:not(.sourceCode), +[data-bs-theme="dark"] p code:not(.sourceCode), +[data-bs-theme="dark"] li code:not(.sourceCode), +[data-bs-theme="dark"] td code:not(.sourceCode) { + background: rgba(103, 216, 239, 0.09); + border-color: rgba(103, 216, 239, 0.18); + color: #9ee7f5; +} + +body.quarto-dark table, +html.quarto-dark table, +[data-bs-theme="dark"] table { + border-color: var(--serpapi-border); +} + +body.quarto-dark th, +body.quarto-dark td, +html.quarto-dark th, +html.quarto-dark td, +[data-bs-theme="dark"] th, +[data-bs-theme="dark"] td { + border-color: var(--serpapi-border); +} diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index ed88099..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/serpapi-python.png b/docs/_static/serpapi-python.png deleted file mode 100644 index 4245bb6..0000000 Binary files a/docs/_static/serpapi-python.png and /dev/null differ diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 517e0c2..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,69 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys - -sys.path.insert(0, os.path.abspath("../..")) - -import serpapi - -# -- Project information ----------------------------------------------------- - -project = "serpapi-python" -copyright = "2023 SerpApi, LLC" -author = "SerpApi, LLC" - -# The full version, including alpha/beta/rc tags -release = serpapi.__version__ - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["sphinx.ext.githubpages", "sphinx.ext.autodoc"] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "alabaster" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - - -# -- Extension configuration ------------------------------------------------- -html_theme_options = { - "logo": "serpapi-python.png", - "logo_name": "serapi-python", -} - -html_sidebars = { - "**": [ - "about.html", - ] -} diff --git a/docs/examples/00-google-across-countries.md b/docs/examples/00-google-across-countries.md new file mode 100644 index 0000000..7c1ae4c --- /dev/null +++ b/docs/examples/00-google-across-countries.md @@ -0,0 +1,71 @@ +--- +title: "Google Across Countries" +description: "Run the same Google Search across multiple countries and locations." +--- + +# Google Across Countries + +Use `gl`, `hl`, `location`, and sometimes `google_domain` to compare localized Google results. + +## Compare Several Countries + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +markets = [ + {"name": "United States", "gl": "us", "hl": "en", "location": "Austin, Texas"}, + {"name": "United Kingdom", "gl": "gb", "hl": "en", "location": "London, England"}, + {"name": "France", "gl": "fr", "hl": "fr", "location": "Paris, France"}, + {"name": "Germany", "gl": "de", "hl": "de", "location": "Berlin, Germany"}, + {"name": "India", "gl": "in", "hl": "en", "location": "Mumbai, Maharashtra"}, +] + +for market in markets: + results = client.search( + engine="google", + q="best coffee beans", + location=market["location"], + gl=market["gl"], + hl=market["hl"], + ) + + organic = results.get("organic_results", []) + first = organic[0] if organic else {} + + print(market["name"]) + print(first.get("title")) + print(first.get("link")) + print() +``` + +## Use a Google Domain + +Some workflows also need a specific Google domain: + +```python +results = client.search( + engine="google", + q="best coffee beans", + google_domain="google.co.in", + gl="in", + hl="en", + location="Mumbai, Maharashtra", +) +``` + +## Finding Valid Locations + +Use the client helper: + +```python +locations = client.locations(q="Mumbai", limit=5) + +for location in locations: + print(location.get("canonical_name")) +``` + +See [Account and Locations](../../user-guide/account-and-locations.md) for the local guide to the locations helper. Use the [SerpApi Playground](https://serpapi.com/playground) to test location values with the rest of your search parameters. diff --git a/docs/examples/01-bing-search.md b/docs/examples/01-bing-search.md new file mode 100644 index 0000000..83d2b01 --- /dev/null +++ b/docs/examples/01-bing-search.md @@ -0,0 +1,38 @@ +--- +title: "Bing Search" +description: "Run a Bing web search and read organic result fields." +--- + +# Bing Search + +Use the Bing Search API when you want a second web index alongside Google, or when your product specifically needs Bing result ordering. The Python client sends Bing parameters directly to SerpApi, so you can start with a small query and add localization or pagination as your use case grows. + +## Search Bing + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="bing", + q="coffee", + location="Austin, Texas", +) + +for result in results.get("organic_results", [])[:5]: + print(result.get("position"), result.get("title")) + print(result.get("link")) +``` + +## What to Read + +Most applications start with `organic_results`, then store the `title`, `link`, `snippet`, and `position` fields. If your query returns richer SERP blocks, inspect the top-level keys with: + +```python +print(results.keys()) +``` + +For every supported Bing parameter, use the [Bing Search API documentation](https://serpapi.com/bing-search-api). To tune a query interactively, use the [SerpApi Playground](https://serpapi.com/playground). diff --git a/docs/examples/02-google-maps-local-business.md b/docs/examples/02-google-maps-local-business.md new file mode 100644 index 0000000..642a627 --- /dev/null +++ b/docs/examples/02-google-maps-local-business.md @@ -0,0 +1,36 @@ +--- +title: "Google Maps Local Businesses" +description: "Find local businesses with Google Maps results." +--- + +# Google Maps Local Businesses + +Use the Google Maps API for local discovery workflows: store locators, lead generation, local SEO checks, or building a shortlist of nearby places. The most important inputs are the business query and the map coordinate/zoom string in `ll`. + +## Search for Local Businesses + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_maps", + q="coffee shops", + ll="@30.2672,-97.7431,14z", + type="search", +) + +for place in results.get("local_results", [])[:5]: + print(place.get("title")) + print(place.get("rating"), place.get("reviews")) + print(place.get("address")) +``` + +## What to Read + +Start with `local_results`. Common fields include `title`, `rating`, `reviews`, `address`, `phone`, `website`, and `gps_coordinates`. Some responses also include `place_results` when the query resolves to a specific place. + +For the complete parameter list, use the [Google Maps API documentation](https://serpapi.com/google-maps-api). Use the [SerpApi Playground](https://serpapi.com/playground) to find a working `ll` value for your target market. diff --git a/docs/examples/03-google-shopping-products.md b/docs/examples/03-google-shopping-products.md new file mode 100644 index 0000000..3ff97b9 --- /dev/null +++ b/docs/examples/03-google-shopping-products.md @@ -0,0 +1,37 @@ +--- +title: "Google Shopping Products" +description: "Search Google Shopping and extract product cards." +--- + +# Google Shopping Products + +Use the Google Shopping API when you need product result cards, prices, merchants, and shopping links. It is a good fit for product discovery, price monitoring, catalog enrichment, and market research. + +## Search Products + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_shopping", + q="espresso machine", + location="Austin, Texas", + gl="us", + hl="en", +) + +for product in results.get("shopping_results", [])[:5]: + print(product.get("title")) + print(product.get("price"), product.get("source")) + print(product.get("link")) +``` + +## What to Read + +Most shopping workflows use `shopping_results`. Save `title`, `price`, `source`, `rating`, `reviews`, `thumbnail`, and `link` if present. For filtering, sorting, and engine-specific options, check the live docs before hard-coding parameters. + +See the [Google Shopping API documentation](https://serpapi.com/google-shopping-api) and experiment in the [SerpApi Playground](https://serpapi.com/playground). diff --git a/docs/examples/04-google-flights-travel.md b/docs/examples/04-google-flights-travel.md new file mode 100644 index 0000000..bdfab71 --- /dev/null +++ b/docs/examples/04-google-flights-travel.md @@ -0,0 +1,42 @@ +--- +title: "Google Flights Travel" +description: "Search round-trip flight options with Google Flights." +--- + +# Google Flights Travel + +Use the Google Flights API for travel search, flight price research, or building itinerary comparison tools. Flight searches are date-sensitive, so use future dates and choose airport codes that match the route you want. + +## Search Round-Trip Flights + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=30) + +results = client.search( + engine="google_flights", + departure_id="AUS", + arrival_id="LAX", + outbound_date="2026-09-15", + return_date="2026-09-22", + currency="USD", + hl="en", + gl="us", +) + +flights = results.get("best_flights") or results.get("other_flights", []) + +for itinerary in flights[:3]: + print("Total price:", itinerary.get("price")) + for flight in itinerary.get("flights", []): + print(flight.get("departure_airport", {}).get("id"), "->", flight.get("arrival_airport", {}).get("id")) +``` + +## What to Read + +Start with `best_flights`, then fall back to `other_flights` when needed. Useful fields include `price`, `total_duration`, `carbon_emissions`, and the nested `flights` list for airline, airport, and timing data. + +For trip type, cabin, date, currency, and airport parameters, see the [Google Flights API documentation](https://serpapi.com/google-flights-api). The [SerpApi Playground](https://serpapi.com/playground) is useful for testing routes before adding them to code. diff --git a/docs/examples/05-google-finance-market-data.md b/docs/examples/05-google-finance-market-data.md new file mode 100644 index 0000000..35d9c73 --- /dev/null +++ b/docs/examples/05-google-finance-market-data.md @@ -0,0 +1,38 @@ +--- +title: "Google Finance Market Data" +description: "Fetch quote, graph, and market context from Google Finance." +--- + +# Google Finance Market Data + +Use the Google Finance API for stock, index, mutual fund, currency, or futures lookups. It is useful for dashboards, watchlists, and enriching business workflows with current market context. + +## Fetch a Quote + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_finance", + q="GOOGL:NASDAQ", + window="1M", + hl="en", +) + +summary = results.get("summary", {}) +knowledge = results.get("knowledge_graph", {}) + +print(summary.get("title") or knowledge.get("title")) +print(summary.get("price") or knowledge.get("price")) +print("Graph points:", len(results.get("graph", []))) +``` + +## What to Read + +Use `summary` and `knowledge_graph` for quote-level details, `graph` for time-series points, and `news_results` for finance-related headlines when present. Use `window` to change the graph range. + +See the [Google Finance API documentation](https://serpapi.com/google-finance-api) for supported `q` formats and time windows. You can test symbols in the [SerpApi Playground](https://serpapi.com/playground). diff --git a/docs/examples/06-google-trends-demand.md b/docs/examples/06-google-trends-demand.md new file mode 100644 index 0000000..fa86551 --- /dev/null +++ b/docs/examples/06-google-trends-demand.md @@ -0,0 +1,39 @@ +--- +title: "Google Trends Demand" +description: "Measure search interest over time with Google Trends." +--- + +# Google Trends Demand + +Use the Google Trends API to compare demand, seasonality, and regional interest. This is useful for content planning, product research, launch timing, and market comparisons. + +## Interest Over Time + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_trends", + q="electric bikes", + date="today 12-m", + geo="US", + data_type="TIMESERIES", + tz="420", +) + +timeline = results.get("interest_over_time", {}).get("timeline_data", []) + +for point in timeline[-5:]: + value = point.get("values", [{}])[0].get("extracted_value") + print(point.get("date"), value) +``` + +## What to Read + +For time-series charts, read `interest_over_time.timeline_data`. For regional demand, switch `data_type` to `GEO_MAP_0`. For related terms, use `RELATED_QUERIES` or `RELATED_TOPICS`. + +See the [Google Trends API documentation](https://serpapi.com/google-trends-api) for `data_type`, `geo`, `date`, and `tz` options. The [SerpApi Playground](https://serpapi.com/playground) helps confirm that a trend query returns the chart you expect. diff --git a/docs/examples/07-google-ai-overview.md b/docs/examples/07-google-ai-overview.md new file mode 100644 index 0000000..a21bc57 --- /dev/null +++ b/docs/examples/07-google-ai-overview.md @@ -0,0 +1,44 @@ +--- +title: "Google AI Overview" +description: "Read AI Overview data from Google Search results or fetch it with a page token." +--- + +# Google AI Overview + +Google AI Overview data can appear directly inside Google Search results. Sometimes Google requires an extra request using `ai_overview.page_token`; in that case, use the Google AI Overview API immediately because the token expires quickly. + +## Search and Fetch AI Overview + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +search = client.search( + engine="google", + q="how do noise cancelling headphones work", + location="Austin, Texas", + gl="us", + hl="en", +) + +ai_overview = search.get("ai_overview", {}) + +if ai_overview.get("page_token"): + response = client.search( + engine="google_ai_overview", + page_token=ai_overview["page_token"], + ) + ai_overview = response.get("ai_overview", {}) + +for block in ai_overview.get("text_blocks", [])[:3]: + print(block.get("snippet") or block.get("text")) +``` + +## What to Read + +Use `ai_overview.text_blocks` for the generated answer and `ai_overview.references` for cited sources when present. If the first Google Search response already includes the AI Overview content, you can read it directly without the second request. + +See the [Google Search API AI Overview docs](https://serpapi.com/search-api#api-examples-results-for-ai-overview) and the [Google AI Overview API documentation](https://serpapi.com/google-ai-overview-api). Use the [SerpApi Playground](https://serpapi.com/playground) to find queries that currently return AI Overview data. diff --git a/docs/examples/08-google-news-monitoring.md b/docs/examples/08-google-news-monitoring.md new file mode 100644 index 0000000..0ebc9b3 --- /dev/null +++ b/docs/examples/08-google-news-monitoring.md @@ -0,0 +1,36 @@ +--- +title: "Google News Monitoring" +description: "Collect recent headlines for a topic with Google News." +--- + +# Google News Monitoring + +Use the Google News API for media monitoring, topic tracking, and alerting workflows. It returns news-focused result cards instead of general web results. + +## Search News + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_news", + q="artificial intelligence", + gl="us", + hl="en", +) + +for item in results.get("news_results", [])[:5]: + print(item.get("title")) + print(item.get("source", {}).get("name") or item.get("source")) + print(item.get("link")) +``` + +## What to Read + +Start with `news_results`. Save `title`, `link`, `source`, `date`, `snippet`, and `thumbnail` when present. News result shapes can vary by query, so inspect a sample response before deciding your storage schema. + +See the [Google News API documentation](https://serpapi.com/google-news-api) and tune your topic in the [SerpApi Playground](https://serpapi.com/playground). diff --git a/docs/examples/09-google-jobs-listings.md b/docs/examples/09-google-jobs-listings.md new file mode 100644 index 0000000..3ce45e7 --- /dev/null +++ b/docs/examples/09-google-jobs-listings.md @@ -0,0 +1,37 @@ +--- +title: "Google Jobs Listings" +description: "Search job listings by role and location." +--- + +# Google Jobs Listings + +Use the Google Jobs API to collect job cards for a role, market, or hiring workflow. It is useful for market maps, compensation research, and recruiting dashboards. + +## Search Jobs + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_jobs", + q="software engineer", + location="Austin, Texas", + hl="en", + gl="us", +) + +for job in results.get("jobs_results", [])[:5]: + print(job.get("title")) + print(job.get("company_name"), "-", job.get("location")) + print(job.get("via")) +``` + +## What to Read + +Use `jobs_results` for the listing cards. Typical fields include `title`, `company_name`, `location`, `via`, `description`, `detected_extensions`, and `related_links`. For detail pages, check whether the response includes identifiers or links that fit your workflow. + +See the [Google Jobs API documentation](https://serpapi.com/google-jobs-api) for localization and pagination parameters. Use the [SerpApi Playground](https://serpapi.com/playground) to test role/location combinations. diff --git a/docs/examples/10-youtube-video-search.md b/docs/examples/10-youtube-video-search.md new file mode 100644 index 0000000..c932372 --- /dev/null +++ b/docs/examples/10-youtube-video-search.md @@ -0,0 +1,34 @@ +--- +title: "YouTube Video Search" +description: "Search YouTube videos and read video result metadata." +--- + +# YouTube Video Search + +Use the YouTube Search API when you need video discovery results, channel references, or topic-level video monitoring. YouTube uses `search_query` instead of `q`. + +## Search Videos + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="youtube", + search_query="coffee brewing guide", +) + +for video in results.get("video_results", [])[:5]: + print(video.get("title")) + print(video.get("channel", {}).get("name")) + print(video.get("link")) +``` + +## What to Read + +Start with `video_results`. Useful fields include `title`, `link`, `channel`, `views`, `published_date`, `length`, and `thumbnail`. Some queries return additional sections such as channels, playlists, shorts, or related searches. + +See the [YouTube Search API documentation](https://serpapi.com/youtube-search-api) for YouTube-specific parameters. The [SerpApi Playground](https://serpapi.com/playground) is the quickest way to inspect the exact response shape for your query. diff --git a/docs/examples/11-amazon-product-search.md b/docs/examples/11-amazon-product-search.md new file mode 100644 index 0000000..21b74cd --- /dev/null +++ b/docs/examples/11-amazon-product-search.md @@ -0,0 +1,35 @@ +--- +title: "Amazon Product Search" +description: "Search Amazon products and read price, rating, delivery, and product identifiers." +--- + +# Amazon Product Search + +Use the Amazon Search API when you need product listings, prices, ratings, delivery details, sponsored products, or Amazon product identifiers. The Amazon engine uses `k` for the search query. + +## Search Products + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="amazon", + k="coffee grinder", + amazon_domain="amazon.com", +) + +for product in results.get("organic_results", [])[:5]: + print(product.get("title")) + print(product.get("price"), product.get("rating"), product.get("reviews")) + print(product.get("asin"), product.get("link_clean")) +``` + +## What to Read + +Start with `organic_results` for product cards. Useful fields include `title`, `asin`, `price`, `extracted_price`, `rating`, `reviews`, `thumbnail`, `delivery`, `prime`, `link_clean`, and `serpapi_link`. Some searches also return `product_ads`, `featured_products`, `video_results`, `filters`, and `related_searches`. + +For localization, sorting, category nodes, and Amazon-specific filters, see the [Amazon Search API documentation](https://serpapi.com/amazon-search-api). Use the [SerpApi Playground](https://serpapi.com/playground) to inspect result shapes for the product category you care about. diff --git a/docs/examples/12-walmart-product-search.md b/docs/examples/12-walmart-product-search.md new file mode 100644 index 0000000..8f24d0b --- /dev/null +++ b/docs/examples/12-walmart-product-search.md @@ -0,0 +1,36 @@ +--- +title: "Walmart Product Search" +description: "Search Walmart products and read pricing, reviews, shipping, and product IDs." +--- + +# Walmart Product Search + +Use the Walmart Search API for product search, price monitoring, catalog enrichment, and availability checks. Walmart uses `query` instead of `q`. + +## Search Products + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="walmart", + query="coffee maker", + walmart_domain="walmart.com", +) + +for product in results.get("organic_results", [])[:5]: + offer = product.get("primary_offer", {}) + print(product.get("title")) + print(offer.get("offer_price"), product.get("rating"), product.get("reviews")) + print(product.get("us_item_id"), product.get("product_page_url")) +``` + +## What to Read + +Start with `organic_results`. Useful fields include `title`, `us_item_id`, `product_id`, `rating`, `reviews`, `seller_name`, `primary_offer.offer_price`, `price_per_unit`, `out_of_stock`, `product_page_url`, and `serpapi_product_page_url`. + +Use `sort`, `min_price`, `max_price`, `store_id`, and `facet` when you need more targeted product monitoring. See the [Walmart Search API documentation](https://serpapi.com/walmart-search-api) for supported filters and pagination behavior. diff --git a/docs/examples/13-tripadvisor-travel-search.md b/docs/examples/13-tripadvisor-travel-search.md new file mode 100644 index 0000000..c45ee96 --- /dev/null +++ b/docs/examples/13-tripadvisor-travel-search.md @@ -0,0 +1,35 @@ +--- +title: "Tripadvisor Travel Search" +description: "Search Tripadvisor places, hotels, restaurants, and attractions." +--- + +# Tripadvisor Travel Search + +Use the Tripadvisor Search API when you need destination, hotel, restaurant, attraction, or forum search results from Tripadvisor. The `ssrc` parameter narrows the search to a result type such as hotels, restaurants, or things to do. + +## Search Places + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="tripadvisor", + q="Rome", + ssrc="h", +) + +for place in results.get("places", [])[:5]: + print(place.get("title")) + print(place.get("place_type"), place.get("location")) + print(place.get("link")) +``` + +## What to Read + +Start with `places`. Useful fields include `title`, `place_type`, `place_id`, `location`, `description`, `thumbnail`, `link`, and `serpapi_link`. + +Use `ssrc` to focus the search: `h` for hotels, `r` for restaurants, `A` for things to do, `g` for destinations, and `a` for all results. See the [Tripadvisor Search API documentation](https://serpapi.com/tripadvisor-search-api) for the current filter and pagination options. diff --git a/docs/examples/14-google-shopping-price-monitoring.md b/docs/examples/14-google-shopping-price-monitoring.md new file mode 100644 index 0000000..c330c91 --- /dev/null +++ b/docs/examples/14-google-shopping-price-monitoring.md @@ -0,0 +1,41 @@ +--- +title: "Google Shopping Price Monitoring" +description: "Filter Google Shopping results by price and read product cards for monitoring workflows." +--- + +# Google Shopping Price Monitoring + +Use the Google Shopping API when you need product cards from many merchants. For price monitoring, combine query, market, price filters, and selected result fields. + +## Search Filtered Products + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_shopping", + q="espresso machine", + location="Austin, Texas", + gl="us", + hl="en", + min_price=100, + max_price=800, + sort_by=1, + json_restrictor="shopping_results[].{title, price, source, rating, reviews, link}", +) + +for product in results.get("shopping_results", [])[:5]: + print(product.get("title")) + print(product.get("price"), product.get("source")) + print(product.get("rating"), product.get("reviews")) +``` + +## What to Read + +Start with `shopping_results`. Useful fields include `title`, `product_id`, `price`, `extracted_price`, `source`, `rating`, `reviews`, `thumbnail`, `delivery`, `product_link`, and `serpapi_immersive_product_api`. + +Use `min_price`, `max_price`, `sort_by`, `free_shipping`, and `on_sale` for monitoring workflows. For pagination, prefer `serpapi_pagination.next` over hand-built offsets when it is present. See the [Google Shopping API documentation](https://serpapi.com/google-shopping-api) for the full parameter set. diff --git a/docs/examples/15-duckduckgo-search.md b/docs/examples/15-duckduckgo-search.md new file mode 100644 index 0000000..275edfe --- /dev/null +++ b/docs/examples/15-duckduckgo-search.md @@ -0,0 +1,33 @@ +--- +title: "DuckDuckGo Search" +description: "Run a DuckDuckGo search and read organic result fields." +--- + +# DuckDuckGo Search + +Use the DuckDuckGo Search API when you need another privacy-oriented web result source alongside Google and Bing. Start with a simple query, then add region and time filters when your workflow needs them. + +## Search DuckDuckGo + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="duckduckgo", + q="coffee", +) + +for result in results.get("organic_results", [])[:5]: + print(result.get("position"), result.get("title")) + print(result.get("link")) +``` + +## What to Read + +Most workflows start with `organic_results`. Useful fields include `title`, `link`, `snippet`, `position`, and any rich result blocks returned for the query. + +See the [DuckDuckGo Search API documentation](https://serpapi.com/duckduckgo-search-api) for region, date, and safe-search options. diff --git a/docs/examples/16-baidu-search.md b/docs/examples/16-baidu-search.md new file mode 100644 index 0000000..b4f8ce1 --- /dev/null +++ b/docs/examples/16-baidu-search.md @@ -0,0 +1,33 @@ +--- +title: "Baidu Search" +description: "Search Baidu results for China-focused research workflows." +--- + +# Baidu Search + +Use the Baidu Search API when your application needs results from Baidu's web index. It is useful for China-focused SEO checks, market research, and search result monitoring. + +## Search Baidu + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="baidu", + q="coffee", +) + +for result in results.get("organic_results", [])[:5]: + print(result.get("position"), result.get("title")) + print(result.get("link")) +``` + +## What to Read + +Start with `organic_results`, then inspect any top-level result blocks returned by the query. Baidu result shapes can vary by keyword, so store only fields you have observed in sample responses. + +See the [Baidu Search API documentation](https://serpapi.com/baidu-search-api) for supported filters. diff --git a/docs/examples/17-google-local-services.md b/docs/examples/17-google-local-services.md new file mode 100644 index 0000000..4591da3 --- /dev/null +++ b/docs/examples/17-google-local-services.md @@ -0,0 +1,35 @@ +--- +title: "Google Local Services" +description: "Read Google Local Services ad cards for a service category." +--- + +# Google Local Services + +Use the Google Local Services API when you need local services ad data for a category, provider, or market. It returns ad cards rather than general Google Maps place results. + +## Search Local Services + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_local_services", + q="electrician", + data_cid="6745062158417646970", +) + +for ad in results.get("local_ads", [])[:5]: + print(ad.get("title")) + print(ad.get("rating"), ad.get("reviews")) + print(ad.get("phone")) +``` + +## What to Read + +Start with `local_ads`. Useful fields include `title`, `rating`, `reviews`, `phone`, `service_area`, `years_in_business`, and `link` when present. + +See the [Google Local Services API documentation](https://serpapi.com/google-local-services-api) for query and provider detail options. diff --git a/docs/examples/18-ebay-product-listings.md b/docs/examples/18-ebay-product-listings.md new file mode 100644 index 0000000..a58bf4b --- /dev/null +++ b/docs/examples/18-ebay-product-listings.md @@ -0,0 +1,34 @@ +--- +title: "eBay Product Listings" +description: "Search eBay listings and read product, price, and seller fields." +--- + +# eBay Product Listings + +Use the eBay Search API when you need marketplace listings, prices, condition data, or seller result pages. eBay uses `_nkw` for the search keyword. + +## Search eBay + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="ebay", + _nkw="coffee", +) + +for listing in results.get("organic_results", [])[:5]: + print(listing.get("title")) + print(listing.get("price"), listing.get("condition")) + print(listing.get("link")) +``` + +## What to Read + +Start with `organic_results`. Useful fields include `title`, `price`, `condition`, `shipping`, `location`, `seller`, `thumbnail`, and `link`. + +See the [eBay Search API documentation](https://serpapi.com/ebay-search-api) for filters, sorting, and pagination. diff --git a/docs/examples/19-home-depot-product-search.md b/docs/examples/19-home-depot-product-search.md new file mode 100644 index 0000000..6e8b0c3 --- /dev/null +++ b/docs/examples/19-home-depot-product-search.md @@ -0,0 +1,34 @@ +--- +title: "Home Depot Product Search" +description: "Search Home Depot product cards and read price, rating, and product identifiers." +--- + +# Home Depot Product Search + +Use The Home Depot Search API for home improvement product discovery, price tracking, and catalog enrichment. Start with a broad query and then add filters once you know the category shape. + +## Search Products + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="home_depot", + q="table", +) + +for product in results.get("products", [])[:5]: + print(product.get("title")) + print(product.get("price"), product.get("rating")) + print(product.get("product_id")) +``` + +## What to Read + +Start with `products`. Useful fields include `title`, `product_id`, `price`, `rating`, `reviews`, `brand`, `thumbnail`, and product URLs when present. + +See the [The Home Depot Search API documentation](https://serpapi.com/home-depot-search-api) for product filters and pagination. diff --git a/docs/examples/20-google-events-discovery.md b/docs/examples/20-google-events-discovery.md new file mode 100644 index 0000000..a3df9bd --- /dev/null +++ b/docs/examples/20-google-events-discovery.md @@ -0,0 +1,34 @@ +--- +title: "Google Events Discovery" +description: "Search Google Events for upcoming event cards." +--- + +# Google Events Discovery + +Use the Google Events API when you need event cards for a topic, venue, or local market. It returns event-specific metadata instead of general organic search results. + +## Search Events + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_events", + q="coffee", +) + +for event in results.get("events_results", [])[:5]: + print(event.get("title")) + print(event.get("date", {}).get("when")) + print(event.get("address")) +``` + +## What to Read + +Start with `events_results`. Useful fields include `title`, `date`, `address`, `link`, `ticket_info`, `venue`, and `description` when present. + +See the [Google Events API documentation](https://serpapi.com/google-events-api) for date and location parameters. diff --git a/docs/examples/21-google-images-search.md b/docs/examples/21-google-images-search.md new file mode 100644 index 0000000..1839d71 --- /dev/null +++ b/docs/examples/21-google-images-search.md @@ -0,0 +1,35 @@ +--- +title: "Google Images Search" +description: "Search Google Images and read image result metadata." +--- + +# Google Images Search + +Use the Google Images API when you need image discovery results, thumbnails, sources, and original image links. + +## Search Images + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_images", + tbm="isch", + q="coffee", +) + +for image in results.get("images_results", [])[:5]: + print(image.get("title")) + print(image.get("source")) + print(image.get("original")) +``` + +## What to Read + +Start with `images_results`. Useful fields include `title`, `source`, `link`, `thumbnail`, `original`, `original_width`, and `original_height`. + +See the [Google Images API documentation](https://serpapi.com/google-images-api) for image filters and pagination. diff --git a/docs/examples/22-google-scholar-research.md b/docs/examples/22-google-scholar-research.md new file mode 100644 index 0000000..9413ea8 --- /dev/null +++ b/docs/examples/22-google-scholar-research.md @@ -0,0 +1,34 @@ +--- +title: "Google Scholar Research" +description: "Search Google Scholar publications and read citation-focused fields." +--- + +# Google Scholar Research + +Use the Google Scholar API when you need publication search results, citation counts, author links, or research monitoring workflows. + +## Search Scholar + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_scholar", + q="coffee", +) + +for result in results.get("organic_results", [])[:5]: + print(result.get("title")) + print(result.get("publication_info", {}).get("summary")) + print(result.get("inline_links", {}).get("cited_by", {}).get("total")) +``` + +## What to Read + +Start with `organic_results`. Useful fields include `title`, `link`, `publication_info`, `snippet`, `resources`, and `inline_links.cited_by`. + +See the [Google Scholar API documentation](https://serpapi.com/google-scholar-api) for author, citation, and date filters. diff --git a/docs/examples/23-google-play-store-apps.md b/docs/examples/23-google-play-store-apps.md new file mode 100644 index 0000000..5316dee --- /dev/null +++ b/docs/examples/23-google-play-store-apps.md @@ -0,0 +1,36 @@ +--- +title: "Google Play Store Apps" +description: "Search Google Play app results and read app store metadata." +--- + +# Google Play Store Apps + +Use the Google Play Store API when you need app search results, app metadata, ratings, or links into Google Play. + +## Search Apps + +```python +import os +import serpapi + + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) + +results = client.search( + engine="google_play", + q="kite", + store="apps", + max_results="2", +) + +for app in results.get("organic_results", [])[:5]: + print(app.get("title")) + print(app.get("rating"), app.get("downloads")) + print(app.get("link")) +``` + +## What to Read + +Start with `organic_results`. Useful fields include `title`, `link`, `rating`, `downloads`, `description`, `thumbnail`, and app identifiers. + +See the [Google Play Store API documentation](https://serpapi.com/google-play-api) for store, device, and localization options. diff --git a/docs/examples/index.qmd b/docs/examples/index.qmd new file mode 100644 index 0000000..3ebd1f1 --- /dev/null +++ b/docs/examples/index.qmd @@ -0,0 +1,188 @@ +--- +title: "Examples" +description: "Starter recipes grouped by API category." +--- + +# Examples + +Use these examples as starting points, then check the linked SerpApi API documentation for engine-specific parameters. The categories below follow the API list published in [SerpApi llms.txt](https://serpapi.com/llms.txt). + +## Starter Examples + +**Search Engines** + +- [Google Across Countries](google-across-countries.md) +- [Bing Search](bing-search.md) +- [DuckDuckGo Search](duckduckgo-search.md) +- [Baidu Search](baidu-search.md) + +**AI Answers** + +- [Google AI Overview](google-ai-overview.md) + +**Local and Maps** + +- [Google Maps Local Businesses](google-maps-local-business.md) +- [Google Local Services](google-local-services.md) + +**Shopping and Marketplaces** + +- [Google Shopping Products](google-shopping-products.md) +- [Google Shopping Price Monitoring](google-shopping-price-monitoring.md) +- [Amazon Product Search](amazon-product-search.md) +- [Walmart Product Search](walmart-product-search.md) +- [eBay Product Listings](ebay-product-listings.md) +- [Home Depot Product Search](home-depot-product-search.md) + +**Travel and Hospitality** + +- [Google Flights Travel](google-flights-travel.md) +- [Tripadvisor Travel Search](tripadvisor-travel-search.md) + +**Finance, Trends, Jobs, and Events** + +- [Google Finance Market Data](google-finance-market-data.md) +- [Google Trends Demand](google-trends-demand.md) +- [Google Jobs Listings](google-jobs-listings.md) +- [Google Events Discovery](google-events-discovery.md) + +**Media, Apps, and Research** + +- [YouTube Video Search](youtube-video-search.md) +- [Google Images Search](google-images-search.md) +- [Google Scholar Research](google-scholar-research.md) +- [Google Play Store Apps](google-play-store-apps.md) + +## Supported API Map + +**Search Engines** + +- [Google Search API](https://serpapi.com/search-api) +- [Google Light Search API](https://serpapi.com/google-light-api) +- [Bing Search API](https://serpapi.com/bing-search-api) +- [DuckDuckGo Search API](https://serpapi.com/duckduckgo-search-api) +- [DuckDuckGo Light API](https://serpapi.com/duckduckgo-light-api) +- [Baidu Search API](https://serpapi.com/baidu-search-api) +- [Yahoo! Search API](https://serpapi.com/yahoo-search-api) +- [Yandex Search API](https://serpapi.com/yandex-search-api) +- [Naver Search API](https://serpapi.com/naver-search-api) + +**AI Answers** + +- [Google AI Mode API](https://serpapi.com/google-ai-mode-api) +- [Google AI Overview API](https://serpapi.com/google-ai-overview-api) +- [Bing Copilot API](https://serpapi.com/bing-copilot-api) +- [Brave AI Mode API](https://serpapi.com/brave-ai-mode-api) +- [Naver AI Overview API](https://serpapi.com/naver-ai-overview-api) + +**Local and Maps** + +- [Google Local API](https://serpapi.com/google-local-api) +- [Google Local Services API](https://serpapi.com/google-local-services-api) +- [Google Maps API](https://serpapi.com/google-maps-api) +- [Google Maps Photos API](https://serpapi.com/google-maps-photos-api) +- [Google Maps Autocomplete API](https://serpapi.com/google-maps-autocomplete-api) +- [Google Maps Directions API](https://serpapi.com/google-maps-directions-api) +- [Google Maps Posts API](https://serpapi.com/google-maps-posts-api) +- [Google Maps Reviews API](https://serpapi.com/google-maps-reviews-api) +- [Google Maps Contributor Reviews API](https://serpapi.com/google-maps-contributor-reviews-api) +- [Apple Maps API](https://serpapi.com/apple-maps-api) +- [Apple Maps Places API](https://serpapi.com/apple-maps-places-api) +- [Bing Maps API](https://serpapi.com/bing-maps-api) +- [DuckDuckGo Maps API](https://serpapi.com/duckduckgo-maps-api) +- [Yelp Search API](https://serpapi.com/yelp-search-api) +- [Yelp Place API](https://serpapi.com/yelp-place) +- [Yelp Reviews API](https://serpapi.com/yelp-reviews-api) + +**Shopping and Marketplaces** + +- [Google Shopping API](https://serpapi.com/google-shopping-api) +- [Google Shopping Light API](https://serpapi.com/google-shopping-light-api) +- [Google Immersive Product API](https://serpapi.com/google-immersive-product-api) +- [Amazon Search API](https://serpapi.com/amazon-search-api) +- [Amazon Product API](https://serpapi.com/amazon-product-api) +- [Walmart Search API](https://serpapi.com/walmart-search-api) +- [Walmart Product API](https://serpapi.com/walmart-product-api) +- [Walmart Reviews API](https://serpapi.com/walmart-product-reviews-api) +- [eBay Search API](https://serpapi.com/ebay-search-api) +- [eBay Product API](https://serpapi.com/ebay-product-api) +- [The Home Depot Search API](https://serpapi.com/home-depot-search-api) +- [The Home Depot Product API](https://serpapi.com/home-depot-product) +- [The Home Depot Reviews API](https://serpapi.com/home-depot-product-reviews) +- [Bing Shopping API](https://serpapi.com/bing-shopping-api) +- [Bing Product API](https://serpapi.com/bing-product-api) +- [Yahoo! Shopping API](https://serpapi.com/yahoo-shopping-search-api) + +**Travel and Hospitality** + +- [Google Flights API](https://serpapi.com/google-flights-api) +- [Google Flights Autocomplete API](https://serpapi.com/google-flights-autocomplete-api) +- [Google Flights Deals API](https://serpapi.com/google-flights-deals-api) +- [Google Hotels API](https://serpapi.com/google-hotels-api) +- [Google Hotels Autocomplete API](https://serpapi.com/google-hotels-autocomplete-api) +- [Google Hotels Photos API](https://serpapi.com/google-hotels-photos-api) +- [Google Hotels Reviews API](https://serpapi.com/google-hotels-reviews-api) +- [Google Travel Explore API](https://serpapi.com/google-travel-explore-api) +- [Tripadvisor Search API](https://serpapi.com/tripadvisor-search-api) +- [Tripadvisor Place API](https://serpapi.com/tripadvisor-place-api) +- [Tripadvisor Reviews API](https://serpapi.com/tripadvisor-reviews-api) +- [OpenTable Reviews API](https://serpapi.com/open-table-reviews-api) + +**News, Trends, Events, and Demand** + +- [Google News API](https://serpapi.com/google-news-api) +- [Google News Light API](https://serpapi.com/google-news-light-api) +- [Bing News API](https://serpapi.com/bing-news-api) +- [DuckDuckGo News API](https://serpapi.com/duckduckgo-news-api) +- [Baidu News API](https://serpapi.com/baidu-news-api) +- [Google Trends API](https://serpapi.com/google-trends-api) +- [Google Trends Autocomplete API](https://serpapi.com/google-trends-autocomplete) +- [Google Trends Trending Now API](https://serpapi.com/google-trends-trending-now) +- [Google Events API](https://serpapi.com/google-events-api) +- [Google Sports API](https://serpapi.com/google-sports-api) +- [Google Forums API](https://serpapi.com/google-forums-api) + +**Media, Apps, and Social** + +- [Google Images API](https://serpapi.com/google-images-api) +- [Google Images Light API](https://serpapi.com/google-images-light-api) +- [Google Lens API](https://serpapi.com/google-lens-api) +- [Google Reverse Image API](https://serpapi.com/google-reverse-image) +- [Google Videos API](https://serpapi.com/google-videos-api) +- [Google Videos Light API](https://serpapi.com/google-videos-light-api) +- [Google Short Videos API](https://serpapi.com/google-short-videos-api) +- [Bing Images API](https://serpapi.com/bing-images-api) +- [Bing Reverse Image API](https://serpapi.com/bing-reverse-image-api) +- [Bing Videos API](https://serpapi.com/bing-videos-api) +- [Yahoo! Images API](https://serpapi.com/yahoo-images-api) +- [Yahoo! Videos API](https://serpapi.com/yahoo-videos-api) +- [Yandex Images API](https://serpapi.com/yandex-images-api) +- [Yandex Videos API](https://serpapi.com/yandex-videos-api) +- [YouTube Search API](https://serpapi.com/youtube-search-api) +- [YouTube Video API](https://serpapi.com/youtube-video-api) +- [YouTube Video Transcript API](https://serpapi.com/youtube-video-transcript) +- [Apple App Store API](https://serpapi.com/apple-app-store) +- [Apple App Store Reviews API](https://serpapi.com/apple-reviews) +- [Apple App Store Product API](https://serpapi.com/apple-product) +- [Google Play Store API](https://serpapi.com/google-play-api) +- [Google Play Games API](https://serpapi.com/google-play-games) +- [Google Play Movies API](https://serpapi.com/google-play-movies) +- [Google Play Books API](https://serpapi.com/google-play-books) +- [Google Play Product API](https://serpapi.com/google-play-product-api) +- [Facebook Profile API](https://serpapi.com/facebook-profile-api) +- [Instagram Profile API](https://serpapi.com/instagram-profile-api) + +**Research, Knowledge, Ads, Finance, and Jobs** + +- [Google Scholar API](https://serpapi.com/google-scholar-api) +- [Google Scholar Author API](https://serpapi.com/google-scholar-author-api) +- [Google Scholar Case Law API](https://serpapi.com/google-scholar-case-law-api) +- [Google Patents API](https://serpapi.com/google-patents-api) +- [Google Patents Details API](https://serpapi.com/google-patents-details-api) +- [Google Related Questions API](https://serpapi.com/google-related-questions-api) +- [Google Autocomplete API](https://serpapi.com/google-autocomplete-api) +- [Google Ads API](https://serpapi.com/google-ads-api) +- [Google Ads Transparency API](https://serpapi.com/google-ads-transparency-center-api) +- [Google Finance API](https://serpapi.com/google-finance-api) +- [Google Finance Markets API](https://serpapi.com/google-finance-markets) +- [Google Jobs API](https://serpapi.com/google-jobs-api) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..801134d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,133 @@ +--- +title: "SerpApi Python Library & Package" +description: "Official Python client for SerpApi search data in applications, AI workflows, RAG, and data pipelines." +--- + +Integrate search data into your AI workflow, RAG or fine-tuning pipeline, Python application, or data product using the official wrapper for [SerpApi](https://serpapi.com). + +SerpApi supports Google, Google Maps, Google Shopping, Bing, DuckDuckGo, Baidu, Yandex, Yahoo, eBay, YouTube, App Stores, Walmart, Home Depot, Naver, and many more engines. + +Query a wide range of data at scale, including web search results, local business listings, shopping results, flight schedules, stock market data, job listings, trends, news headlines, AI Overview results, and video search results. + +## Install + +:::{.panel-tabset} + +## pip + +```bash +pip install serpapi +``` + +## uv + +```bash +uv add serpapi +``` + +::: + +Python 3.6 or newer is required by the package. + +## First Request + +Sign up at [SerpApi](https://serpapi.com/users/sign_up), copy your API key from the [dashboard](https://serpapi.com/manage-api-key), and set it in your shell: + +:::{.panel-tabset} + +## macOS / Linux + +```bash +export SERPAPI_KEY="secret_api_key" +``` + +## Windows + +```powershell +$env:SERPAPI_KEY = "secret_api_key" +``` + +::: + +```python +import os +import serpapi + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) +results = client.search( + engine="google", + q="coffee", + location="Austin, Texas", + hl="en", + gl="us", +) + +print(results["organic_results"][0]["link"]) +``` + +The `results` variable contains a `SerpResults` object. It behaves like a standard dictionary and adds convenience helpers for response conversion, pagination, and fetching search archives. + +Request parameters map directly to the SerpApi HTTP API. For the full engine list and engine-specific parameters, use the [SerpApi API documentation](https://serpapi.com/search-api). Use the [SerpApi Playground](https://serpapi.com/playground) to build and test a request before moving it into Python. + +:::{.docs-home-nav} + +:::{.docs-home-nav__intro} + +## Documentation Map + +Choose the path that matches what you are building. Start with setup and a first request, then move into client behavior, request parameters, pagination, error handling, or engine-specific examples. + +- New integrations: read [Getting Started](user-guide/getting-started.md), then [Client Usage](user-guide/client-usage.md). +- Existing `google-search-results` users: follow the [Migration Guide](user-guide/migrating-from-google-search-results.md). +- Engine setup: use [Parameters and Engines](user-guide/parameters-and-engines.md) with the [SerpApi Playground](https://serpapi.com/playground). +- Production workflows: review [pagination](user-guide/pagination.md), [timeouts and errors](user-guide/errors-and-timeouts.md), [request options](user-guide/request-options.md), [account/location helpers](user-guide/account-and-locations.md), [async search archive](user-guide/async-search-archive.md), [JSON Restrictor](user-guide/json-restrictor.md), and [zero trace controls](user-guide/zero-trace.md). +- [Examples](docs/examples/index.qmd): browse focused recipes grouped by search engines, AI answers, local/maps, shopping, travel, finance, trends, jobs, events, media, apps, and research. + +
+ +::: + +:::{.docs-home-nav__sidebar} + +### User Guide + +- [Getting Started](user-guide/getting-started.md) +- [Client Usage](user-guide/client-usage.md) +- [Parameters and Engines](user-guide/parameters-and-engines.md) +- [Pagination](user-guide/pagination.md) +- [Errors and Timeouts](user-guide/errors-and-timeouts.md) +- [Account and Locations](user-guide/account-and-locations.md) + +### Migration + +- [Migrating from google-search-results](user-guide/migrating-from-google-search-results.md) + +### Advanced Usage + +- [Async Search Archive](user-guide/async-search-archive.md) +- [Parallel Requests with Threads](user-guide/threading.md) +- [Parallel Requests with Multiprocessing](user-guide/multiprocessing.md) +- [Zero Trace and Cache Controls](user-guide/zero-trace.md) +- [JSON Restrictor](user-guide/json-restrictor.md) +- [Request Options](user-guide/request-options.md) + +### Examples + +- [Examples Overview](docs/examples/index.qmd) +- Search Engines: [Google](docs/examples/google-across-countries.md), [Bing](docs/examples/bing-search.md), [DuckDuckGo](docs/examples/duckduckgo-search.md), [Baidu](docs/examples/baidu-search.md) +- AI Answers: [Google AI Overview](docs/examples/google-ai-overview.md) +- Local and Maps: [Google Maps](docs/examples/google-maps-local-business.md), [Google Local Services](docs/examples/google-local-services.md) +- Shopping and Marketplaces: [Google Shopping](docs/examples/google-shopping-products.md), [Amazon](docs/examples/amazon-product-search.md), [Walmart](docs/examples/walmart-product-search.md), [eBay](docs/examples/ebay-product-listings.md), [Home Depot](docs/examples/home-depot-product-search.md) +- Travel and Hospitality: [Google Flights](docs/examples/google-flights-travel.md), [Tripadvisor](docs/examples/tripadvisor-travel-search.md) +- Finance, Trends, Jobs, and Events: [Google Finance](docs/examples/google-finance-market-data.md), [Google Trends](docs/examples/google-trends-demand.md), [Google Jobs](docs/examples/google-jobs-listings.md), [Google Events](docs/examples/google-events-discovery.md) +- Media, Apps, and Research: [YouTube](docs/examples/youtube-video-search.md), [Google Images](docs/examples/google-images-search.md), [Google Scholar](docs/examples/google-scholar-research.md), [Google Play](docs/examples/google-play-store-apps.md) + +::: + +::: diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 717c69a..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,191 +0,0 @@ -.. serpapi-python documentation master file, created by - sphinx-quickstart on Sun Apr 3 21:09:40 2022. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -**serpapi-python** -================== - -an official Python client library for `SerpApi.*?)```",
+ re.DOTALL,
+)
+API_KEY = os.environ.get("SERPAPI_KEY") or os.environ.get("API_KEY")
+
+
+def docs_pages():
+ return [
+ ROOT / "README.md",
+ ROOT / "docs" / "index.md",
+ *sorted((ROOT / "docs" / "user_guide").glob("*.md")),
+ *sorted((ROOT / "docs" / "examples").glob("*.md")),
+ ]
+
+
+def runnable_block(block):
+ if API_KEY is None:
+ return block
+
+ return (
+ block
+ .replace('"secret_api_key"', repr(API_KEY))
+ .replace("'secret_api_key'", repr(API_KEY))
+ )
+
+
+@pytest.mark.skipif(API_KEY is None, reason="SERPAPI_KEY or API_KEY is required")
+@pytest.mark.parametrize("path", docs_pages(), ids=lambda path: path.relative_to(ROOT).as_posix())
+def test_markdown_python_blocks_execute(path, monkeypatch):
+ monkeypatch.setenv("SERPAPI_KEY", API_KEY)
+ monkeypatch.setenv("API_KEY", API_KEY)
+
+ blocks = list(PYTHON_BLOCK_RE.finditer(path.read_text(encoding="utf-8")))
+ assert blocks, f"{path} has no Python examples"
+
+ namespace = {
+ "__name__": "docs_examples",
+ "client": serpapi.Client(api_key=API_KEY, timeout=20),
+ "os": os,
+ "serpapi": serpapi,
+ }
+ for number, block in enumerate(blocks, start=1):
+ if block.group("skip"):
+ continue
+
+ code = runnable_block(block.group("code"))
+ exec(compile(code, f"{path}::python-block-{number}", "exec"), namespace)