본문 바로가기

Data Scientist

웹크롤링(Requests & BeautifulSoup)

반응형

웹페이지는 html(hyper text markup language) / CSS / Javascript 가 섞여있다. 

 

웹 크롤링 (Web Crawler)

- 웹 크롤러란 자동화된 방법으로 웹(Web)에서 다양한 정보를 수집하는 소프트웨어다.

- 원하는 서비스에서 원하는 정보를 편하게 얻어올 수 있다.

- 언어를 막론하고 구현할 수 있지만, 주로 Python을 이용한다.

 

 

 

파이썬으로 크롤링할 때, 주로 사용하는 라이브러리

  1. Requests: 파이썬에서 동작하는 작고 빠른 브라우저
    • 웹서버로부터 초기 HTML만 받을 뿐, 추가 CSS/JavaScript 처리 X
    • 거의 모든 플랫폼에서 구동 가능
  2. Selenium: 브라우저 X, 브라우저를 원격 컨트롤하는 테스팅 라이브러리
    • Chrome, Firefox, IE, phantomJS 등
    • 기존 브라우저를 사용하므로, 추가 CSS/JavaScript 처리 지원
    • 리소스를 많이 먹는다. 사이트에 따라 죽기도 한다.
  3. BeautifulSoup4: HTML parser
    • 지정 HTML로부터 원하는 위치/형식의 문자열을 획득
    • 주로 Requests에 의해 많이 사용되지만, Selenium에서도 사용할 수 있다.

 

실습을 해보자..

나동빈님 개인웹

여기의 공지사항을 긁어보자

import requests

# 특정 URL에 접속하는 요청(Request) 객체를 생성합니다.
request = requests.get('http://www.dowellcomputer.com/main.jsp')

# 접속한 이후의 웹 사이트 소스코드를 추출합니다
html = request.text.strip()

print(html)

html 코드

import requests
from bs4 import BeautifulSoup

# 특정 URL에 접속하는 요청(Request) 객체를 생성합니다.
request = requests.get('http://www.dowellcomputer.com/main.jsp')
# 접속한 이후의 웹 사이트 소스코드를 추출합니다.
html = request.text
# HTML 소스코드를 파이썬 BeatifulSoup 객체로 변환합니다.
soup = BeautifulSoup(html, 'html.parser')

# <a> 태그를 포함하는 요소를 추출합니다.
links = soup.select('td > a')

# 모든 링크에 하나씩 접근합니다.
for link in links:
  # 링크가 href 속성을 가지고 있다면
  if link.has_attr('href'):
    # href 속성의 값으로 notice라는 문자가 포함되어 있다면
    if link.get('href').find('notice') != -1:
      print(link.text)
      
자바 기초 프로그래밍 강좌를 완강했습니다.
컴잘알에 오신 것을 환영합니다.

이런 식으로 requests를 이용해서 특정 url에 접속하는 객체를 생성하고 

그 중에서도 text만 뽑는다. 

for구문을 사용해서 모든 링크에 하나씩 접근을 하고 그 하나의 링크가 href 속성을 가지고 있으면(if구문)

notice를 찾아서 -1과 같지 않다면 link의 텍스트를 출력하란 코드이다. 

그리고 links는 'td' 중에서 'a' 태그를 포함하는 것만 뽑아온다.

출력 결과물을 보면 공지사항의 제목이 잘 출력된 것을 확인할 수 있다. 

왜 a냐면 다음 사진을 보면 이해가 된다. 

이 사진은 화면에서 'F12' 키를 누르면 개발자도구가 뜨고 오른쪽 분할 화면으로 구조가 나타난다. 

그 중에서 공지사항의 제목이 해당하는 태그가 'a' 인 것을 확인할 수 있다. 

 

이제 Requests와 BeautifulSoup을 이용해서 네이버 뉴스기사를 크롤링해보자.

 

네이버 뉴스속보

2020년 2월 26일 기준 네이버 뉴스의 속보 화면이다. 

더보기

코로나가 난리인데.. 현재 확진환자가 1146명이다. 

어서 종식되길 바란다.. 아니 마스크 가격이라도 내려가면 좋겠다.

어차피 봄되면 미세먼지 때문에 계속 써야되는데.. 너무 비싸다 

하나에 4~5천원이라니.. 돈도 없는 취준생 입장에서는 

울며 겨자를 먹으려해도 겨자도 못구하는 판이다. 

import requests
from bs4 import BeautifulSoup

url = "https://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1=001"

html = requests.get(url).text
soup = BeautifulSoup(html, "html.parser")

all = soup.find("ul", {'class': "type06_headline"})
dl = all.find_all("dl")

for item2 in dl:
    try:
        img = item2.find('dt', {'class':'photo'}).find('img')
        print('img= ', img['src'])
        print('-------------------------------')
    except:
        print('No image')

이렇게 코드를 입력하면 크롤링하는 당시에 네이버 뉴스기사들이 크롤링되는데 이 코드의 경우 기사 옆의 사진들 주소를 가져오는 코드이다.  하나를 열어보면 사진만 가져온 것을 확인할 수 있다.

 

크롤링 된 네이버 뉴스의 사진들(링크)

    - find() 및 find_all()함수

함수 인자로는 찾고자 하는 태그의 이름, 속성 기타 등등이 들어간다.

find(name, attrs, recursive, string, **kwargs)

 

find() : 해당 조건에 맞는 하나의 태그를 가져온다. 중복이면 가장 첫 번째 태그를 가져온다.

find_all(name, attrs, recursive, string, limit, **kwargs)

find_all() : 해당 조건에 맞는 모든 태그들을 가져온다.

dl = all.find_all("dl")

for item2 in dl:      # dl 태그 모두 찾은 뒤 하나씩 뽑는다
    link = item2.find("dt", {"class" : ""}).find("a")     # dl 하위에서 dt태그를 찾고 a태그를 찾는다. 
    print(link["href"])     # link 중에 href를 출력
    # replace를 통해서 탭,줄띄움을 모두 공백으로 바꾸고
    # 문장들 중 첫번째 자리(스페이스)를 짤라낸다
    print(link.text.replace("\t", "").replace("\n", "")[1:len(link.text)+1])
   
dl = all.find_all("dl")     
for item2 in dl:    
    try:         
        content = item2.find("dd")  
        print(content.text.replace("\t","").replace("\n","").split("...")[0])     
    except: 
        print("No Content") 

이 코드는 뉴스의 링크주소와 헤드라인, 기사내용을 가져온 것을 알 수 있다. 

 

 

혹시 requests를 쓰는데 에러가 날 수도 있다. 

import requests 
from bs4 import BeautifulSoup

# 특정 URL에 접속하는 요청(request) 객체를 생성 

# 접속한 이후의 웹 사이트 소스코드를 추출한다. 
html = requests.get('http://google.com').text # 가져온 html 문자를 숩에 넘겨
soup = BeautifulSoup(html, 'html.parser') 
print(soup.find('h1').text)

AttributeError: 'NoneType' object has no attribute 'text'

''' h1 태그를 못찾아서 soup.find('h1')에서 None이 발생'''

이러한 문제가 발생했다면 다음과 같은 상황일 것이다. 

 

- '페이지 소스' 메뉴를 통해 본 HTML은 웹서버로부터 받은 최초의 HTML

   이 HTML 구조는 로딩 후에 변경될 수 있다. by JavaScript

- '브라우저 개발자도구'를 통해 확인한 구조

   최초의 구조로부터 JavaScript를 통해 변경된 구조

 

>우리는 ReactJS라는 JavaScript 코드를 통해 내용이 그려진 웹페이지를 본 것 이다.

뭔말인지 잘모르겠지만 우리가 보고있는 태그와 실제 태그가 다르다는 것 같다. 

이렇게 다를 때는 어떻게 해야하는걸까..

 

이럴 때는 Selenium을 써야한다.

Selenium은 웬만하면 다 된다고 한다..

하지만 쓸 수만 있다면 Requests가 성능이 수백배 좋다고 한다. 

다음 글에서는 Selenium을 통해 자동화를 시도하겠다. 

 

😁

 

출처: 

https://2.python-requests.org/en/master/user/quickstart/#make-a-request

 

Quickstart — Requests 2.23.0 documentation

Eager to get started? This page gives a good introduction in how to get started with Requests. Let’s get started with some simple examples. Passing Parameters In URLs You often want to send some sort of data in the URL’s query string. If you were construct

2.python-requests.org

나동빈님 유튜브: https://youtu.be/kiowbtjDrWo

AskDjango이진석님: https://www.youtube.com/watch?v=7_IEdMv9eFE

 

반응형