크롤링

msung99·2022년 5월 5일
0

크롤링(Crawling)

  • 크롤러(Crawler) : 뜻=> 1. 기는 것 2. 파충류

    • 웹사이트를 기어다니면서 데이터를 모아주는 소프트웨어
  • 크롤링 : 크롤러의 웹 페이지릐 데이터를 추출해 내는 행위

  • 파이썬을 활용해 크롤링 시도하면 된다


함수와 모듈

함수를 통해 반복되는 작업 효율적으로 처리가능
모듈은 함수의 집합(라이브러리)


클라이언트(요청) <=> 서버(응답)

  • 요청 종류 : put, set, post, delete 요청

  • 클라이언트 : 서버에 요청을 하는 존재

  • 서버 : 클라이언트의 요청에 대한 응답을 회신하는 존재

    • 클라이언트가 www.daum.net의 정보를 요청하면, 서버가 요청을 받고 daum 홈페이지의 html 정보로 응답을 보내줌
    • 클라이언트는 응답받은 정보를 기반으로 실시간 검색어를 찾아봄

requests 모듈

  • pip을 통해 requests 모듈 설치
$pip install requests : pip 라는 도구가 requests 라는 외부 모듈을 찾아서 로컬에 설치해줌
  • requests 모듈 import
import requests

requests.get()

  • requests.get( url, params = None, **kwargs )
    • get 요청을 보내는 기능. 응답을 리턴받을 수 있음
    • url : 요청을 보낸 서버의 주소

(reponse는 get()의 요청에 대한 응답을 저장하는 변수)

응답 메소드(기능들)

response.text : 응답으로 받아오는 HTML 태그의 내부에 있는 텍스트 값을 가져옵니다.

response.url : 응답으로 받아오는 HTML 태그의 a태그에서 url 값을 가져옵니다.

response.content : 텍스트 기능과 비슷하지만 약간의 차이가 있다면 텍스트는 유니코드 값을, 컨텐츠는 바이트 값을 가져오는 것을 알 수 있습니다.

response.encoding : en-이라는 단어 자체가 어디에서 “속하다”인데 데이터가 담긴 할당공간(박스)의 번호정도로 추측해 보았습니다.

response.headers : HTML의 header라는 곳의 정보를 가져오는 응답 값 메소드입니다.

response.json : 딕셔너리와 비슷한 형태의 웹 통신에 사용되는 자료 구조라 생각하면 될 것 같습니다.

response.links : header에 있는 link 태그 값을 가져옵니다.

response.ok : 서버에서 응답을 잘 처리했을 때 반환하는 값입니다.

response.status_code : 응답이 속하는 현황을 보여주는 번호로 200, 300, 400 등 다양한 번호가 있습니다.

import requests

url = "http://www.daum.net"
response = requests.get(url) # get()으로 해당 url에다 요청후 응답받은 
# 응답을 response 변수에 저장 

print(response.text) # 응답을 저장하는 변수에서 html 코드를 모두 출력

print(response.text)


BeautifulSoup

  • 로컬에 따로 bs4 모듈을 설치 받아야함
  • BeautifulSoup는 bs4 모듈안에 탑제되있는 메소드

BeautifulSoup vs response

BeautifulSoup란?

  • 우리가 가져온 데이터를 기반으로 의미있는 데이터로 변경하는 것을 도와줌
  • response.text 의 문자열 덩어티 타입 데이터 하나를 BeautifulSoup라는 타입의 통에다가 잘게잘게 나눠서 보기 좋게 정리한다.
import requests
from bs4 import BeautifulSoup

url = "http://www.daum.net/"
response = requests.get(url) 

print(type(response.text)) 
# 출력 : <class 'str'> => 문자열 타입

print(type(BeautifulSoup(response.text, 'html.parser'))) 
# 출력 : <'bs4.BeautifulSoup'>
# => 문자열 이었던 타입을 다른 타입으로 변환함
# response.text 라는 문자열 타입 덩어리 하나를 BeautifulSoup 라는 통 안에다 보기 좋게 
# 예쁘게 정리함. 그래서 그 저장한 통의 타입 <'bs4.BeautifulSoup'> 이 출력됨

BeautifulSoup 형태, 파싱과 파서(parser)

BeautifulSoup(데이터, 파싱방법)

my_soup = BeautifulSoup(response.text, 'html.parser')

* 통에 담을 데이터 : response.text
* 파서 이름 : html.parser (html을 파싱하는 파서의 이름)
  • 뭉쳐저있는 문자열을 하나씩 떼서 통에 담는 기능

  • 데이터 : BeautifulSoup라는 통에 담을 데이터

    • 데이터 종류 : HTML, XML
    • 데이터는 reponse.text 와 같이 html 을 가져오면 된다.
  • 파싱방법
    • 파싱 : 우리의 문서, 데이터를 의미있게 변경하는 작업
      • 다시말해, 문자열로 뭉쳐진 의미있는 데이터로 쪼개는 과정
    • 즉, 어떤 문장, 문자열들을 분석해서 의미가 있는 데이터들로 변경하는 것
  • 파서(parser) : 파싱을 도와주는 프로그램
    • html.parser => 파이썬에 내장된 기본 파서

BeautifulSoup 메소드

  • response 처럼 BeautifulSoup도 다양한 기능을 제공한다.
    • 그 기능들을 활용해서 BeautifulSoup가 쪼갠 여러 데이터중 원하는 데이터를 추출

메소드

  • my_soup.title : < title > 태그를 리턴

  • my_soup.title.string : 해당 태그의 문자만을 리턴

  • my_soup.span : html문서 안에있는 가장 상단의 span 태그를 리턴

  • my_soup.findAll('span')) : html문서 중에 인자값(여기서는 span) 으로 부여한 태그를 모두 리턴

    • 즉, 문서 안에 존재하는 모든 span 태그를 리턴
    • span 태그 안에 있는 모든 태그들도 함께 리턴
  • result.get_text() : result 변수에 저장된 해당 테그에 들어있는 텍스트 내용을 출력

예제1

import requests
from bs4 import BeautifulSoup

url = "http://www.daum.net/"
response = requests.get(url)
print(response.text[:500])

my_soup = BeautifulSoup(response.text, 'html.parser')

print(my_soup.title)   # 출력 : <title>Daum</title> =>     html문서 response.text 에서 <title> 태그를 리턴
print(my_soup.title.string)   # 출력 : Daum =>    파이썬에서 문자를 의미
print(my_soup.span)   # 출력 : None =>    최상단의 span 태그 하나만을 리턴
print(my_soup.findAll('span'))   # 출력 : 너무 많아서 생략ㅜㅜ =>    html 태그 안에 있는 모든 span 태그를 리턴

예제2


import requests
from bs4 import BeautifulSoup

url = "http://www.daum.net/"
response = requests.get(url)

my_soup = BeautifulSoup(response.text, 'html.parser')

file = open("daum.html", "w")   # 새로운 html 파일 쓰기모드로 생성
file.write(response.text)  # 생성한 daum.html 파일에다 response.text 문자열 내용을 써준다.
file.close()

# print(my_soup.title)    
# print(my_soup.title.string)  
# print(my_soup.span)  
# print(my_soup.findAll('span'))  

실시간 검색어 태그를 html 파일에서 추출하기

예제2에서 만든 daum.html 파일의 일부 내용을 살펴보면 아래와 같다.

아래 코드를 분석해보면, 실시간 검색어의 공통점은 2가지를 지닌다.
1. < a > 태그이다.
2. link_favorsch 라는 클래스를 가진다.

=> 실시간 검색어를 가져오기 위해선 바로 아래 코드처럼
모든 a태그를 가져오면 된다.
그런데 여기서 a태그라는 추출 조건외에도 추가 조건을 매달 수 있다.

result = my_soup.findAll("a", "link_favorsch")

# my_soup 한테 html 문서에서 모든 a 태그들 중에 link_favorsch 라는 
# 클래스를 가진 것들만 찾아줌
# 변수에 할당시, 이 변수를 리스트 변수가 된다. 즉, 리스트 변수에 저장하는 셈임

for result in results: # 실시간 검색어 태그, 즉 <a> 태그를 하나씩 출력
  print(result, '\n')

html 파일 (일부 발췌)

<h3 class="screen_out">인기 검색어</h3>
<div class="slide_favorsch" data-tiara-layer="hot_issue">
<ul class="list_favorsch hide" data-tiara-layer="txt" data-tiara-action-name="검색창_하단_인기검색어">
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EC%83%9D%ED%99%9C+%EC%86%8D+%EA%B1%B0%EB%A6%AC%EB%91%90%EA%B8%B0&amp;DA=NPI" class="link_favorsch @6">생활 속 거리두기</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EB%B0%95%EC%84%B1%EC%9B%85+MC%EB%B0%9C%ED%83%81&amp;DA=NPI&amp;rtmaxcoll=NNS" class="link_favorsch @7">박성웅 MC발탁</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%ED%83%80%EA%B3%B5%ED%8C%90&amp;DA=NPT" class="link_favorsch @8">타공판업체</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EA%B9%80%EC%86%8C%ED%98%84+12%EC%A3%BC%EB%85%84&amp;DA=NPI&amp;rtmaxcoll=NNS" class="link_favorsch @9">김소현 12주년</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EC%A0%84%EC%9B%90%EC%A3%BC%ED%83%9D%EB%A7%A4%EB%A7%A4&amp;DA=NPT" class="link_favorsch @10">전원주택매매</a>
</li>
</ul>
<ul class="list_favorsch " data-tiara-layer="txt" data-tiara-action-name="검색창_하단_인기검색어">
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EC%BD%94%EB%A1%9C%EB%82%9819+%EB%B0%9C%EC%83%9D%ED%98%84%ED%99%A9&amp;DA=NPI" class="link_favorsch @6">코로나19 발생현황</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EB%8B%A4%EB%8B%88%EC%97%98%EB%A6%B0%EB%8D%B0%EB%A7%8C+%ED%95%B4%EB%AA%85&amp;DA=NPI&amp;rtmaxcoll=NNS" class="link_favorsch @7">다니엘린데만 해명</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EA%B5%AD%EB%82%B4%EA%B3%A8%ED%94%84%ED%88%AC%EC%96%B4&amp;DA=NPT" class="link_favorsch @8">국내골프투어</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%ED%95%9C%EC%98%88%EC%8A%AC+%ED%99%94%EB%B3%B4&amp;DA=NPI&amp;rtmaxcoll=NNS" class="link_favorsch @9">한예슬 화보</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%ED%94%8C%EB%9D%BC%EC%8A%A4%ED%8B%B1%EC%9A%A9%EA%B8%B0&amp;DA=NPT" class="link_favorsch @10">플라스틱용기</a>
</li>
</ul>
<ul class="list_favorsch hide" data-tiara-layer="txt" data-tiara-action-name="검색창_하단_인기검색어">
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EC%83%8C%EB%93%9C%EB%B0%95%EC%8A%A4+%EC%82%AC%EA%B3%BC&amp;DA=NPI&amp;rtmaxcoll=NNS" class="link_favorsch @6">샌드박스 사과</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EA%B9%80%ED%98%9C%EC%98%81+%EB%B3%B5%EA%B7%80&amp;DA=NPI&amp;rtmaxcoll=NNS" class="link_favorsch @7">김혜영 복귀</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EC%95%A0%EA%B2%AC%EA%B0%84%EC%8B%9D&amp;DA=NPT" class="link_favorsch @8">애견간식</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EB%B0%95%EC%84%A0%ED%98%B8+%EC%9E%85%EB%8C%80&amp;DA=NPI&amp;rtmaxcoll=NNS" class="link_favorsch @9">박선호 입대발표</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&amp;q=%EB%B6%84%ED%99%8D%EC%BD%94%EB%81%BC%EB%A6%AC%EC%8B%A0%EB%B0%9C&amp;DA=NPT" class="link_favorsch @10">분홍코끼리신발</a>
</li>
</ul>
</div>

예쁘게 추출하기

  • html 문서의 태그를 추출하는 것이 아닌, 태그 안의 내용을 추출해보자.
from bs4 import BeautifulSoup
import requests

url = "http://www.daum.net/"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

results = soup.findAll('a','link_favorsch')

count = 1
for result in results:
    print(count,"위 : ",result.get_text(),"\n")
    count += 1

출력결과

1위. 생활 속 거리두기
2위. 김희철 MC 확정
3위. 목포호텔추천
4위. 김요한 거부
...(이하 생략)

datatime 모듈

  • 날짜 정보를 얻어올 수 있는 모듈

메소드

datatime.today()) : 오늘 날짜 정보를 리턴

print(datatime.today()) # 출력: 2022-05-05 07:45:49.374918

추가기능 : strftime

print(datatime.strftime("%Y년 %m월 %d일의 실시간 검색어 순위입니다.\n")
# 출력 : 2020년 08월 12일의 실시간 검색어 순위입니다.

전체코드

from bs4 import BeautifulSoup
import requests
from datetime import datetime

url = "http://www.daum.net/"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
rank = 1

results = soup.findAll('a','link_favorsch')

print(datetime.today().strftime("%Y년 %m월 %d일의 실시간 검색어 순위입니다.\n"))

for result in results:
    print(rank,"위 : ",result.get_text(),"\n")
    rank += 1

네이버 크롤링

  • 크롤링 로봇이 아님을 알려주기 위해 아래와 같은 코드 추가
    • 우리가 로봇이아니고, 어떤 환경에서 프로그램을 사용하고 있다는 정보를 전달
headers1 = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
  • 그리고 이 인자를 get() 의 headers 라는 2번쨰로 인자로 할당한다.

=> request 요청의 get 함수가 서버에 요청을 보낼때, headers 를 통해 크롤링 봇이 아님을 네이버에게 알려줄 수 있다.

이에 따른 네이버에서는 크롤링 봇이 아님을 인식하고 응답을 다시 우리에게 보내준다.

from bs4 import BeautifulSoup
import requests
from datetime import datetime

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
url = "https://datalab.naver.com/keyword/realtimeList.naver?age=20s"

response = requests.get(url, headers = headers1)

soup = BeautifulSoup(response.text, 'html.parser')

rank = 1
results = soup.findAll('span','item_title')

print(response.text)
search_rank_file = open("rankresult.txt","a")
print(datetime.today().strftime("%Y년 %m월 %d일의 실시간 검색어 순위입니다.\n"))

for result in results:
    search_rank_file.write(str(rank)+"위:"+result.get_text()+"\n")
    print(rank,"위 : ",result.get_text(),"\n")
    rank += 1
profile
https://haon.blog

0개의 댓글