├── .github └── workflows │ └── main.yaml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── google_serp_api ├── __init__.py ├── __version__.py ├── client.py ├── default_headers.py └── example │ └── example.py ├── requirements.txt ├── setup.py └── tox.ini /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: lint-test-publish 2 | 3 | on: [push] 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | - name: Install dependencies 11 | run: | 12 | make deps 13 | - name: Lint code 14 | run: | 15 | make lint 16 | 17 | test: 18 | runs-on: ubuntu-20.04 19 | strategy: 20 | matrix: 21 | python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Set up Python 25 | uses: actions/setup-python@v2 26 | with: 27 | python-version: ${{ matrix.python-version }} 28 | - name: Install dependencies 29 | run: | 30 | make deps 31 | 32 | publish: 33 | if: github.ref == 'refs/heads/main' 34 | needs: [lint, test] 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Install dependencies 39 | run: | 40 | make deps 41 | - name: Build package 42 | run: >- 43 | make build 44 | # - name: Publish package to Test PyPI (always) 45 | # uses: pypa/gh-action-pypi-publish@release/v1 46 | # with: 47 | # password: ${{ secrets.TEST_PYPI_API_TOKEN }} 48 | # repository_url: https://test.pypi.org/legacy/ 49 | # skip_existing: true 50 | - name: Publish package to PyPI (only if pushing a tag) 51 | if: startsWith(github.ref, 'refs/tags') 52 | uses: pypa/gh-action-pypi-publish@release/v1 53 | with: 54 | password: ${{ secrets.PYPI_API_TOKEN }} 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Scrapeit Cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: ## Install package from source in edit mode 2 | pip install -e . 3 | 4 | deps: ## Install development dependencies 5 | pip install -r requirements.txt 6 | 7 | lint: ## Lint code 8 | flake8 --config flake8 google_serp_api/ setup.py 9 | 10 | build: ## Build a binary wheel and a source tarball 11 | python setup.py sdist bdist_wheel 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hasdata Python Google SERP API SDK 2 | 3 | The Google SERP API provides real-time access to structured Google search results, offering no blocks or CAPTCHAs. 4 | 5 | ## Table of Contents 6 | 7 | 1. [Installation](#installation) 8 | 2. [Getting Started](#getting-started) 9 | - [Obtaining HasData API Key](#obtaining-hasdata-api-key) 10 | - [Basic Usage Example](#basic-usage-example) 11 | - [Usage](#usage) 12 | 4. [Request Headers](#request-headers) 13 | 5. [Supported Parameters](#supported-parameters) 14 | 6. [Advanced Features](#advanced-features) 15 | 7. [Best Practices](#best-practices) 16 | 8. [Troubleshooting](#troubleshooting) 17 | 18 | ## Installation 19 | 20 | To use the Hasdata Python Google SERP API SDK, you can install it: 21 | 22 | ```bash 23 | pip install google-serp-api 24 | ``` 25 | 26 | ## Getting Started 27 | 28 | ### Obtaining HasData API Key 29 | Signup to HasData to [get your API key](https://app.hasdata.com/sign-up) and some free credits to get started. 30 | 31 | ### Basic Usage Example 32 | 33 | ```python 34 | from google_serp_api import GoogleSerpApi 35 | 36 | api_key = os.getenv('HASDATA_API_KEY', 'INSERT_YOUR_API_KEY_HERE') 37 | 38 | client = GoogleSerpApi(api_key) 39 | try: 40 | query = { 41 | "q": "Coffee", 42 | "location": "Austin,Texas,United States", 43 | "domain": "google.com", 44 | "gl": "us" 45 | } 46 | response = client.getSearchResults(query) 47 | data = response.json() 48 | print(data) 49 | except Exception as e: 50 | print(f"Error occurred: {e}") 51 | 52 | ``` 53 | 54 | ### Usage 55 | 56 | To make API requests using the SDK, follow these steps: 57 | 58 | 1. Import the `GoogleSerpApi` class from the SDK: 59 | 60 | ```python 61 | from google_serp_api import GoogleSerpApi 62 | ``` 63 | 64 | 2. Replace `'INSERT_YOUR_API_KEY_HERE'` with your actual API key: 65 | 66 | ```python 67 | api_key = 'YOUR_HASDATA_API_KEY' 68 | ``` 69 | 70 | 3. Create an instance of the `GoogleSerpApi` class with your API key: 71 | 72 | ```python 73 | client = GoogleSerpApi(api_key=api_key) 74 | ``` 75 | 76 | 4. Specify the search parameters in a dictionary: 77 | 78 | ```python 79 | params = { 80 | "q": "Coffee", 81 | "location": "Austin,Texas,United States", 82 | "domain": "google.com", 83 | "gl": "us" 84 | } 85 | ``` 86 | 87 | 5. Make the API request using the `getSearchResults` method and get the response: 88 | 89 | ```python 90 | response = client.getSearchResults(params=params) 91 | ``` 92 | 93 | 6. Access the response data as text: 94 | 95 | ```python 96 | print(response.text) 97 | ``` 98 | 99 | ## Request Headers 100 | 101 | | Parameter | Description | 102 | |---------------|-------------| 103 | | x-api-key | Your secret API key 104 | 105 | ## Supported Parameters 106 | 107 | The SDK supports various parameters that allow you to customize your requests. Here are the supported parameters: 108 | 109 | | Parameter | Default Value | Description | Example | 110 | |-----------|-------------|---------|---------| 111 | |q|-|**Required**. Specify the search term for which you want to scrape the SERP.|`q=Coffee`| 112 | |location|-|**Optional**. Google canonical location for the search.|`location=Austin,Texas,United States`| 113 | |domain|google.com|**Optional**. Google domain to use. Default is google.com.|`domain=google.com`| 114 | |gl|us|**Optional**. The two-letter country code for the country you want to limit the search to.|`gl=us`| 115 | 116 | For more details on each parameter, refer to the [Hasdata documentation](https://docs.hasdata.com/google-serp/serp). 117 | 118 | ## Advanced Features 119 | 120 | The Hasdata Python Google SERP API SDK also supports advanced features to enhance your requests. These features include pagination and filtering options, allowing you to customize and refine your queries. The [documentation](https://docs.hasdata.com/google-serp/serp) provides additional information on advanced parameters. 121 | 122 | ## Best Practices 123 | 124 | To ensure a smooth experience and optimal performance while using the Hasdata Python Google SERP API SDK, consider the following best practices: 125 | To ensure a smooth experience and optimal performance while using the Hasdata Python Google SERP API SDK, consider the following best practices: 126 | 127 | 1. **Review API Documentation**: Familiarize yourself with the API documentation to understand all available parameters, response formats, and potential limitations. This will help you make effective API requests and interpret the responses accurately. 128 | 129 | 2. **Use Rate Limiting**: Implement rate limiting in your code to avoid exceeding the API's rate limits. Abiding by rate limits ensures fair usage and prevents unnecessary disruptions to your API access. 130 | 131 | 3. **Test with Sample Queries**: Before making extensive use of the API, perform test queries with sample data to understand the API's behavior and validate your implementation. 132 | 133 | 4. **Monitor API Usage**: Regularly monitor your API usage and keep track of your credit balance. This allows you to manage your resources effectively and plan accordingly for your project's needs. 134 | 135 | 5. **Keep Credentials Secure**: Safeguard your API key and other sensitive credentials. Avoid hardcoding them in your code or publicly sharing them. Use environment variables or secure configuration methods to store such information. 136 | 137 | By following these best practices, you can effectively utilize the Hasdata Python Google SERP API SDK and maximize the benefits of web scraping, SEO research, competitor analysis, and market research with accurate and valuable data. 138 | 139 | ## Troubleshooting 140 | 141 | If you encounter issues while using the Hasdata Python Google SERP API SDK, consider the following troubleshooting steps: 142 | 143 | 1. **Check your API Key**: Ensure that you have provided the correct API key in the request headers. Double-check for any typos or extra spaces in the API key. 144 | 145 | 2. **Verify Request Parameters**: Review the parameters used in your API request and make sure that all required fields are provided and properly formatted. Incorrect parameters can lead to unexpected results or errors. 146 | 147 | 3. **Inspect API Response**: Examine the API response for any error messages or status codes. The response may provide valuable insights into the issue, such as invalid queries or authentication problems. 148 | 149 | 4. **Monitor Credit and Rate Limits**: Ensure that you are not exceeding your plan's credit limits or rate limits. Regularly monitor your API usage and consider implementing rate-limiting logic to avoid hitting the rate limits. -------------------------------------------------------------------------------- /google_serp_api/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['GoogleSerpApi'] 2 | 3 | from google_serp_api.client import GoogleSerpApi 4 | -------------------------------------------------------------------------------- /google_serp_api/__version__.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.0.5' 2 | -------------------------------------------------------------------------------- /google_serp_api/client.py: -------------------------------------------------------------------------------- 1 | from requests import request, Response 2 | from typing import TypedDict, Optional 3 | 4 | import urllib.parse 5 | 6 | from .default_headers import default_headers 7 | 8 | 9 | class GetSearchResultsParams(TypedDict, total=False): 10 | q: str 11 | location: Optional[str] 12 | uule: Optional[str] 13 | domain: Optional[str] 14 | gl: Optional[str] 15 | hl: Optional[str] 16 | lr: Optional[list] 17 | ludocid: Optional[str] 18 | lsig: Optional[str] 19 | kgmid: Optional[str] 20 | si: Optional[str] 21 | tbs: Optional[str] 22 | safe: Optional[str] 23 | filter: Optional[int] 24 | tbm: Optional[str] 25 | deviceType: Optional[str] 26 | start: Optional[int] 27 | num: Optional[int] 28 | 29 | 30 | class GoogleSerpApi: 31 | 32 | api_url = "https://api.hasdata.com/scrape/google/serp" 33 | 34 | def __init__(self, api_key: str): 35 | self.api_key = api_key 36 | 37 | def getSearchResults( 38 | self, 39 | params: GetSearchResultsParams, 40 | **kwargs 41 | ) -> Response: 42 | headers = { 43 | "x-api-key": self.api_key 44 | } 45 | headers.update(default_headers) 46 | params["source"] = "python_sdk" 47 | url_params = urllib.parse.urlencode(params) 48 | 49 | url = self.api_url + "/" + "?" + url_params 50 | return request("GET", url, headers=headers, **kwargs) 51 | -------------------------------------------------------------------------------- /google_serp_api/default_headers.py: -------------------------------------------------------------------------------- 1 | from .__version__ import __version__ 2 | 3 | # Add User-Agent identifying sdk 4 | default_headers = {"User-Agent": f"Hasdata-Python/{__version__}"} 5 | -------------------------------------------------------------------------------- /google_serp_api/example/example.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | sys.path.append(os.path.abspath('../')) 5 | 6 | from google_serp_api import GoogleSerpApi # noqa: E402 7 | 8 | api_key = os.getenv('HASDATA_API_KEY', 'INSERT_YOUR_API_KEY_HERE') 9 | 10 | client = GoogleSerpApi(api_key) 11 | try: 12 | query = { 13 | "q": "Coffee", 14 | "location": "Austin,Texas,United States", 15 | "domain": "google.com", 16 | "gl": "us" 17 | } 18 | response = client.getSearchResults(query) 19 | data = response.json() 20 | print(data) 21 | except Exception as e: 22 | print(f"Error occurred: {e}") 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flake8==3.9.2 2 | pytest==5.4.2 3 | tox==3.23.1 4 | wheel==0.36.2 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from setuptools import setup 4 | 5 | about = {} 6 | here = os.path.abspath(os.path.dirname(__file__)) 7 | with open( 8 | os.path.join(here, 'google_serp_api', '__version__.py'), 9 | 'r', encoding='utf-8' 10 | ) as f: 11 | exec(f.read(), about) 12 | 13 | setup( 14 | name='google-serp-api', 15 | version=about['__version__'], 16 | url='https://github.com/HasData/google-serp-api-python', 17 | description='The Google SERP API provides real-time access to structured Google search results, offering no blocks or CAPTCHAs.', # noqa: E501 18 | long_description=open('README.md').read(), 19 | long_description_content_type='text/markdown', 20 | author='Roman Milyushkevich', 21 | author_email='roman@hasdata.com', 22 | maintainer='Roman Milyushkevich', 23 | maintainer_email='roman@hasdata.com', 24 | license='MIT', 25 | packages=['google_serp_api'], 26 | classifiers=[ 27 | 'License :: OSI Approved :: MIT License', 28 | 'Programming Language :: Python', 29 | 'Programming Language :: Python :: 3', 30 | 'Programming Language :: Python :: 3.6', 31 | 'Programming Language :: Python :: 3.7', 32 | 'Programming Language :: Python :: 3.8', 33 | 'Programming Language :: Python :: 3.9', 34 | 'Programming Language :: Python :: 3.10', 35 | 'Programming Language :: Python :: 3.11', 36 | 'Programming Language :: Python :: 3.12', 37 | 'Topic :: Software Development :: Libraries :: Python Modules', 38 | ], 39 | python_requires='>=3.6', 40 | install_requires=['requests'], 41 | ) 42 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36, py37, py38, py39, py310, py311, py312 3 | 4 | [testenv] 5 | allowlist_externals = make 6 | deps = pytest 7 | commands = 8 | make test 9 | --------------------------------------------------------------------------------