크롤러(Crawler) : 뜻=> 1. 기는 것 2. 파충류
크롤링 : 크롤러의 웹 페이지릐 데이터를 추출해 내는 행위
파이썬을 활용해 크롤링 시도하면 된다
함수를 통해 반복되는 작업 효율적으로 처리가능
모듈은 함수의 집합(라이브러리)
요청 종류 : put, set, post, delete 요청
클라이언트 : 서버에 요청을 하는 존재
서버 : 클라이언트의 요청에 대한 응답을 회신하는 존재
$pip install requests : pip 라는 도구가 requests 라는 외부 모듈을 찾아서 로컬에 설치해줌
import requests
(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란?
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(데이터, 파싱방법)
my_soup = BeautifulSoup(response.text, 'html.parser')
* 통에 담을 데이터 : response.text
* 파서 이름 : html.parser (html을 파싱하는 파서의 이름)
뭉쳐저있는 문자열을 하나씩 떼서 통에 담는 기능
데이터 : BeautifulSoup라는 통에 담을 데이터
my_soup.title : < title > 태그를 리턴
my_soup.title.string : 해당 태그의 문자만을 리턴
my_soup.span : html문서 안에있는 가장 상단의 span 태그를 리턴
my_soup.findAll('span')) : html문서 중에 인자값(여기서는 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'))
예제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&q=%EC%83%9D%ED%99%9C+%EC%86%8D+%EA%B1%B0%EB%A6%AC%EB%91%90%EA%B8%B0&DA=NPI" class="link_favorsch @6">생활 속 거리두기</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EB%B0%95%EC%84%B1%EC%9B%85+MC%EB%B0%9C%ED%83%81&DA=NPI&rtmaxcoll=NNS" class="link_favorsch @7">박성웅 MC발탁</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%ED%83%80%EA%B3%B5%ED%8C%90&DA=NPT" class="link_favorsch @8">타공판업체</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EA%B9%80%EC%86%8C%ED%98%84+12%EC%A3%BC%EB%85%84&DA=NPI&rtmaxcoll=NNS" class="link_favorsch @9">김소현 12주년</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EC%A0%84%EC%9B%90%EC%A3%BC%ED%83%9D%EB%A7%A4%EB%A7%A4&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&q=%EC%BD%94%EB%A1%9C%EB%82%9819+%EB%B0%9C%EC%83%9D%ED%98%84%ED%99%A9&DA=NPI" class="link_favorsch @6">코로나19 발생현황</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&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&DA=NPI&rtmaxcoll=NNS" class="link_favorsch @7">다니엘린데만 해명</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EA%B5%AD%EB%82%B4%EA%B3%A8%ED%94%84%ED%88%AC%EC%96%B4&DA=NPT" class="link_favorsch @8">국내골프투어</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%ED%95%9C%EC%98%88%EC%8A%AC+%ED%99%94%EB%B3%B4&DA=NPI&rtmaxcoll=NNS" class="link_favorsch @9">한예슬 화보</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%ED%94%8C%EB%9D%BC%EC%8A%A4%ED%8B%B1%EC%9A%A9%EA%B8%B0&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&q=%EC%83%8C%EB%93%9C%EB%B0%95%EC%8A%A4+%EC%82%AC%EA%B3%BC&DA=NPI&rtmaxcoll=NNS" class="link_favorsch @6">샌드박스 사과</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EA%B9%80%ED%98%9C%EC%98%81+%EB%B3%B5%EA%B7%80&DA=NPI&rtmaxcoll=NNS" class="link_favorsch @7">김혜영 복귀</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EC%95%A0%EA%B2%AC%EA%B0%84%EC%8B%9D&DA=NPT" class="link_favorsch @8">애견간식</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EB%B0%95%EC%84%A0%ED%98%B8+%EC%9E%85%EB%8C%80&DA=NPI&rtmaxcoll=NNS" class="link_favorsch @9">박선호 입대발표</a>
</li>
<li>
<a href="https://search.daum.net/search?w=tot&q=%EB%B6%84%ED%99%8D%EC%BD%94%EB%81%BC%EB%A6%AC%EC%8B%A0%EB%B0%9C&DA=NPT" class="link_favorsch @10">분홍코끼리신발</a>
</li>
</ul>
</div>
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.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'}
=> 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