ABOUT ME

IT와 컴퓨터 관련 팁, 파이썬 등과 아파트 정보, 일상적인 경험 등의 생활 정보를 정리해서 올리는 개인 블로그

  • 파이썬 크롤링(Crawling) 연습 - BeautifulSoup 활용 기초
    코딩 연습/코딩배우기 2020. 11. 3. 21:43

     

    ■ BeautifulSoup 활용 기초

    O HTML과 XML 파일에서 데이터를 추출해내는 파이썬 라이브러리
    
    O HTMl과 XML의 트리구조를 탐색, 검색, 변경 가능
    
    O 다양한 파서(parser)를 선택하여 이용 가능
    
    O 파서(parser)
      -html.parser : 설치 필요 없음 
      -lxml : 실치 필요, 매우 빠름
      -lxml-xml 또는 xml : 설치 필요, 매우 빠름
      -html5lib : 설치 필요, 웹브라우저 방식으로 파싱(HTML5 생성), 매우 느림
    
    O 활용
      -BeautifulSoup(markup, 'html.parser')
      -BeautifulSoup(markup, 'lxml')
      -BeautifulSoup(markup, 'html.lxml-xml')
      -BeautifulSoup(markup, 'html5lib')
      

     

    example = '''
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Page Title</title>
    </head>
    <body>
        <h1>Heading 1</h1>
        <p>Paragraph</p>
        <div>
            <a href="www.google.com">google</a>
        </div>
        <div class="class1">
            <p>a</p>
            <a href="www.naver.com">naver</a>
            <p>b</p>
            <p>c</p>
        </div>
        <div id="id1">
            Example page
            <p>g</p>
        </div>
        <h1>Footer</h1>
    </body>
    </html>
    '''
    
    soup = BeautifulSoup(example, 'html.parser')
    
    print(soup.title)
    # <title>Page Title</title>  ## title 태그 내역
    
    print(soup.title.name)  ## title 태그 이름
    # title
    
    print(soup.title.string)  ## title 태그의 문자열
    # Page Title
    
    print(soup.title.parent)  ## title 태그를 포함하고 있는 태그의 내역
    #<head>
    #<meta charset="utf-8"/>
    #<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
    #<title>Page Title</title>
    #</head>
    
    print(soup.title.parent.name)  ## 부모 태그 이름
    # head
    
    print(soup.h1)  ## 첫 번째 h1 태그
    # <h1>Heading 1</h1>
    
    print(soup.p)  ## 첫 번째 p 태그
    # <p>Paragraph</p>
    
    print(soup.div)  ## 첫 번째 div 태그 내역
    #<div>
    #<a href="www.google.com">google</a>
    #</div>
    
    print(soup.a)  ## 첫 번째 a 태그 내역
    # <a href="www.google.com">google</a>

     

    good4me.co.kr

     

    ▷ HTML 태그 검색 - BeautifulSoup의 강력한 메서드

    • find() : 해당 조건에 맞는 하나의 태그를 추출함
    • find_all() : 해당 조건에 맞는 모든 태그를 추출함(ResultSet, list 형태)
    • select() : "CSS 선택자와 같은 형식"으로 선택 가능(list 타입 반환)
    ## 상기 코드에 이어서
    
    soup_find = soup.find('div')  ## soup.div 와 동일
    print(type(soup_find))
    # <class 'bs4.element.Tag'>
    print(soup_find)  ## 첫 번째 div 태그 내역
    # <div>
    # <a href="www.google.com">google</a>
    # </div>
    
    soup_find_all = soup.find_all('div')  ## div 태그 전체 추출 (list 형태)
    print(type(soup_find_all))
    # <class 'bs4.element.ResultSet'>
    print(soup_find_all)
    #[<div>
    #<a href="www.google.com">google</a>
    #</div>, 
    #<div class="class1">
    #<p>a</p>
    #<a href="www.naver.com">naver</a>
    #<p>b</p>
    #<p>c</p>
    #</div>,
    #<div id="id1">
    #  Example page
    #<p>g</p>
    #</div>]
    
    print(type(soup_find_all))
    # <class 'bs4.element.ResultSet'>
    
    print(len(soup_find_all))
    # 3
    
    print(soup_find_all[1])  ## 리스트 index 1번째 요소 추출
    #<div class="class1">
    #<p>a</p>
    #<a href="www.naver.com">naver</a>
    #<p>b</p>
    #<p>c</p>
    #</div>
    
    find_by_id = soup.find_all('div', {'id':'id1'})  ## 태그와 속성으로 추출(list 타입)
    print(find_by_id)
    #[<div id="id1">
    #        Example page
    #        <p>g</p>
    #</div>]
    
    find_by_class = soup.find_all('div', {'class':'class1'})  # class 속성으로 추출
    print(find_by_class)
    #[<div class="class1">
    #<p>a</p>
    #<a href="www.naver.com">naver</a>
    #<p>b</p>
    #<p>c</p>
    #</div>]
    
    
    print(soup.a)
    # <a href="www.google.com">google</a>
    
    print(soup.a.get('href'))  ## a 태그의 href 속성 값 추출
    # www.google.com
    
    print(soup.a['href'])
    # www.google.com
    
    print(soup.a.text)  ## a 태그의 문자열 추출
    # google
    
    print(soup.a.get_text())
    # google
    
    print(soup.find('a'))
    # <a href="www.google.com">google</a>
    
    print(soup.find('a').get('href'))
    # www.google.com
    
    print(soup.find('a')['href'])
    # www.google.com
    
    print(soup.find('a').text)
    # google
    
    print(soup.find('a').get_text())
    # google
    
    print(soup.find_all('a'))
    # [<a href="www.google.com">google</a>, <a href="www.naver.com">naver</a>]
    
    #print(soup.find_all('a').get('href'))  # 에러
    # AttributeError: ResultSet object has no attribute 'get'.
    
    for a_tag in soup.find_all('a'):  ## 각 요소별 속성 추출 위해 for문으로 순환
        print(a_tag)
        print(a_tag.get('href'))
        print(a_tag.get_text())
    
    #<a href="www.google.com">google</a>
    #www.google.com
    #google
    #<a href="www.naver.com">naver</a>
    #www.naver.com
    #naver
    
    
    for a_tag in soup.find_all('a'):
        print(a_tag)
        print(a_tag['href'])
        print(a_tag.text)
    
    #<a href="www.google.com">google</a>
    #www.google.com
    #google
    #<a href="www.naver.com">naver</a>
    #www.naver.com
    #naver
    
    
    
    ## select는 지정 선택자의 모든 내역을 추출함 (list 타입 반환)
    sel_id1 = soup.select('div#id1')
    print(sel_id1)  ## CSS 선택자 형식으로 추출 id는 #, class는 .
    #[<div id="id1">
    #        Example page
    #        <p>g</p>
    #</div>]
    
    print(type(sel_id1))
    # <class 'list'>
    
    sel_class1 = soup.select('div.class1')
    print(sel_class1)
    #[<div class="class1">
    #<p>a</p>
    #<a href="www.naver.com">naver</a>
    #<p>b</p>
    #<p>c</p>
    #</div>]
    
    print(type(sel_class1))
    # <class 'list'>
    
    sel_h1 = soup.select('h1')
    print(sel_h1)
    # [<h1>Heading 1</h1>, <h1>Footer</h1>]
    
    print(type(sel_h1))
    # <class 'list'>
    
    class1_a = soup.select('div.class1 a')  ## class1 태그 내 a 태그 추출 (list)
    print(class1_a)
    # [<a href="www.naver.com">naver</a>]
    
    print(type(class1_a))
    # <class 'list'>
    
    print(class1_a[0].get('href'))  ## list 내 index로 접근하여 href 속성 값 추출
    # www.naver.com
    

     

    ▷ 다른 예제

    national_anthem = '''
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>애국가</title>
    </head>
    <body>
        <div>
            <p id="title">애국가</p>
            <p class="content">
                동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세.<br />
                무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세.<br />
            </p>
            <p class="content">
                남산 위에 저 소나무 철갑을 두른 듯 바람서리 불변함은 우리 기상일세.<br />
                무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세.<br />
            </p>
            <p class="content">
                가을 하늘 공활한데 높고 구름 없이 밝은 달은 우리 가슴 일편단심일세.<br />
                무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세.<br />
            </p>
            <p class="content">
                이 기상과 이 맘으로 충성을 다하여 괴로우나 즐거우나 나라 사랑하세.<br />
                무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세.<br />
            </p>                
        </div>
    </body>
    </html>
    '''
                    
    soup = BeautifulSoup(national_anthem, 'html.parser')
    print(soup.find('p', id = 'title').text)
    ## soup.find('p', {'id' = 'title'}).text 또는 soup.title.text 와 동일
    # 애국가
    
    contents = soup.select('p.content')  ## p 태그 class 속성값
    for p_tag in contents:
        print(p_tag.get_text())
        
    
    [실행 결과]
    #
    #동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세.
    #무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세.
    #
    #
    #남산 위에 저 소나무 철갑을 두른 듯 바람서리 불변함은 우리 기상일세.
    #무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세.
    #
    #
    #가을 하늘 공활한데 높고 구름 없이 밝은 달은 우리 가슴 일편단심일세.
    #무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세.
    #
    #
    #이 기상과 이 맘으로 충성을 다하여 괴로우나 즐거우나 나라 사랑하세.
    #무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세
    #
        

     

    ▷ 인터넷 웹페이지 가져오기

    url = 'http://suanlab.com/'
    html = urllib.request.urlopen(url)
    print(html)
    # <http.client.HTTPResponse object at 0x000001914842F978>
    html = html.read()
    soup = BeautifulSoup(html, 'html.parser')
    #print(soup)
    
    labels = soup.find_all('label')
    for label in labels:
        print(label.get_text())
    
    
    [실행 결과]
    #[2020-05-20] "인공지능의 보안 위협" 칼럼
    #[2020-03-04] "데이터 경제 시대" 칼럼
    #[2019-12-25] "마이데이터 시대의 도래 데이터 주권과 새로운 가치" 칼럼
    #[2019-09-25] "유튜브 탄생과 크리에이터 시대" 칼럼
    #[2019-09-04] "농업으로 들어간 인공지능" 칼럼
    #[2019-08-07] "AI시대 지배할 것인가 지배당하며 살 것인가" 칼럼
    #[2018-12-30] "파이썬으로 텍스트 분석하기" 책 출판
        
    
    labels = soup.select('#wrapper > section > div > div > div > div > div > label')
    ## label에서 마우스 우클릭 후 Copy>>Copy selector
    for label in labels:
        print(label.get_text())
    
    
    [실행 결과]
    #[2020-05-20] "인공지능의 보안 위협" 칼럼
    #[2020-03-04] "데이터 경제 시대" 칼럼
    #[2019-12-25] "마이데이터 시대의 도래 데이터 주권과 새로운 가치" 칼럼
    #[2019-09-25] "유튜브 탄생과 크리에이터 시대" 칼럼
    #[2019-09-04] "농업으로 들어간 인공지능" 칼럼
    #[2019-08-07] "AI시대 지배할 것인가 지배당하며 살 것인가" 칼럼
    #[2018-12-30] "파이썬으로 텍스트 분석하기" 책 출판

     

    ▷ 전 세계 웹사이트 순위 스크래핑

    from bs4 import BeautifulSoup
    import urllib.request
    import pandas as pd
    
    
    url = 'https://www.alexa.com/topsites'
    html = urllib.request.urlopen(url).read()
    soup = BeautifulSoup(html, 'html.parser')
    sites = soup.find_all('div', {'class':'tr site-listing'})
    
    for site in sites:
        rank = site.find('div', class_ = 'td').get_text()
        website = site.select('p > a')[0].get_text()
        infos = site.find_all('div', {'class':'td right'})
        time = infos[0].get_text()
        pageview = infos[1].get_text()
        traffic = infos[2].get_text()
        linking = infos[3].get_text()
    
        print(rank, website, time, pageview, traffic, linking)
    
    
    [실행 결과]
    
    1 Google.com 15:25 16.71 0.40% 1,322,590
    2 Youtube.com 16:36 9.20 15.00% 1,007,247
    3 Tmall.com 7:02 3.77 0.90% 6,224
    4 Facebook.com 18:52 8.75 8.60% 2,237,169
    5 Baidu.com 9:05 4.55 5.10% 104,502
    6 Qq.com 3:38 3.92 2.90% 269,115
    7 Sohu.com 3:40 4.61 1.70% 27,065
    8 Taobao.com 4:37 3.59 3.30% 25,542
    9 360.cn 3:14 4.11 0.40% 15,582
    10 Jd.com 3:30 4.39 1.40% 8,785
    11 Amazon.com 10:10 9.47 19.70% 368,084
    12 Yahoo.com 4:53 4.56 7.90% 323,499
    13 Wikipedia.org 3:45 3.02 74.10% 773,868
    14 Zoom.us 8:41 3.96 13.40% 3,076
    15 Weibo.com 2:58 3.65 2.10% 71,025
    16 Sina.com.cn 2:51 3.41 2.50% 46,925
    17 Live.com 5:21 5.32 10.40% 42,943
    18 Reddit.com 5:31 4.34 30.90% 168,183
    19 Netflix.com 4:17 3.19 9.40% 11,000
    20 Xinhuanet.com 2:54 5.58 2.50% 34,834
    21 Microsoft.com 4:36 3.38 25.80% 240,212
    22 Okezone.com 4:00 4.14 7.40% 10,516
    23 Vk.com 7:16 3.82 9.30% 127,024
    24 Office.com 9:50 9.23 7.00% 5,887
    25 Instagram.com 8:45 9.56 13.70% 639,719
    26 Csdn.net 3:18 4.93 7.20% 6,556
    27 Alipay.com 2:53 3.19 1.40% 3,592
    28 Microsoftonline.com 1:14 1.92 2.70% 702
    29 Myshopify.com 21:41 14.57 3.10% 128
    30 Yahoo.co.jp 8:47 8.21 13.80% 58,916
    31 Panda.tv 2:47 5.33 0.80% 372
    32 Zhanqi.tv 2:51 5.42 0.80% 352
    33 Twitch.tv 6:34 3.41 6.70% 10,022
    34 Bongacams.com 2:57 1.62 6.80% 167,978
    35 Google.com.hk 3:50 5.37 3.40% 9,726
    36 Amazon.in 13:36 11.29 25.80% 6,854
    37 Naver.com 14:11 11.20 10.10% 39,418
    38 Bing.com 2:46 2.65 6.10% 42,641
    39 Apple.com 3:54 3.86 37.50% 178,218
    40 Ebay.com 10:01 7.90 16.40% 75,866
    41 Aliexpress.com 11:02 9.45 14.80% 19,325
    42 Tianya.cn 2:49 5.07 0.90% 5,331
    43 Amazon.co.jp 7:45 9.24 17.50% 50,006
    44 Stackoverflow.com 6:09 3.87 74.90% 26,660
    45 Google.co.in 6:30 12.19 10.00% 17,539
    46 Adobe.com 3:57 3.77 24.80% 248,973
    47 Livejasmin.com 2:33 1.76 3.20% 11,354
    48 Twitter.com 12:57 10.17 11.50% 1,622,153
    49 Yandex.ru 6:08 3.82 2.90% 95,164
    50 Tribunnews.com 3:40 1.92 61.80% 23,839
    

     

    [참고] 이수안컴퓨터연구소

     

Designed by goodthings4me.