파이썬 강의/requests

파이썬 BeautifulSoup 2. 페이지 정보 추출

마리사라 2021. 1. 25. 23:49
반응형

파이썬 BeautifulSoup 2번째 강의는 페이지의 정보를 추출하는 방법입니다.


0. 기초 설명

이전 강의에서 페이지를 크롤링을 하는 방법을 알아보았습니다. 하지만 크롤링 만으로는 단순한 문자의 집합에 불과합니다. 이것을 가공하여 실제로 사용할 수 있는 데이터로 만들어 주어야 합니다.

 

네이버 뉴스 토픽

네이버의 뉴스 토픽을 예시로 들어 보겠습니다. 해당 데이터를 가지고 파이썬에서 현재 뉴스 토픽 1위가 무엇인지 확인하고자 한다고 하겠습니다.

네이버 검색 사이트를 크롤링하여 찾아낸 뉴스토픽 부분

단순한 크롤링 데이터에서 뉴스토픽을 찾기 위해선 아래와 같은 작업이 필요할 것입니다.

  1. 뉴스 토픽이라고 적힌 부분을 찾는다
  2. 1이라고 적힌 부분을 찾아 저장한다
  3. 다음에 오는 텍스트를 찾아 저장한다
  4. 2 ~ 3의 작업을 10위까지 반복한다
  5. 저장된 값들을 적절히 배치한다

하지만 자세히 보면 4번째 줄에 rank라는 class가 있습니다. 그곳에 2라고 적혀 있으니 2등을 의미하는 것이고, txt라는 class에 있는 내용이 해당 등수의 내용이라는 것을 알 수 있습니다. 그렇다면 이제 다음과 같은 방법을 생각해 볼 수도 있습니다.

  1. class="rank"의 값들을 리스트 자료형으로 저장한다
  2. class="txt"의 값들을 리스트 자료형으로 저장한다
  3. 두 리스트 자료형을 1:1 대응시킨다.

이렇게 방법이 더욱 간단해지게 됩니다. 그리고 이것을 가능하게 해주는 모듈이 BeautifulSoup입니다.


1. 실전 코드

뉴스토픽을 검색한 주소

우선 url이 필요합니다. url은 네이버에서 뉴스 토픽을 검색한 주소를 사용하겠습니다.

url = 'https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EB%89%B4%EC%8A%A4%ED%86%A0%ED%94%BD'
query = requests.get(url=url)
soup = BeautifulSoup(query.content, "html.parser")

 

url을 설정하고 requests로 해당 페이지의 정보를 불러온 후, BeautifulSoup로 정보를 변환합니다.

 

필요한 정보는 em의 class="rank"와 span의 class="text"입니다. 이것을 찾아내는 코드는 다음과 같습니다.

# data = soup.find('em', {'class': 'rank'})
data = soup.find_all('em', {'class': 'rank'})

find와 find_all은 같은 파라미터를 필요로 합니다. 첫 번째 파라미터에는 찾을 내용의 태그를, 두 번째 파라미터는 찾을 내용의 하위 태그를 받습니다. 이때 두 번째 파라미터에 딕셔너리 자료형을 넣게 되면, class=txt처럼 정확한 값을 찾을 수 있게 됩니다.

 

data를 출력하면 다음과 같습니다.

결과가 1부터 10까지 간 후, 다시 1부터 10까지 해서 총 20개의 값이 저장됩니다. 이것은 뉴스 토픽에서 뉴스와 연예/스포츠의 결과까지 한 번에 가져왔기 때문입니다.

 

이제 span의 class=txt를 찾아보겠습니다.

data2 = soup.find_all('span', {'class': 'txt'})

이것을 출력하면 다음과 같습니다.

무언가 잘못된 필요 없는 값들까지 들어왔습니다. 이번에 필요한 것은 뉴스 토픽이니 해당 값들이 있는지 찾아보겠습니다.

뒷부분에 필요한 값들이 있는 것을 확인했습니다. 이제 해당 부분의 위치를 찾아보겠습니다.

count = 0
for i in data2:
    if '연예·스포츠' in i:
        break
    count += 1

이렇게 하면, 연예 스포츠가 있는 위치를 알 수 있습니다. 이를 토대로 해당 위치가 맞는지 확인해 보겠습니다.

정상적으로 연예/스포츠가 나왔습니다. 이제 해당 count에 +1을 한 부분부터 우리가 필요한 값이 됩니다.

data2 = data2[count + 1:]

이를 출력해 보면 다음과 같습니다.

아까 보았던 내용과 일치합니다.

 

이제 각각의 값들을 짝지어서 출력해 보겠습니다.

for i in range(20):
    print('%s위 %s' %(data[i], data2[i]))

이를 출력하면 다음과 같습니다.

정상적으로 출력은 됐지만 태그까지 같이 출력돼서 보기에 좋지 않습니다. 이러한 태그를 제거하는 방법은 get_text()가 있습니다.

for i in range(20):
    print('%s위 %s' % (data[i].get_text(), data2[i].get_text()))

해당 데이터 뒤에. get_text()를 붙이게 되면 태그는 빠지고 값만 남게 됩니다. 이를 다시 실행하면 다음과 같습니다.

아까보다 매우 깔끔해졌습니다. 이제 각 1위 사이에 분야만 써주면 될 것 같습니다.

for i in range(20):
    if i == 0:
        print('뉴스')
    elif i == 10:
        print('연예·스포츠')
    print('%s위 %s' % (data[i].get_text(), data2[i].get_text()))

각 항목이 10개이므로, 첫 번째와 11번째에 분야를 써주었습니다.

아까보다 보기에는 더 나아진 듯합니다.


2. 마치며

이번 시간에는 BeautifulSoup로 얻은 데이터에서 유의미한 데이터를 추출하는 방법을 알아보았습니다.

import requests
from bs4 import BeautifulSoup

url = 'https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EB%89%B4%EC%8A%A4%ED%86%A0%ED%94%BD'
query = requests.get(url=url)
soup = BeautifulSoup(query.content, "html.parser")
data = soup.find_all('em', {'class': 'rank'})
data2 = soup.find_all('span', {'class': 'txt'})
count = 0
for i in data2:
    if '연예·스포츠' in i:
        break
    count += 1
data2 = data2[count + 1:]

for i in range(20):
    if i == 0:
        print('뉴스')
    elif i == 10:
        print('연예·스포츠')
    print('%s위 %s' % (data[i].get_text(), data2[i].get_text()))
반응형