I started learn OOP in Python. I have OOP basics in Java and apparently I have a problem with thinking in OOP in Python (and using the best functionalities and syntax). I have doubts about my OOP design in web scraping for a local book review page. So the basic idea is scraping information about book with the user reviews for that books.
The structure of the Python package:
/bookscraper
__init__.py
book.py
comment.py
parsers.py
parsers.py:
from urllib.request import urlopen
from bs4 import BeautifulSoup
from bookscraper.book import Book
from bookscraper.comment import Comment
class Parser:
def __init__(self, url, name, search_url):
self.url = url
self.name = name
self.search_url = search_url
class DatabazeKnih(Parser):
PAGE_URL = 'http://www.databazeknih.cz/'
NAME = 'Databáze knih'
SEARCH_URL = 'search?q={}&hledat=&stranka=search'
def __init__(self):
super().__init__(DatabazeKnih.PAGE_URL, DatabazeKnih.NAME, DatabazeKnih.SEARCH_URL)
def search(self, name):
self.search_html = urlopen(DatabazeKnih.PAGE_URL + DatabazeKnih.SEARCH_URL.format(name))
self.book_link = DatabazeKnih.PAGE_URL + self.get_book_link() + '?show=alldesc'
return self.get_book_info()
def get_book_page(self):
return urlopen(self.book_link)
def get_book_link(self):
soup = BeautifulSoup(self.search_html, 'html.parser')
return soup.find(type='book').attrs['href']
@staticmethod
def parse_comment(comment):
user = comment.find('a').string
text = comment.find('p', {'class': 'odtopm new2 justify'}).text
date = comment.find('span', {'class': 'pozn_lightest odleft_pet'}).string
return user, text, date
@staticmethod
def get_comments(soup):
comments_objects = []
comments = soup.find_all('div', {'class': 'komholdu'})
for comment in comments:
user, text, date = DatabazeKnih.parse_comment(comment)
comments_objects.append(Comment(user, text, date))
return comments_objects
@staticmethod
def get_authors(soup):
return [author.string for author in soup.find(itemprop='author').find_all('a')]
def get_book_info(self):
soup = BeautifulSoup(self.get_book_page(), 'html.parser')
title = soup.find(itemprop='name').string
rating = soup.findAll('a', {'class': 'bpoints'})[0].string
text = soup.find(itemprop='description').string
authors = DatabazeKnih.get_authors(soup)
year = soup.find(itemprop='datePublished').string
comments = DatabazeKnih.get_comments(soup)
return Book(title, rating, text, authors, year, comments)
Then there are the Book
and Comment
classes. I will add some functionality to these classes. Now I prepared only constructors:
class Book:
def __init__(self, title, rating, text, authors, year, comments):
self.title = title
self.rating = rating
self.text = text
self.authors = authors # this is a list
self.year = year
self.comments = comments # this is a list
class Comment:
def __init__(self, user, text, date):
self.user = user
self.text = text
self.date = date
Then I can't get info about book via creating parser object:
from bookscraper.parsers import DatabazeKnih
parser = DatabazeKnih()
book = parser.search('ydris') # Name of the book
My code is working, but is it a good OOP design? I have some doubts about the design of methods in the DatabazeKnih
class. In search method I set two attributes I found it is not a good practice, but how should I rewrite? Should I create setters for this two attributes?