diff --git a/README.md b/README.md index 8ac4e06..84e6ada 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ quotes = page.css('.quote').css('.text::text') # Chained selectors quotes = [element.text for element in page.css('.quote').css('.text')] # Slower than bulk query above # Get the first quote element -quote = page.css('.quote').first # or [0] or .get() +quote = page.css_first('.quote') # or page.css('.quote').first or [0] or .get() # Working with elements quote.html_content # Inner HTML @@ -244,8 +244,8 @@ To increase the complexity a little bit, let's say we want to get all books' dat ```python >>> for product in page.find_by_text('Tipping the Velvet').parent.parent.find_similar(): print({ - "name": product.css('h3 a::text')[0], - "price": product.css('.price_color')[0].re_first(r'[\d\.]+'), + "name": product.css_first('h3 a::text'), + "price": product.css_first('.price_color').re_first(r'[\d\.]+'), "stock": product.css('.availability::text')[-1].clean() }) {'name': 'A Light in the ...', 'price': '51.77', 'stock': 'In stock'} diff --git a/scrapling/parser.py b/scrapling/parser.py index 3416ec6..4f994b4 100644 --- a/scrapling/parser.py +++ b/scrapling/parser.py @@ -394,6 +394,58 @@ class Adaptor(SelectorsGeneration): return self.__convert_results(score_table[highest_probability]) return [] + def css_first(self, selector: str, identifier: str = '', + auto_match: bool = False, auto_save: bool = False, percentage: int = 0 + ) -> Union['Adaptors[Adaptor]', List, None]: + """Search current tree with CSS3 selectors and return the first result if possible, otherwise return `None` + + **Important: + It's recommended to use the identifier argument if you plan to use different selector later + and want to relocate the same element(s)** + + :param selector: The CSS3 selector to be used. + :param auto_match: Enabled will make function try to relocate the element if it was 'saved' before + :param identifier: A string that will be used to save/retrieve element's data in auto-matching + otherwise the selector will be used. + :param auto_save: Automatically save new elements for `auto_match` later + :param percentage: The minimum percentage to accept while auto-matching and not going lower than that. + Be aware that the percentage calculation depends solely on the page structure so don't play with this + number unless you must know what you are doing! + + :return: List as :class:`Adaptors` + """ + try: + return self.css(selector, identifier, auto_match, auto_save, percentage)[0] + except (IndexError, TypeError,): + return None + + def xpath_first(self, selector: str, identifier: str = '', + auto_match: bool = False, auto_save: bool = False, percentage: int = 0, **kwargs: Any + ) -> Union['Adaptors[Adaptor]', List, None]: + """Search current tree with XPath selectors and return the first result if possible, otherwise return `None` + + **Important: + It's recommended to use the identifier argument if you plan to use different selector later + and want to relocate the same element(s)** + + Note: **Additional keyword arguments will be passed as XPath variables in the XPath expression!** + + :param selector: The XPath selector to be used. + :param auto_match: Enabled will make function try to relocate the element if it was 'saved' before + :param identifier: A string that will be used to save/retrieve element's data in auto-matching + otherwise the selector will be used. + :param auto_save: Automatically save new elements for `auto_match` later + :param percentage: The minimum percentage to accept while auto-matching and not going lower than that. + Be aware that the percentage calculation depends solely on the page structure so don't play with this + number unless you must know what you are doing! + + :return: List as :class:`Adaptors` + """ + try: + return self.xpath(selector, identifier, auto_match, auto_save, percentage, **kwargs)[0] + except (IndexError, TypeError,): + return None + def css(self, selector: str, identifier: str = '', auto_match: bool = False, auto_save: bool = False, percentage: int = 0 ) -> Union['Adaptors[Adaptor]', List]: