Pyhton 웹 크롤링(Web Crawling)
웹 크롤러란?
위키 백과 – https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC
웹 크롤러(web crawler)는 조직적, 자동화된 방법으로 월드 와이드 웹을 탐색하는 컴퓨터 프로그램이다.
웹 크롤러가 하는 작업을 웹 크롤링(web crawling) 혹은 스파이더링(spidering)이라 부른다. 검색 엔진과 같은 여러 사이트에서는 데이터의 최신 상태 유지를 위해 웹 크롤링한다. 웹 크롤러는 대체로 방문한 사이트의 모든 페이지의 복사본을 생성하는 데 사용되며, 검색 엔진은 이렇게 생성된 페이지를 보다 빠른 검색을 위해 인덱싱한다. 또한 크롤러는 링크 체크나 HTML 코드 검증과 같은 웹 사이트의 자동 유지 관리 작업을 위해 사용되기도 하며, 자동 이메일 수집과 같은 웹 페이지의 특정 형태의 정보를 수집하는 데도 사용된다.
크롤링을 위한 Python 모듈
HTTP 요청 모듈 : urllib, requests
urllib 표준 모듈
기본 사용법
- HTTP 를 통해 웹 서버에 데이터를 얻은데 사용
- Python3 에서는 urllib.request 까지 import 해야 오류 안남
import urllib
request = urllib.request.Request(URL)
AttributeError: module 'urllib' has no attribute 'request'
- urllib.parse.quote () : GET 요청시 한글 URL 엔코딩
- urllib.request.urlopen() : urllib.request.Request 객체를 받아 HTTP 요청
- response.getcode() : 응답코드 200 이면 OK, 404 면 File Not Found 등등
- response.read() : html 을 읽어 옴
import urllib.request
search_addr = "http://book.daum.net/search/bookSearch.do?query="
search_word = "파이썬"
search_word_enc = urllib.parse.quote(search_word)
URL = search_addr + search_word_enc
request = urllib.request.Request(URL)
response = urllib.request.urlopen(req)
status_code = response.getcode()
html_data = response.read()
header 값 추가
- 크롬등의 브라우저에서 header 값 확인
# 모바일 아이폰 접속시 header 일부 정보
user-agent:Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25
- header User-Agent를 추가해서 모바일 페이지 호출 하기
import urllib.request
URL = "http://www.daum.net"
header_info = {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25'}
request = urllib.request.Request(URL, headers=header_info)
response = urllib.request.urlopen(request)
print(response.geturl()) # https://m.daum.net/?nil_top=mobile
print(response.info()) # 응답해더 값
예외 오류 처리
urllib.error
객체 사용
import urllib.request
import urllib.error
search_addr = "http://book.daum.net/search/bookSearch.do?query="
search_word = "파이썬"
search_word_enc = urllib.parse.quote(search_word)
URL = search_addr + search_word_enc
request = urllib.request.Request(URL)
try:
response = urllib.request.urlopen(request)
status_code = response.getcode()
if status_code == 200:
print('Status Code :' + str(status_code))
html_data = response.read()
#print(response.info())
else:
print('Status Code :' + str(status_code))
except urllib.error.HTTPError as e:
print(e.code)
print(e.reason)
print(e.headers)
requests 모듈
- urllib 보다 유용하며 Rest API 를 지원
- 매개변수는 dictionary 로 구성 하며 인코딩(URL 인코딩)이 필요 없음
- http://www.python-requests.org/en/master/
- 설치(Installation)
pip install requests
기본 사용법
- requests.get(URL) : URL HTTP 요청
- response.status_code : 응답코드 200 이면 OK, 404 면 File Not Found 등등
- response.text : 응답내용을 읽어 옴
import requests
search_addr = "http://book.daum.net/search/bookSearch.do?query="
search_word = "파이썬"
URL = search_addr + search_word_enc
response = requests.get(URL)
status_code = response.status_code
html_data = response.text
print(status_code)
GET 요청
- requests.get() 에서 parmas 옵션 사용
import requests
URL = "http://book.daum.net/search/bookSearch.do"
params = {'query' : '파이썬'}
response = requests.get(URL, params=params)
status_code = response.status_code
html_data = response.text
print(response.url)
print(status_code)
POST 요청
- requests.get() 에서 data 옵션 사용
import requests
URL = "http://book.daum.net/search/bookSearch.do"
data = {'query' : '파이썬'}
response = requests.get(URL, data=data)
status_code = response.status_code
html_data = response.text
print(response.url)
print(status_code)
header 값 추가
- requests.get() 에서 headers 옵션 사용
import requests
URL = "http://book.daum.net/search/bookSearch.do"
params = {'query' : '파이썬'}
headers = {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25'}
response = requests.get(URL, headers=headers, params=params)
status_code = response.status_code
html_data = response.text
print(response.url) # m.book.daum.net 모바일 페이지가 호출 됨
print(status_code)
예외 오류 처리
import requests
URL = "http://book.daum.net/search/bookSearch.do1"
params = {'query' : '파이썬'}
headers = {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25'}
response = requests.get(URL, headers=headers, params=params)
print(dir(response))
status_code = response.status_code
if status_code == 200:
html_data = response.text
print(response.url)
print(status_code)
else:
print('Error code : ' + str(status_code))
print('Error reason : ' + str(response.reason))
HTML, XML 파싱 모듈 : BeautifulSoup
- 사이트 주소 : https://www.crummy.com/software/BeautifulSoup/
- 설치(Installation)
pip install beautifulsoup4
기본 사용법
BeautifulSoup()
- requests.get(URL)요청의 응답 데이터 파싱
import requests
from bs4 import BeautifulSoup
params = {'query' : '파이썬' }
url = 'http://book.daum.net/search/bookSearch.do'
res = requests.get(url, params=params)
html = BeautifulSoup(res.content, 'html.parser')
print(html.prettify())
태그 검색 방법
방법 1 : BeautifulSoup객체.태그명
html_body = html.title
print(html_body.prettify())
html_body_ul = html.body.ul
print(html_body_ul.prettify())
방법 2 : BeautifulSoup객체.(‘태그명’)
html_body = html('title')
print(html_body.prettify())
html_body_ul = html.body('ul')
print(html_body_ul.prettify())
방법 3 : BeautifulSoup객체.find(‘태그명’)
html_body = html.find('title')
print(html_body.prettify())
html_ul = html.find('ul')
print(html_body_ul.prettify())
일치하는 태그 숫자 제한
하나만 검색 : find(‘태그명’)
html_ul = html.find('ul')
print(html_body_ul.prettify())
모두 검색 : find_all(‘태그명’)
html_meta = html.find_all('meta')
for i in html_meta:
print(i)
숫자 제한 해서 검색 : find_all(‘태그명’, limit=숫자)
html_meta = html.find_all('meta', limit=3)
for i in html_meta:
print(i)
클래스(class) 아이디(id) 로 검색
- find_all(class_ 옵션 ) 사용
html_class = html.find_all(class_='cate_list')
for i in html_class:
print(i)
아이디(id) 로 검색
- find_all(id 옵션 ) 사용
html_id = html.find_all(id='query')
for i in html_id:
print(i)
속성으로 검색
- find_all(attrs={‘속성’ : ‘값’ ) 사용
# class
html_attr = html.find_all(attrs={'class':'cate_list'})
for i in html_attr:
print(i)
# id
html_attr = html.find_all(attrs={'id':'query'})
for i in html_attr:
print(i)
# type
html_attr = html.find_all(attrs={'type': True})
for i in html_attr:
print(i)
태그의 텍스트(내용) 만 검색
- text 속성 사용
html_ul = html.find('ul')
print(html_body_ul.text)
다음(daum) 에서 ‘파이썬’ 책 검색을 해서 책제목, 가격, 지은이, 출판일 검색
- 첫 번째 책 만 가져오기
- html에서
<form class="" method="post" name="libaryForm">
부분 이 하에서 책 리스트 검색됨 - 하위 트리에서 ul.li 가 책 리트스
- text 등 속성을 이용해서 원하는 값 가져 오기
import requests
from bs4 import BeautifulSoup
params = {'query' : '파이썬' }
url = 'http://book.daum.net/search/bookSearch.do'
res = requests.get(url, params=params)
html = BeautifulSoup(res.content, 'html.parser')
html_step1 = html.find(attrs={'name':'libaryForm'})
html_step2 = html_step1.ul.li
book_info = {}
book_title = html_step2.find(attrs={'class' : 'title'}).text
book_title = book_title.replace('\n','')
book_writer = html_step2.find(attrs={'class' : 'view'}).a.text
book_price = html_step2.find(attrs={'class' : 'prc'}).text
book_date = html_step2.find(attrs={'class' : 'date'}).text
book_price = book_price.replace('\n','')
book_price = book_price.replace('\t','')
#print(html_step2)
book_info['title'] = book_title
book_info['writer'] = book_writer
book_info['price'] = book_price
book_info['date'] = book_date
print(book_info)
- 페이지 전체 책 가져오기
import requests
from bs4 import BeautifulSoup
params = {'query' : '파이썬' }
url = 'http://book.daum.net/search/bookSearch.do'
res = requests.get(url, params=params)
html = BeautifulSoup(res.content, 'html.parser')
html_step1 = html.find(attrs={'name':'libaryForm'})
html_step2s = html_step1.ul.find_all('li')
book_infos = []
for html_step2 in html_step2s:
book_info = {}
book_title = html_step2.find(attrs={'class' : 'title'}).text
book_title = book_title.replace('\n','')
book_writer = html_step2.find(attrs={'class' : 'view'}).a.text
book_price = html_step2.find(attrs={'class' : 'prc'}).text
book_date = html_step2.find(attrs={'class' : 'date'}).text
book_price = book_price.replace('\n','')
book_price = book_price.replace('\t','')
book_info['title'] = book_title
book_info['writer'] = book_writer
book_info['price'] = book_price
book_info['date'] = book_date
book_infos.append(book_info)
for book_info in book_infos:
print(book_info)