본문 바로가기
IT/Python

파이썬 크롤링-03. API를 이용한 크롤링

by 무녈 2021. 6. 24.

자료의 출처는 엘리스 AI 트랙(https://aitrack.elice.io/) '파이썬 크롤링'  이며, 학습 후 정리한 내용입니다.

⚡️올바르지 않은 내용이 있을 경우 댓글로 남겨주시면 감사하겠습니다.⚡️


API를 이용한 크롤링

API

AIP란?

API(Application Programming Interface)는
어떤
프로그램과 또 다른 프로그램을 연결해주는 매개체

 

컴퓨터를 다루기 위해 마우스키보드를 이용하는 것처럼 API는 프로그램 사이를 연결해주는 역할

 

예를 들어 지도 데이터를 이용하여 맛집 찾기 웹 서비스를 제작하려면 어떻게 해야 할까?

보통의 일반인들은 지도 데이터를 갖고 있지 않고, 이를 수집하는 것도 매우 어렵다.

그렇다고 공개된 데이터를 그대로 사용하는 것도 어렵다

 

Google이 갖고 있는 지도 데이터를 공개하였다고 가정

 

그러나 원본 데이터는 너무 방대하기도 하고, 호환성 등의 문제도 있어 쉽게 사용할 수 없다.

마치 키보드와 마우스가 없는 컴퓨터를 사용하는 것과 같다.

 

그래서 Google은 지도 데이터를 응용하여 사용할 수 있도록 Google Map API라는 매개체를 사용자들에게 제공

 

위 사진은 daum 증권 사이트입니다.
여러 기업들의 주가 정보를
API를 거쳐 받아온 후 표시하고 있다.

 

방금 보신 daum 증권 사이트와 같이
API를 이용해 정보를 가져오는 웹 사이트가 꽤 있다.

 

이런 경우 정보가 HTML에 처음부터 존재하지 않고, 정보를 API로부터 불러오고 나서 HTML에 존재하게 된다.

 

따라서 daum 증권 사이트에서는
주가 데이터를 BeautifulSoup으로 크롤링할  수 없다.

 

웹 사이트를 처음 로드할 때 HTML 문서에는 주가 데이터가 존재하지 않기 때문

 

보통 API를 이용하여 데이터를 불러오는 경우는

데이터가 동적으로 변화하는 일이 많아

실시간으로 값을 불러와야 하는 경우

 

기업의 주가도 하나의 예시입니다.

 

이럴 땐 daum 증권 사이트에서
주가 정보를 요청하는
API에 접근하여
어떤 정보를 전달해주고 있는지 접근하면 된다.

크롬 개발자 도구의 Network 탭에서 웹사이트가 데이터를 요청하는 API를 볼 수 있다.

url = "http://finance.daum.net/api/search/ranks?limit=10" 
req = requests.get(url) # JSON 데이터

 

API의 URL에 GET 요청을 보내면 JSON 데이터를 얻을 수 있다.

JSON(JavaScript Object Notation)keyvalue를 저장하는, 딕셔너리 꼴의 데이터 형식이다.

 

몇몇 웹 사이트들은 크롤러 등을 통한 기계적인 접근을 막고 있다.

이를 우회하기 위해 requests.get 메소드에 "headers" 매개변수를 지정해야한다.

 

‘헤더’란 HTTP 상에서 클라이언트와 서버가
요청 또는 응답을 보낼 때 전송하는
부가적인 정보를 의미합니다.

실습에서 headers에 사용할 옵션을 제공하고 있습니다.

 

custom_header = {
    'referer’ : ...
    'user-agent’ : ...  }

 

refereruser-agent 옵션을 지정하고 있는데,

referer는 이전 웹 페이지의 주소를 의미하고

user-agent는 이용자의 여러 가지 사양을 의미

# 실습 - Daum 증권 페이지에서 주가 크롤링
# http://finance.daum.net/ 에서 보여주는 인기 검색 상위 10개 기업의 결과는, 이전처럼 HTML 문서를 분석하여 크롤링하는 방식을 사용할 수 없습니다.
# 웹 페이지가 API로부터 실시간으로 변하는 주식의 정보를 주기적으로 요청하여 표시하고 있기 때문입니다.
# 웹에서 요청하는 서버에 직접 요청하여 json 데이터를 얻은 후 출력해보도록 하겠습니다.
# API의 URL은 개발자 도구의 Network 탭에서 얻을 수 있습니다.

import requests
import json

custom_header = {
    'referer' : 'http://http://finance.daum.net/quotes/A048410#home',
    'user-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'  }


def get_data() :
    result = []
    url = "https://finance.daum.net/api/search/ranks?limit=10" 
    # 상위 10개 기업의 정보를 얻는 API url을 작성하세요.
    req = requests.get(url, headers = custom_header)
    
    if req.status_code == requests.codes.ok:    
        print("접속 성공")
        # API에 접속에 성공하였을 때의 logic을 작성해주세요.
        # JSON 데이터의 원하는 부분만 불러와 result에 저장해주세요.
        stock_data = json.loads(req.text)
        
        for d in stock_data["data"]:
            result.append([d["rank"], d["name"], d["tradePrice"]])
        
    else:
        print("접속 실패")
    
    return result

def main() :
    data = get_data()
    
    for d in data :
        print(d)
    
if __name__ == "__main__" :
    main()

# json 파일을 파이썬 코드에서 불러오기 위해 파이썬의 json 모듈을 사용할 수 있습니다.

import json
with open("stock.json") as stock :
    data = json.loads(stock) 

stock.json이라는 json 데이터를 data 변수에 로드하는 코드입니다.

# 실습 - 음식점 리뷰 크롤링
# 어떤 음식점의 리뷰 데이터를 전부 크롤링하여 출력해보도록 하겠습니다.
# main 함수에서 href 변수에 값을 넣음으로서 원하는 음식점의 리뷰를 크롤링하실 수 있습니다.
# 주의사항
# 실습 url : https://www.mangoplate.com/restaurants/B8CzA6i9Bb8Z
# 실습에서 사용한 url을 통해 음식점의 리뷰를 크롤링하고 싶으시다면,
# main 함수의 href 변수에 /restaurants/B8CzA6i9Bb8Z를 넣어주시면 됩니다.

from bs4 import BeautifulSoup
import requests
import json

custom_header = {
    'referer' : 'https://www.mangoplate.com',
    'user-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' }

def get_reviews(code) :
    comments = []
    
    i = 0
    while True :
        url = f"https://stage.mangoplate.com/api/v5{code}/reviews.json?language=kor&device_uuid=V3QHS15862342340433605ldDed&device_type=web&start_index={i}&request_count=50&sort_by=2"
        req = requests.get(url, headers = custom_header)
        
        if req.status_code == requests.codes.ok:    
            print("접속 성공")
            reviews = json.loads(req.text)
            
            if len(reviews) == 0:
                break
                
            for review in reviews:
                comment = review["comment"]
                text = comment["comment"]
                comments.append(text)
            
        else:
            print("Error code")
        i = i + 5
    
    return comments
    
    

def main() :
    href = "/restaurants/iMRRP69qtkeO"
    print(get_reviews(href))
    

if __name__ == "__main__" :
    main()
# 실습 - 음식저 href 크롤링

# 음식점 href 크롤링
# 이전에는 크롤링하고 싶은 음식점의 고유 번호 값을 직접 입력해주어야 했기에 크롤링하기 불편했습니다.
# 여러 음식점을 손쉽게 크롤링할 수 있도록 특정 키워드를 검색하였을 때 검색 결과로 나타나는 식당들의 이름과 href 링크 정보를 얻어와봅시다.

from bs4 import BeautifulSoup
import requests
import json            #json import하기

custom_header = {
    'referer' : 'https://www.mangoplate.com/',
    'user-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' }


def get_restaurants(name) :
    # 검색어 name이 들어왔을 때 검색 결과로 나타나는 식당들을 리스트에 담아 반환하세요.
    restaurant_list = []
    
    url = "https://www.mangoplate.com/search/" + name
    req = requests.get(url, headers = custom_header)
    soup = BeautifulSoup(req.text, "html.parser")
    
    restaurants = soup.find_all("div", class_="list-restaurant-item")
    
    for rest in restaurants:
        info = rest.find("div", class_="info")
        href = info.find("a")["href"]
        title = info.find("h2").get_text().replace('\n', '').replace(' ', '')
        restaurant_list.append([title, href])
    
    
    return restaurant_list
    

def main() :
    name = input()
    
    restaurant_list = get_restaurants(name)
    
    for rest in restaurant_list:
        print(rest[1])

if __name__ == "__main__" :
    main()
# 실습 - 검색 결과 음식점 리뷰 크롤링

# 특정 검색어를 입력하면, 해당 검색어에 관련된 음식점들의 리뷰 상위 5개를 각각 찾아 출력합니다.

from bs4 import BeautifulSoup
import requests
import json            #json import하기

custom_header = {
    'referer' : 'https://www.mangoplate.com/',
    'user-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' }

def get_reviews(code) :
    comments = []
    
    url = f"https://stage.mangoplate.com/api/v5{code}/reviews.json?language=kor&device_uuid=V3QHS15862342340433605ldDed&device_type=web&start_index=0&request_count=5&sort_by=2"
    req = requests.get(url, headers = custom_header)
    
    # req에 데이터를 불러온 결과가 저장되어 있습니다.
    # JSON으로 저장된 데이터에서 댓글을 추출하여 comments에 저장하고 반환하세요.
    if req.status_code == requests.codes.ok:
        print("접속 성공")
        reviews = json.loads(req.text)
        
        for review in reviews:
            comment = review["comment"]
            text = comment["comment"]
            comments.append(text)
                
    else:
        print("Error code")
    
    return comments
    

def get_restaurants(name) :
    url = f"https://www.mangoplate.com/search/{name}"
    req = requests.get(url, headers = custom_header)
    soup = BeautifulSoup(req.text, "html.parser")
    
    # soup에는 특정 키워드로 검색한 결과의 HTML이 담겨 있습니다.
    # 특정 키워드와 관련된 음식점의 이름과 href를 튜플로 저장하고,
    # 이름과 href를 담은 튜플들이 담긴 리스트를 반환하세요.
    restaurants = soup.find_all("div", class_="list-restaurant-item")
    
    restaurant_list = []
    
    for rest in restaurants:
        info = rest.find("div", class_="info")
        href = info.find("a")["href"]
        title = info.find("h2").get_text().replace('\n', '').replace(' ', '')
        restaurant_list.append([title, href])    
        
    return restaurant_list
        
    

def main() :
    name = input("검색어를 입력하세요 : ")
    
    restuarant_list = get_restaurants(name)
    
    for r in restuarant_list :
        print(r[0])
        print(get_reviews(r[1]))
        print("="*30)
        print("\n"*2)

if __name__ == "__main__" :
    main()
반응형

댓글