8000 Added browser automation lecture notes. · coding794/complete-python-course@c5ce141 · GitHub
[go: up one dir, main page]

Skip to content

Commit c5ce141

Browse files
committed
Added browser automation lecture notes.
1 parent 40d97af commit c5ce141

File tree

74 files changed

+806
-15
lines changed
  • 7_searching_for_quotes
  • 8_encapsulating_logic_simply
  • 9_adding_some_error_handling
  • Some content is hidden

    Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

    74 files changed

    +806
    -15
    lines changed

    course_contents/12_browser_automation_selenium/code/pages/quotes_page.py

    Lines changed: 26 additions & 13 deletions
    Original file line numberDiff line numberDiff line change
    @@ -12,37 +12,50 @@ def __init__(self, browser):
    1212

    1313
    @property
    1414
    def quotes(self) -> List[QuoteParser]:
    15-
    return [QuoteParser(e) for e in self.browser.find_elements_by_css_selector(QuotesPageLocators.QUOTE)]
    16-
    15+
    return [
    16+
    QuoteParser(e)
    17+
    for e in self.browser.find_elements_by_css_selector(
    18+
    QuotesPageLocators.QUOTE
    19+
    )
    20+
    ]
    21+
    1722
    @property
    1823
    def author_dropdown(self) -> Select:
    19-
    element = self.browser.find_element_by_css_selector(QuotesPageLocators.AUTHOR_DROPDOWN)
    24+
    element = self.browser.find_element_by_css_selector(
    25+
    QuotesPageLocators.AUTHOR_DROPDOWN
    26+
    )
    2027
    return Select(element)
    21-
    28+
    2229
    @property
    2330
    def tags_dropdown(self):
    24-
    element = self.browser.find_element_by_css_selector(QuotesPageLocators.TAG_DROPDOWN)
    31+
    element = self.browser.find_element_by_css_selector(
    32+
    QuotesPageLocators.TAG_DROPDOWN
    33+
    )
    2534
    return Select(element)
    26-
    35+
    2736
    @property
    2837
    def search_button(self):
    29-
    return self.browser.find_element_by_css_selector(QuotesPageLocators.SEARCH_BUTTON)
    30-
    38+
    return self.browser.find_element_by_css_selector(
    39+
    QuotesPageLocators.SEARCH_BUTTON
    40+
    )
    41+
    3142
    def select_author(self, author_name: str):
    3243
    self.author_dropdown.select_by_visible_text(author_name)
    33-
    44+
    3445
    def get_available_tags(self) -> List[str]:
    35-
    return [option.text for option in self.tags_dropdown.options]
    36-
    46+
    return [option.text.strip() for option in self.tags_dropdown.options]
    47+
    3748
    def select_tag(self, tag_name: str):
    3849
    self.tags_dropdown.select_by_visible_text(tag_name)
    39-
    50+
    4051
    def search_for_quotes(self, author_name: str, tag_name: str) -> List[QuoteParser]:
    4152
    self.select_author(author_name)
    4253
    try:
    4354
    self.select_tag(tag_name)
    4455
    except NoSuchElementException:
    45-
    raise InvalidTagForAuthorError(f"Author '{author_name}' does not have any quotes tagged with '{tag_name}'.")
    56+
    raise InvalidTagForAuthorError(
    57+
    f"Author '{author_name}' does not have any quotes tagged with '{tag_name}'."
    58+
    )
    4659
    self.search_button.click()
    4760
    return self.quotes
    4861

    course_contents/12_browser_automation_selenium/code/parsers/quote.py

    Lines changed: 2 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -6,7 +6,7 @@ def __init__(self, parent):
    66
    self.parent = parent
    77

    88
    def __repr__(self):
    9-
    return f'<Quote {self.content}, by {self.author}>'
    9+
    return f"<Quote {self.content}, by {self.author}>"
    1010

    1111
    @property
    1212
    def content(self):
    @@ -19,6 +19,6 @@ def author(self):
    1919
    return self.parent.find_element_by_css_selector(locator).text
    2020

    2121
    @property
    22-
    def tags(self):
    22+
    def tag(self):
    2323
    locator = QuoteLocators.TAGS_LOCATOR
    2424
    return self.parent.find_element_by_css_selector(locator)
    Lines changed: 18 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,18 @@
    1+
    from selenium import webdriver
    2+
    from pages.quotes_page import QuotesPage, InvalidTagForAuthorError
    3+
    4+
    5+
    try:
    6+
    author = input("Enter the author you'd like quotes from: ")
    7+
    tag = input("Enter your tag: ")
    8+
    9+
    chrome = webdriver.Chrome(executable_path="/usr/local/bin/chromedriver")
    10+
    chrome.get("http://quotes.toscrape.com/search.aspx")
    11+
    page = QuotesPage(chrome)
    12+
    13+
    print(page.search_for_quotes(author, tag))
    14+
    except InvalidTagForAuthorError as e:
    15+
    print(e)
    16+
    except Exception as e:
    17+
    print(e)
    18+
    print("An unknown error occurred. Please try again.")

    course_contents/12_browser_automation_selenium/lectures/11_adding_waits_to_our_code/locators/__init__.py

    Whitespace-only changes.
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,4 @@
    1+
    class QuoteLocators:
    2+
    CONTENT_LOCATOR = "span.content"
    3+
    AUTHOR_LOCATOR = "span.author"
    4+
    TAGS_LOCATOR = "span.tag"
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,6 @@
    1+
    class QuotesPageLocators:
    2+
    QUOTE = "div.quote"
    3+
    AUTHOR_DROPDOWN = "select#author"
    4+
    TAG_DROPDOWN = "select#tag"
    5+
    TAG_DROPDOWN_VALUE_OPTION = "select#tag option[value]"
    6+
    SEARCH_BUTTON = 'input[name="submit_button"]'

    course_contents/12_browser_automation_selenium/lectures/11_adding_waits_to_our_code/pages/__init__.py

    Whitespace-only changes.
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,77 @@
    1+
    from typing import List
    2+
    from selenium.webdriver.common.by import By
    3+
    from selenium.webdriver.support import expected_conditions
    4+
    from selenium.webdriver.support.ui import Select
    5+
    from selenium.webdriver.support.wait import WebDriverWait
    6+
    7+
    from locators.quotes_page_locators import QuotesPageLocators
    8+
    from parsers.quote import QuoteParser
    9+
    10+
    11+
    class QuotesPage:
    12+
    def __init__(self, browser):
    13+
    self.browser = browser
    14+
    15+
    @property
    16+
    def quotes(self) -> List[QuoteParser]:
    17+
    return [
    18+
    QuoteParser(e)
    19+
    for e in self.browser.find_elements_by_css_selector(
    20+
    QuotesPageLocators.QUOTE
    21+
    )
    22+
    ]
    23+
    24+
    @property
    25+
    def author_dropdown(self) -> Select:
    26+
    element = self.browser.find_element_by_css_selector(
    27+
    QuotesPageLocators.AUTHOR_DROPDOWN
    28+
    )
    29+
    return Select(element)
    30+
    31+
    @property
    32+
    def tags_dropdown(self):
    33+
    element = self.browser.find_element_by_css_selector(
    34+
    QuotesPageLocators.TAG_DROPDOWN
    35+
    )
    36+
    return Select(element)
    37+
    38+
    @property
    39+
    def search_button(self):
    40+
    return self.browser.find_element_by_css_selector(
    41+
    QuotesPageLocators.SEARCH_BUTTON
    42+
    )
    43+
    44+
    def select_author(self, author_name: str):
    45+
    self.author_dropdown.select_by_visible_text(author_name)
    46+
    47+
    def get_available_tags(self) -> List[str]:
    48+
    return [option.text.strip() for option in self.tags_dropdown.options]
    49+
    50+
    def select_tag(self, tag_name: str):
    51+
    self.tags_dropdown.select_by_visible_text(tag_name)
    52+
    53+
    def search_for_quotes(self, author_name: str, tag_name: str) -> List[QuoteParser]:
    54+
    self.select_author(author_name)
    55+
    56+
    # https://selenium-python.readthedocs.io/waits.html
    57+
    WebDriverWait(self.browser, 10).until(
    58+
    expected_conditions.presence_of_element_located(
    59+
    (By.CSS_SELECTOR, QuotesPageLocators.TAG_DROPDOWN_VALUE_OPTION)
    60+
    )
    61+
    )
    62+
    63+
    # Alternatively, implicit wait
    64+
    self.browser.implicitly_wait(10)
    65+
    66+
    try:
    67+
    self.select_tag(tag_name)
    68+
    except NoSuchElementException:
    69+
    raise InvalidTagForAuthorError(
    70+
    f"Author '{author_name}' does not have any quotes tagged with '{tag_name}'."
    71+
    )
    72+
    self.search_button.click()
    73+
    return self.quotes
    74+
    75+
    76+
    class InvalidTagForAuthorError(ValueError):
    77+
    pass

    course_contents/12_browser_automation_selenium/lectures/11_adding_waits_to_our_code/parsers/__init__.py

    Whitespace-only changes.
    Lines changed: 24 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,24 @@
    1+
    from locators.quote_locators import QuoteLocators
    2+
    3+
    4+
    class QuoteParser:
    5+
    def __init__(self, parent):
    6+
    self.parent = parent
    7+
    8+
    def __repr__(self):
    9+
    return f"<Quote {self.content}, by {self.author}>"
    10+
    11+
    @property
    12+
    def content(self):
    13+
    locator = QuoteLocators.CONTENT_LOCATOR
    14+
    return self.parent.find_element_by_css_selector(locator).text
    15+
    16+
    @property
    17+
    def author(self):
    18+
    locator = QuoteLocators.AUTHOR_LOCATOR
    19+
    return self.parent.find_element_by_css_selector(locator).text
    20+
    21+
    @property
    22+
    def tags(self):
    23+
    locator = QuoteLocators.TAGS_LOCATOR
    24+
    return self.parent.find_elements_by_css_selector(locator)
    Lines changed: 9 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,9 @@
    1+
    import requests
    2+
    3+
    from pages.quotes_page import QuotesPage
    4+
    5+
    page_content = requests.get('http://quotes.toscrape.com').content
    6+
    page = QuotesPage(page_content)
    7+
    8+
    for quote in page.quotes:
    9+
    print(quote)

    course_contents/12_browser_automation_selenium/lectures/1_our_scraping_code/locators/__init__.py

    Whitespace-only changes.
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,4 @@
    1+
    class QuoteLocators:
    2+
    CONTENT_LOCATOR = 'span.text'
    3+
    AUTHOR_LOCATOR = 'small.author'
    4+
    TAGS_LOCATOR = 'div.tags a.tag'
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,5 @@
    1+
    class QuotesPageLocators:
    2+
    QUOTE = "div.quote"
    3+
    AUTHOR_DROPDOWN = "select#author"
    4+
    TAG_DROPDOWN = "select#tag"
    5+
    SEARCH_BUTTON = 'input[name="submit_button"]'

    course_contents/12_browser_automation_selenium/lectures/1_our_scraping_code/pages/__init__.py

    Whitespace-only changes.
    Lines changed: 13 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,13 @@
    1+
    from bs4 import BeautifulSoup
    2+
    3+
    from locators.quotes_page_locators import QuotesPageLocators
    4+
    from parsers.quote import QuoteParser
    5+
    6+
    7+
    class QuotesPage:
    8+
    def __init__(self, page):
    9+
    self.soup = BeautifulSoup(page, 'html.parser')
    10+
    11+
    @property
    12+
    def quotes(self):
    13+
    return [QuoteParser(e) for e in self.soup.select(QuotesPageLocators.QUOTE)]

    course_contents/12_browser_automation_selenium/lectures/1_our_scraping_code/parsers/__init__.py

    Whitespace-only changes.
    Lines changed: 24 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,24 @@
    1+
    from locators.quote_locators import QuoteLocators
    2+
    3+
    4+
    class QuoteParser:
    5+
    def __init__(self, parent):
    6+
    self.parent = parent
    7+
    8+
    def __repr__(self):
    9+
    return f'<Quote {self.content}, by {self.author}>'
    10+
    11+
    @property
    12+
    def content(self):
    13+
    locator = QuoteLocators.CONTENT_LOCATOR
    14+
    return self.parent.select_one(locator).string
    15+
    16+
    @property
    17+
    def author(self):
    18+
    locator = QuoteLocators.AUTHOR_LOCATOR
    19+
    return self.parent.select_one(locator).string
    20+
    21+
    @property
    22+
    def tags(self):
    23+
    locator = QuoteLocators.TAGS_LOCATOR
    24+
    return self.parent.select(locator)
    Lines changed: 10 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,10 @@
    1+
    from selenium import webdriver
    2+
    3+
    from pages.quotes_page import QuotesPage
    4+
    5+
    chrome = webdriver.Chrome(executable_path="/usr/local/bin/chromedriver")
    6+
    chrome.get("http://quotes.toscrape.com")
    7+
    page = QuotesPage(chrome)
    8+
    9+
    for quote in page.quotes:
    10+
    print(quote)

    course_contents/12_browser_automation_selenium/lectures/3_using_chrome_in_scraping_code/locators/__init__.py

    Whitespace-only changes.
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,4 @@
    1+
    class QuoteLocators:
    2+
    CONTENT_LOCATOR = 'span.text'
    3+
    AUTHOR_LOCATOR = 'small.author'
    4+
    TAGS_LOCATOR = 'div.tags a.tag'
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,2 @@
    1+
    class QuotesPageLocators:
    2+
    QUOTE = 'div.quote'

    course_contents/12_browser_automation_selenium/lectures/3_using_chrome_in_scraping_code/pages/__init__.py

    Whitespace-only changes.
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,16 @@
    1+
    from locators.quotes_page_locators import QuotesPageLocators
    2+
    from parsers.quote import QuoteParser
    3+
    4+
    5+
    class QuotesPage:
    6+
    def __init__(self, browser):
    7+
    self.browser = browser
    8+
    9+
    @property
    10+
    def quotes(self):
    11+
    return [
    12+
    QuoteParser(e)
    13+
    for e in self.browser.find_elements_by_css_selector(
    14+
    QuotesPageLocators.QUOTE
    15+
    )
    16+
    ]

    course_contents/12_browser_automation_selenium/lectures/3_using_chrome_in_scraping_code/parsers/__init__.py

    Whitespace-only changes.
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,24 @@
    1+
    from locators.quote_locators import QuoteLocators
    2+
    3+
    4+
    class QuoteParser:
    5+
    def __init__(self, parent):
    6+
    self.parent = parent
    7+
    8+
    def __repr__(self):
    9+
    return f"<Quote {self.content}, by {self.author}>"
    10+
    11+
    @property
    12+
    def content(self):
    13+
    locator = QuoteLocators.CONTENT_LOCATOR
    14+
    return self.parent.find_element_by_css_selector(locator).text
    15+
    16+
    @property
    17+
    def author(self):
    18+
    locator = QuoteLocators.AUTHOR_LOCATOR
    19+
    return self.parent.find_element_by_css_selector(locator).text
    20+
    21+
    @property
    22+
    def tags(self):
    23+
    locator = QuoteLocators.TAGS_LOCATOR
    24+
    return self.parent.find_elements_by_css_selector(locator)
    Lines changed: 10 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,10 @@
    1+
    from selenium import webdriver
    2+
    3+
    from pages.quotes_page import QuotesPage
    4+
    5+
    chrome = webdriver.Chrome(executable_path="/usr/local/bin/chromedriver")
    6+
    chrome.get("http://quotes.toscrape.com")
    7+
    page = QuotesPage(chrome)
    8+
    9+
    for quote in page.quotes:
    10+
    print(quote)

    course_contents/12_browser_automation_selenium/lectures/4_our_new_page_locators/locators/__init__.py

    Whitespace-only changes.
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,4 @@
    1+
    class QuoteLocators:
    2+
    CONTENT_LOCATOR = "span.content"
    3+
    AUTHOR_LOCATOR = "span.author"
    4+
    TAGS_LOCATOR = "span.tag"
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,5 @@
    1+
    class QuotesPageLocators:
    2+
    QUOTE = "div.quote"
    3+
    AUTHOR_DROPDOWN = "select#author"
    4+
    TAG_DROPDOWN = "select#tag"
    5+
    SEARCH_BUTTON = 'input[name="submit_button"]'

    course_contents/12_browser_automation_selenium/lectures/4_our_new_page_locators/pages/__init__.py

    Whitespace-only changes.
    Lines changed: 16 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,16 @@
    1+
    from locators.quotes_page_locators import QuotesPageLocators
    2+
    from parsers.quote import QuoteParser
    3+
    4+
    5+
    class QuotesPage:
    6+
    def __init__(self, browser):
    7+
    self.browser = browser
    8+
    9+
    @property
    10+
    def quotes(self):
    11+
    return [
    12+
    QuoteParser(e)
    13+
    for e in self.browser.find_elements_by_css_selector(
    14+
    QuotesPageLocators.QUOTE
    15+
    )
    16+
    ]

    course_contents/12_browser_automation_selenium/lectures/4_our_new_page_locators/parsers/__init__.py

    Whitespace-only changes.
    Lines changed: 24 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,24 @@
    1+
    from locators.quote_locators import QuoteLocators
    2+
    3+
    4+
    class QuoteParser:
    5+
    def __init__(self, parent):
    6+
    self.parent = parent
    7+
    8+
    def __repr__(self):
    9+
    return f"<Quote {self.content}, by {self.author}>"
    10+
    11+
    @property
    12+
    def content(self):
    13+
    locator = QuoteLocators.CONTENT_LOCATOR
    14+
    return self.parent.find_element_by_css_selector(locator).text
    15+
    16+
    @property
    17+
    def author(self):
    18+
    locator = QuoteLocators.AUTHOR_LOCATOR
    19+
    return self.parent.find_element_by_css_selector(locator).text
    20+
    21+
    @property
    22+
    def tags(self):
    23+
    locator = QuoteLocators.TAGS_LOCATOR
    24+
    return self.parent.find_elements_by_css_selector(locator)

    0 commit comments

    Comments
     (0)
    2A29
    0