ABOUT ME

-

Total
-
  • Python selectolax: Modest 엔진 HTML parser
    컴퓨터/파이썬 2021. 1. 16. 21:40
    728x90
    반응형

    selectolax

     

    rushter/selectolax

    Python binding to Modest engine (fast HTML5 parser with CSS selectors). - rushter/selectolax

    github.com

     

    1. 소개

     selectolax 라이브러리는 C언어로 제작된 HTML 렌더러 (Modest 엔진)에 python으로 wrapper만 한 라이브러리이다.

    유명한 python의 beautifulsoup4 HTML 파서와 거의 비슷하게 작동하지만, 써본 결과 더 빠르다.

    구글 SERP 페이지 800개 벤치마크

    설치법

    pip install selectolax

     

    2. 사용법

    beautifulsoup4를 이용한 버전

    학교 공지를 파싱 할 때 사용한 함수를 비교해 보았다.

    BeautifulSoup로 html을 불러오면 된다.

    (1000개의 공지 id, 제목, 작성일, 작성자 불러오기)

    import ssl
    from urllib.error import HTTPError, URLError
    from urllib.request import urlopen
    
    from bs4 import BeautifulSoup
    
    
    def parser_soup(url=f"{ADDRESS}?mode=list&&articleLimit={LENGTH}&article.offset=0"):
        # req = requests.get(f"{ADDRESS}?mode=list&&articleLimit={LENGTH}&article.offset=0")
        context = ssl._create_unverified_context()
        try:
            result = urlopen(url, timeout=2.0, context=context)
        except HTTPError:
            print("Seems like the server is down now.")
            return None, None, None, None, 0  # make entity
        except TimeoutError:
            print("It's taking too long to load website.")
            return None, None, None, None, 0  # make entity
    
        html = result.read().decode("utf-8")
        
        # 아래부터 BeautifulSoup 부분
        soup = BeautifulSoup(html, "html.parser")
        no_post = soup.select("td.b-no-post")
        if no_post:
            return None, None, None, None, 0  # make entity
    
        ids = soup.select("td.b-num-box")
        posts = soup.select("div.b-title-box > a")
        dates = soup.select("span.b-date")
        writers = soup.select("span.b-writer")
        return ids, posts, dates, writers, len(ids)

    selectolax를 이용한 버전

    HTMLParser로 결과 html을 읽으면 된다.

    (100개의 공지 id, 제목, 작성일, 작성자 불러오기)

    from selectolax.parser import HTMLParser
    
    def parser_modest(url=f"{ADDRESS}?mode=list&articleLimit={LENGTH}&article.offset=0"):
        # req = requests.get(f"{ADDRESS}?mode=list&&articleLimit={LENGTH}&article.offset=0")
        context = ssl._create_unverified_context()
        try:
            result = urlopen(url, timeout=2.0, context=context)
        except HTTPError:
            print("Seems like the server is down now.")
            return None, None, None, None, 0  # make entity
        except TimeoutError:
            print("It's taking too long to load website.")
            return None, None, None, None, 0  # make entity
    
        html = result.read().decode("utf-8")
        
        # 아래부터 selectolax 부분
        soup = HTMLParser(html)
        no_post = soup.css("td.b-no-post")
        if no_post:
            return None, None, None, None, 0  # make entity
    
        ids = soup.css("td.b-num-box")
        posts = soup.css("div.b-title-box > a")
        dates = soup.css("span.b-date")
        writers = soup.css("span.b-writer")
        return ids, posts, dates, writers, len(ids)

    결과

    1000개의 공지를 읽어왔을 때 selectolax가 약 2~3초 정도 빠르다.

    if __name__ == "__main__":
        from timeit import default_timer
    
        print("BeautifulSoup")
        start = default_timer()
        parser_soup(f"{ADDRESS}?mode=list&articleLimit=1000&article.offset=0")
        print(f"{default_timer() - start:.5f}s")
    
        print("Modest selectolax")
        start = default_timer()
        parser_modest(f"{ADDRESS}?mode=list&articleLimit=1000&article.offset=0")
        print(f"{default_timer() - start:.5f}s")
    
    
    """ 결과
    BeautifulSoup
    4.18911s
    
    Modest selectolax
    2.77901s
    """

     

    문법 비교

    result = urlopen(url, timeout=2.0, context=context)
    html = result.read().decode("utf-8")
    
    # beautifulsoup4 하나만 선택 select_one
    no_post = soup.select_one("td.b-no-post")
    
    # selectolax 하나만 선택 css_first
    no_post = soup.css_first("td.b-no-post")
    
    # bs4 여러개 선택 select
    ids = soup.select("td.b-num-box")
    
    # selectolax 여러개 선택 css
    ids = soup.css("td.b-num-box")
    

    파싱 결과 이용

    selectolax는 text란 object가 형성된다.

    # selectolax strip
    postId = ids[i].text(strip=True)
    
    # bs4 strip
    postId = ids[i].text.strip()
    
    
    # selectolax attribute 불러오기 attributes (dictionary)
    postLink = posts[i].attributes["href"]
    
    # bs4 attribute 불러오기 get
    postLink = posts[i].get("href")

     

    더 많은 예제

     

    selectolax 공식 예제

    Python binding to Modest engine (fast HTML5 parser with CSS selectors)

    github.com

     

     

    728x90

    댓글