파이썬 프로그래밍

파이썬 자동화 데이터 웹 크롤링 requests, BeautifulSoup 샘플 프로그래밍

코니코니 2022. 10. 1. 21:00
반응형

파이썬 자동화 데이터 웹 크롤링 requests, BeautifulSoup 샘플 프로그래밍

파이썬에서 셀레니움과 같이 웹 자동화 기능을 사용해서 웹에서 특정 데이터를 수집할 수 있겠지만 셀레니움은 아무래도 웹을 직접 움직이는 방식이다 보니까 무겁고 속도도 느리다는 단점이 있습니다. 반면 requests와 BeautifulSoup 모듈을 사용하면 보다 간결하고 빠르게 웹 데이터를 수집할 수 있습니다. 두개의 모듈은 pip을 통해서 먼저 설치를 해줘야 합니다.

pip install requests
pip install beautifulsoup4

그럼 requests 부터 간단한 예시 코드를 보도록 하죠.

test = requests.get("https://api.ipify.org", timeout=5).text
print(test)

==결과==
210.220.151.252

requests.get("사이트").text 기능을 통해서 원하는 사이트의 html 정보를 통으로 가져올 수 있는데 해당 ipify 사이트의 경우에는 html 요소에 접속 아이피만을 보여주기 때문에 결과값이 아이피만 나오는 것을 볼 수 있습니다. timeout=5를 넣어준 것은 페이지 요청을 할 때 5초 이상 시간이 걸리면 타임아웃 에러를 발생시키는 기능입니다. 의무적으로 넣어줄 필요는 없죠.

test = requests.get("https://www.musinsa.com/", timeout=5).text
print(test)

==결과==
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
</body>
</html>

그러나 무신사의 경우에는 결과에서 403 에러를 볼 수 있습니다. 이유는 서버에서 요청을 확인할 때 정상적인 요청이 아니라고 판단을 하여 접속 자체를 못하게 막는 것인데 이유는 서버간 소통을 할 때 필요한 신분증과도 같은 헤더값이 없기 때문입니다.

크롬 개발자도구를 통해서 웹 접속 후 요청 헤더값을 보면 다양한 요소들이 서버로 전송이 되는 것을 볼 수 있습니다. 이렇게 정보들이 같이 서버로 전송이 되어야 정상적인 접속 요청으로 인식을 하는 것이죠. 그러나 단순하게 서버에 접속만 하는 용도로는 이렇게 모든 값들이 들어갈 필요는 없습니다.

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                         'Chrome/104.0.0.0 Safari/537.36'}


test = requests.get("https://www.musinsa.com/", timeout=5, headers=headers).text
print(test)

==결과==
.
.
.
< div class ="n-banner-info" >< span class ="n-banner-brandname" > 로드 존 그레이 
< / span > < a href = "/app/plan/views/25098" class ="n-banner-title font-mss" > 
22 F / W 신상품 발매ㅣ최대 10 % 쿠폰 할인 < / a > < span
class ="n-banner-label font-mss" > NEW ARRIVAL < / span > < / div >
.
.
.

헤더값에 user-agent 정도만 넣어주고 요청을 보내도 거의 대부분의 사이트에서는 정상적인 소통이 가능합니다. 그리고 자바스크립트로 구성된 사이트의 경우에는 요청만으로는 해결이 어려울 수 있는데 이런 경우에는 좀 더 디테일한 설명이 필요하기 때문에 나중에 따로 포스팅을 작성하는게 좋겠네요!

이렇게 requests만으로 html을 가져올 수 있다면 이제 이 소스에서 BeautifulSoup과 연동해 특정 데이터들을 추출할 수 있습니다.

크롬 개발자도구를 통해서 사이트 요소의 명칭들을 볼 수 있습니다. 위 예시는 무신사 스토어에서 가디건을 검색하고 상품들의 제목 요소를 찾은 경우인데 제목들의 클래스 명은 list_info입니다 이제 이 값을 BeautifulSoup에서 가져와보도록 하겠습니다.

site_url = 'https://www.musinsa.com/search/musinsa/integration?type=&q=%EA%B0%80%EB%94%94%EA%B1%B4'
test = requests.get(site_url, timeout=5, headers=headers).text
# BeautifulSoup에 requests 데이터 넣기
soup = BeautifulSoup(test, 'html.parser')
# find_all 기능으로 class명이 list_info인 요소를 전부 찾기
site_data = soup.find_all(class_='list_info')

for s in site_data:
    # replace 함수로 필요없는 문자열 제외시키기
    get_txt = s.text.replace('  ', '').replace('\n', '')
    print(get_txt)

==결과==
Miller Heavyweight Cardigan Dust
화란 세미오버 가디건 블랙
10/19 배송 Miller Heavyweight Cardigan Burnt Orange
9/19 배송 GAFF TEX CARDIGAN (BLACK)
Miller Heavyweight Cardigan Navy
10/7 배송 V NECK CABLE CARDIGAN NAVY
소프트 베이직 가디건 블랙
오디너리 크롭 가디건 블랙
엔젤 와펜 가디건 블랙
9/23 배송 헤비오버핏 램스울 가디건 챠콜
오버핏 크롭 카라 가디건 [블랙]
화란 세미오버 가디건 클라우드 그레이
'
'
'

requests로 가져온 html 데이터를 BeautifulSoup에 연동을 시켜서 클래스 명으로 요소를 찾아서 텍스트를 출력하는 코드입니다.

site_url = 'https://www.musinsa.com/search/musinsa/integration?type=&q=%EA%B0%80%EB%94%94%EA%B1%B4'
test = requests.get(site_url, timeout=5, headers=headers).text
# BeautifulSoup에 requests 데이터 넣기
soup = BeautifulSoup(test, 'html.parser')
# find_all 기능으로 class명이 list_info인 요소를 전부 찾기
site_data = soup.find_all(class_='list_info')

site_url에는 크롤링 타겟 주소를 넣어주고 requests로 받아온 데이터를 test 변수에 넣어줍니다. 그리고 BeautifulSoup(test, 'html.parser') 기능을 사용해 BeautifulSoup에 데이터를 연결시키고 soup이라는 변수에 넣었습니다.

요소를 찾는 기능으로는 find, find_all, select 등 다양한 방식으로 요소를 찾을 수 있는데 저같은 경우에는 find, find_all 두가지 기능을 많이 사용합니다. find와 find_all의 차이는 요소를 하나만 찾는 것과 여러개를 한번에 찾는다는 것에 차이가 있다고 보면 됩니다.

soup.find_all(class_='list_info')

이렇게 적은 것은 class 명이 list_info인 모든 요소를 찾아 리스트화 시키는 것이죠. 결국 site_data이라는 변수에는 class 명이 list_info인 모든 요소가 들어가는 것입니다.

for s in site_data:
    # replace 함수로 필요없는 문자열 제외시키기
    get_txt = s.text.replace('  ', '').replace('\n', '')
    print(get_txt)

이제 이 요소가 들어있는 리스트를 for문으로 하나씩 가져와 출력을 하는 것이죠. get_txt라는 변수에는 s.text로 해당 요소의 텍스트만 가져온다는 것이고 replace함수를 통해서 텍스트에서 필요없는 문자열을 제거하여 깔끔하게 텍스트 데이터를 변수에 저장하는 용도라고 볼 수 있습니다. 실제로 replace 없이 추출을 하면 쓸대없는 줄바꿈과 띄어쓰기가 많아서 보기 어렵게 뽑히는 것을 볼 수 있었죠.

이렇게 requests, BeautifulSoup 두가지를 적절하게 사용을 한다면 셀레니움보다 훨씬 효율적으로 데이터를 가공할 수 있지만 위에서 언급했던 내용처럼 자바스크립트와 같은 페이지에서 직접 특정 행동을 해야 요소가 보여지는 경우에는 이렇게 서버상에서 가져오는 데이터 만으로는 크롤링이 힘들 수 있습니다.

그런 경우에는 단순하게 메인 페이지의 url과 상호작용을 하는 것이 아니라 자바스크립트에 연결된 고유 서버와 상호작용을 해야하기 때문에 조금은 까다로운 부분이라고 볼 수 있죠. 이부분은 나중에 포스팅으로 설명을 해보도록 할게요!

반응형