Python TIL(11) - 웹스크래핑 실습

random·2021년 3월 28일
1

Python - TIL

목록 보기
11/19

Web-Scraping 실습

간단한 웹스크래핑 프로그램 만들기 실습체험

| 기초개념 |

  • 크롤링(crawling)
    크롤링은 크롤러가 하는 작업을 부르는 말로, 여러 인터넷 사이트의 페이지(문서, html 등)를 수집해서 분류하는 것이다. 대체로 찾아낸 데이터를 저장한 후 쉽게 찾을 수 있게 인덱싱한다.
  • 파싱(parsing)
    파싱이란 어떤 페이지(문서, html 등)에서 내가 원하는 데이터를 특정 패턴이나 순서로 추출하여 정보를 가공하는 것이다.
  • 스크래핑(scraping)
    스크래핑이란 HTTP를 통해 웹 사이트의 내용을 긁어다 원하는 형태로 가공하는 것이다.
    쉽게 말해 웹 사이트의 데이터를 수집하는 모든 작업을 뜻한다.
    크롤링도 일종의 스크래핑 기술이라고 할 수 있다.
  1. 실습 환경 구축

아래의 3가지 외부 라이브러리를 별도로 다운받아야한다. (MAC OS 터미널 이용)

  • pip3 install requests: 웹사이트 접근해서 무언가 요청 시 쓰는 기능
  • pip3 install lxml: 웹사이트 내부에 있는 무언가를 읽을 때 쓰는 기능 아래 Soup을 호출하여 이용할 때, 인자값으로 넣어줌
  • pip3 install bs4 (beautiful soup): String으로 조금 난잡하게 스크랩된 html 형식의 웹문서 원문을 어느게 css인지 어느게 html인지 잘 정리해서 보여줌.

*주의점: 라이브러리, pip, python등 서로 호환이 잘 되게 버전체크 필수!


  1. 웹페이지에서 텍스트 따오기

import requests

result = requests.get("https://en.wikipedia.org/wiki/Basketball")  #http or https 인지 꼭 확인하기!

print(type(result))

import bs4

soup = bs4.BeautifulSoup(result.text, "lxml")
soup.select('title')      #html 세부 섹션들 선택 가능함. <div>/<h>/<p>기타등등
soup.select('p')

print(soup.select('title')[0].getText())  # getText덕분에 string code 선택해서 출력
site_paragraphs = soup.select("p")   
print(site_paragraphs[1]) #여기서 호출되는 값은 string이 아니고 특별한 Soup 객체이다
print(site_paragraphs[2].getText())   #20번 라인과 달리 여기는 string 출력됨 비교하기!
  • 라이브러리로 다운받은 requests, bs4 모듈을 각각 import 하여 사용준비 모드로 만듦.
  • http 또는 https로 시작되는 주소에서만 적용 가능한 기능임으로 주소 url 잘 확인할 것.
  • html과 css의 기본 지식들이 바탕이 되어야만 웹스크래핑을 더 능숙하게 할 수 있음: 기본 생성 구조를 이해하면 자신이 원하는 정보를 더 빠르게 찾을 수 있음. 예시; <head, title, p, ul> 등 각각의 태그가 의미하는 바를 이해하는지 여부.
  • 한 가지 유용한 팁으로, 본인이 원하는 부분에 (예시; 'contents') 마우스 우측클릭 후 inspect element를 클릭하면 바로 자신이 원했던 html 원본 문구를 찾을 수 있음!
  • 위 소스코드 예시에선, 위키피디아 농구 관련 설명 페이지에서, 원하는 위치의 정보를 스크래핑하는 시도를 해봄.

  1. 웹에서 이미지 따오기

| 위에서 활용한 위키피디아 농구 페이지에서 원하는 사진을 스크래핑해보기 |


import requests
import bs4

result = requests.get("https://en.wikipedia.org/wiki/Basketball")  #http or https 인지 꼭 확인하기!

soup = bs4.BeautifulSoup(result.text, "lxml")

# vsc에서는 print로 명령해줘야 관련 텍스트가 출력됨
(soup.select('.toctext'))  #.점을 붙여서 class call을 함! 처음에 점 필수!
(type(soup.select('.toctext')[0]))   
#타입결과를 출력해보면 <class 'bs4.element.Tag'> 이렇게 나오는데 이건 기존의 파이썬 타입이 아님 새로운 특별한 객체 타입임을 의미함!

first_item = soup.select('.toctext')[0]
(first_item.text)

basketball = soup.select('.thumbimage')[0]


print(basketball['class'])
print(basketball['src'])   #여기서 추출되는 링크 소스 str이 웹스크래핑때 우리가 필요로 하는것!

image_link = requests.get("https://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Canasta_y_tablero_-_0.00.jpg/800px-Canasta_y_tablero_-_0.00.jpg")
# print(image_link.content)  #여기서 출력되는 값은 위 이미지 소스의 binary file 이고 컴퓨터만 이해 가능한 언어! 그래서 우리가 이미지 볼려면 따로 파일 오픈명령을 해줘야함!

f = open(/Users/raykim/Desktop/vscode/Udemy/Python3_Bootcamp/'my_basketball_image.jpg', 'wb')
f.write(image_link.content)
f.close()
  • 이미지 파일은 저작권 침해 우려가 있음으로 항상 2차 가공 또는 공개적으로 이용할 때 주의 해야한다!
  • soup.select('.toctext')에서 점을 붙이는 이유: class call을 하기 위해서 필수로 붙여야 하는 것; 암기할 것!.
  • html 원문을 확인해본 결과 <toctext> 클래스 내부에 내가 원하는 이미지 파일있음.
  • 마지막 f 부분: 파일 input/output 개념을 이용해서 내가 원하는 폴더에 'my_basketball_image.jpg'라는 이름의 파일을 만들고 열어서 이미지를 저장하고 닫는다.

  1. 복수의 페이지에서 for문을 이용하여 웹 스크래핑 해보기

| 목표: 2개 이상 별점을 받은 책 관련 정보만 따오기 |


import requests
import bs4
base_url = 'https://books.toscrape.com/catalogue/page-{}.html'
res = requests.get(base_url.format(1))
soup = bs4.BeautifulSoup(res.text, "lxml")
# print(soup)

len(soup.select(".product_pod"))  #한페이지에 20개 아이템 컨테이너가 있다는 걸 확인한것! #product_pod 클래스에 내가 원하는 개별 아이템 정보들이 다 들어있음
  • 활용 웹사이트: https://books.toscrape.com/index.html (웹스크래핑을 마음껏 연습할 수 있게 해주는 저작권 염려없는 사이트)
  • 추후 편의상, base_url 이라는 변수명을 애초에 정해주기
  • 여러 페이지를 둘러본 결과 기본 url이 아래와 같이 "https://books.toscrape.com/catalogue/page-{}.html" 의 형태를 유지하고 페이지가 넘어갈 떄 마다 page뒤에 숫자만 변경된 다는 것을 발견함: for loop를 활용할 수 있는 힌트 제공.

two_stars_titles = []  

for n in range(1,51):   #=> 총 50쪽 페이지 스크래핑 의미

    scrape_url = base_url.format(n) 
    res = requests.get(scrape_url) #=> 사이트에 스크랩 요청 의미

    soup = bs4.BeautifulSoup(res.text, 'lxml') => Soup 기능 활성화
    books = soup.select(".product_pod") #product_pod => 책별로 모든 관련 정보를 담고있는 컨테이너 클래스 선택

    for book in books:
    
    	1) if 'star-rating Two' in str(book): #=> str으로만 찾기
        
        2) if len(book.select('.star-rating.Two')) != 0: 
        #=> 클래스로 찾기
            book_title = book.select('a')[1]['title'] #=> 필요한 정보 선택 세부화 과정
            two_stars_titles.append(book_title) 
            #=> 처음 만들어놓은 리스트에 for looping으로 조건 맞는 아이템 추가
            
            print(two_stars_titles)
  • 추후 새로운 책제목 정보가 추가될 빈 리스트 two_starts_titles를 만든 후,

  • 해당 페이지수가 50페이지 임을 확인하고 for 루프의 range를 (1, 51)로 설정함.

  • rating 정도를 찾기위해서 두가지 방법을 활용가능함.
    1안) 빠르지만 결과가 조금 지저분한 문자 그대로의 str을 찾는 법,
    2안) 2스타를 암시하는 class('.star-rating.Two')를 지정해서 찾기, 이게 더 깔끔하고 좋은 코드임. 클래스 찾을 때는 꼭 앞에 본 예시처럼 '.'을 붙이기!

  • "if len(book.select('.star-rating.Two')) != 0:" 해당 if 구절은 별점을 두개 받은 책이 해당 웹페이지에 확실히 존재하기 떄문에 이후 이어지는 논리전개를 확실히 이어주는 역할을 함.

  • example.select()[][] 포맷을 이용해서 딕셔너리 기능처럼 원하는 값을 세밀하게 호출할 수 있음. 위에서는 책 title 만을 추출하기 위해서 book.select('a')[1]['title']으로 표현함.

  • example.select("star-rating.Three") 원문 html에 띄어쓰기가 되어있다면 파이썬에서 호출할 때는 띄어쓰기 없이 점으로 그것을 표현해줘야함. 암기할 것!

  • 코딩 결과값: 해당 웹사이트에 있는 복수의 페이지에 있는 수 많은 책제목 정보를 성공적으로 스크래핑함.

0개의 댓글