text: import requests
  from bs4 import BeautifulSoup
  
  # WHY
  # The SearchRequest module contains all the internal logic for the library.
  #
  # This encapsulates the logic,
  # ensuring users can work at a higher level of abstraction.
  
  # USAGE
  # req = search_request.SearchRequest("[QUERY]", search_type="[title]")
  
  
  class SearchRequest:
  
      col_names = [
          "id",
          "author",
          "title",
          "publisher",
          "year",
          "pages",
          "language",
          "size",
          "extension",
          "mirror_1",
          "mirror_2",
          "mirror_3",
          "edit",
      ]
  
      def __init__(self, query, search_type="title"):
          self.query = query
          self.search_type = search_type
  
          if len(self.query) < 3:
              raise Exception("Query is too short")
  
      def strip_i_tag_from_soup(self, soup):
          subheadings = soup.find_all("i")
          for subheading in subheadings:
              subheading.decompose()
  
      def get_search_page(self):
          query_parsed = "%20".join(self.query.split(" "))
          if self.search_type.lower() == "title":
              search_url = (
                  f"http://libgen.is/search.php?req={query_parsed}&column=title&res=100"
              )
          elif self.search_type.lower() == "author":
              search_url = (
                  f"http://libgen.is/search.php?req={query_parsed}&column=author&res=100"
              )
          search_page = requests.get(search_url)
          return search_page
  
      def aggregate_request_data(self):
          search_page = self.get_search_page()
          soup = BeautifulSoup(search_page.text, "lxml")
          self.strip_i_tag_from_soup(soup)
  
          # Libgen results contain 3 tables
          # Table2: Table of data to scrape.
          information_table = soup.find_all("table")[2]
  
          # Determines whether the link url (for the mirror)
          # or link text (for the title) should be preserved.
          # Both the book title and mirror links have a "title" attribute,
          # but only the mirror links have it filled.(title vs title="libgen.io")
          raw_data = [
              [
                  td.a["href"]
                  if td.find("a")
                  and td.find("a").has_attr("title")
                  and td.find("a")["title"] != ""
                  else "".join(td.stripped_strings)
                  for td in row.find_all("td")
              ]
              for row in information_table.find_all("tr")[
                  1:
              ]  # Skip row 0 as it is the headings row
          ]
  
          output_data = [dict(zip(self.col_names, row)) for row in raw_data]
          return output_data
  