Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SerpApi GET Method Implementation #113

Merged
merged 16 commits into from
May 7, 2023
38 changes: 38 additions & 0 deletions .github/workflows/django.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Django CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

env:
serp_api_key: ${{ secrets.SERP_API_KEY }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}


jobs:
build:

runs-on: ubuntu-latest
defaults:
run:
working-directory: ./practice_app
strategy:
max-parallel: 4
matrix:
python-version: [ 3.10.11 ]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Tests
run: |
python manage.py test
Empty file added practice_app/api/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions practice_app/api/api_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import os


api_keys = {
'serp_api' : os.getenv('serp_api_key')
}
51 changes: 49 additions & 2 deletions practice_app/api/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,50 @@
from django.test import TestCase

from django.test import TestCase,Client
from unittest import skip
import requests
from . import api_keys
# Create your tests here.
class google_scholar_test_cases(TestCase):
Copy link
Contributor

@laylaylo laylaylo May 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I was just looking at this code again and I noticed that the class naming doesn't quite align with our decision to use PEP-8 Style, see class naming convention. Just a friendly reminder for future reference!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx for the heads up. I will fix them in a future PR.

def setUp(self):
self.c = Client()


def tearDown(self):
print('GET Tests Completed Successfully')

def test_404_responses(self):
self.assertEquals(self.c.get("/api/serp-api/?title=").status_code, 404)
self.assertEquals(self.c.get("/api/serp-api/?").status_code, 404)
self.assertEquals(self.c.get("/api/serp-api/").status_code, 404)
self.assertEquals(self.c.get("/api/serp-api/?rows=5").status_code, 404)
self.assertEquals(self.c.get("/api/serp-api/title=sad").status_code, 404)
self.assertEquals(self.c.get("/api/serp-api/?title=&").status_code, 404)

@skip('limited use for this api')
def test_results(self):
serp_api_response = requests.get('https://serpapi.com/search.json?engine=google_scholar&q=test&hl=en&num=3&api_key=' + api_keys.api_keys['serp_api'])
self.assertEquals(serp_api_response.status_code,200,"SerpApi didn't work as supposed to")
serp_api_response = serp_api_response.json()['organic_results']
response = self.c.get("/api/google-scholar/?title=test&rows=3")
self.assertEquals(response.status_code,200)
response_content = response.json()['results']
self.assertEquals(len(response_content),3)
count = 0
for result in response_content:
self.assertIn('source',result.keys())
self.assertEquals(result['source'],'google_scholar')
self.assertIn('authors',result.keys())
self.assertIn('id', result.keys())
self.assertIn('abstract', result.keys())
self.assertIn('url', result.keys())
self.assertIn('pos', result.keys())
self.assertIn('date', result.keys())
self.assertIn('title',result.keys())
self.assertEquals(serp_api_response[count]['title'],result['title'])
self.assertEquals(serp_api_response[count]['link'], result['url'])
self.assertEquals(serp_api_response[count]['position'], result['pos'])
count += 1





3 changes: 2 additions & 1 deletion practice_app/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.urls import path
from . import views

urlpatterns = [

path("google-scholar/", views.google_scholar, name="google-scholar"),
]
67 changes: 65 additions & 2 deletions practice_app/api/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,66 @@
from django.shortcuts import render
import requests
import re
from django.http import JsonResponse
from . import api_keys

# Create your views here.


def google_scholar(request):
number = request.GET.get("rows")
search = request.GET.get("title")
if search == None or search == "":
return JsonResponse({'status': 'Title to search must be given.'}, status=404)
if number == None or number == "" or not number.isnumeric():
number = 5
else:
number = int(number)

request = requests.get('https://serpapi.com/search.json?engine=google_scholar&q=' + search + '&hl=en&num=' + str(number) + '&api_key=' + api_keys.api_keys['serp_api'])
if request.status_code == 200:
request = request.json()
papers = request['organic_results']
response = {}
results = []
for paper in papers:
pub_info = paper['publication_info']
paper_info = {}
paper_info['source'] = 'google_scholar'

if 'authors' in pub_info.keys():
defabdullah marked this conversation as resolved.
Show resolved Hide resolved
paper_info['authors'] = []
for author in pub_info['authors']:
a = {'name' : author['name']}
paper_info['authors'].append(a.copy())
else:
temp = pub_info['summary'].split('-')[0].strip()
temp = temp.split(',')
authors = []
for i in temp:
i = i.strip()
author = {}
author['name'] = i
authors.append(author.copy())
paper_info['authors'] = authors

paper_info['id'] = paper['result_id']
summary = pub_info['summary']
summary = '-' + summary + '-'
year = re.findall('[\W|\s](\d{4})[\W|\s]', summary)
if len(year) == 0:
year = None
paper_info['date'] = 'Not found'
else:
year = int(year[0])
paper_info['date'] = year

paper_info['abstract'] = paper['snippet']
paper_info['title'] = paper['title']
paper_info['url'] = paper['link']
paper_info['pos'] = paper['position']
results.append(paper_info.copy())
response['results'] = results
return JsonResponse(response)
elif request.status_code == 404:
return JsonResponse({'status': 'Unsuccessful Search.'}, status=404)
else:
return JsonResponse({'status': 'An internal server error has occured. Please try again.'},status=503)
7 changes: 4 additions & 3 deletions practice_app/practice_app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"""

from pathlib import Path

import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

Expand All @@ -20,12 +20,12 @@
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-b+g%8zg=kxk79bbpj2527obyccp)7hl2y19bh8df)hjb-t1y_("
SECRET_KEY = os.getenv('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['*']


# Application definition
Expand All @@ -37,6 +37,7 @@
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"api",
]

MIDDLEWARE = [
Expand Down
2 changes: 2 additions & 0 deletions practice_app/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Django==4.2
requests==2.29.0