웹 크롤링에 대한 이해
웹 크롤링
: 웹 스크래핑(Web Scraping)이라고도 하며 컴퓨터 소프트웨어 기술로 각종 웹 사이트들에서 원하는 정보를 추출하는 것을 의미
웹 크롤러
: 인터넷에 있는 웹 페이지를 방문해서 자료를 수집하는 일을 하는 프로그램
크롤링을 위한 선행학습
- 웹(web)의 개념 (request, response 등)
- HTML, CSS, Javascript
- 파이썬 기초
웹 크롤링의 기법
- HTML 페이지를 가져와서 HTML/CSS 등을 파싱하고, 필요한 데이터만 추출하는 기법
- Open API(Rest API)를 제공하는 서비스에 Open AI를 호출해서, 받은 데이터 중 필요한 데이터만 추출하는 기법
- 브라우저를 프로그래밍으로 조작해서 필요한 데이터만 추출하는 기법
웹 크롤링의 예시
검색엔진(네이버, 다음, 구글)
- 구글에서 크롤링 봇을 검색해보자.
쇼핑몰
- 경쟁사의 제품 정보들을 크롤링하여 사용(법적 다툼 발생)
API (Application Programming Interface) 외의 정보
- API에서 제공하는 정보 외에 필요한 정보들을 크롤링해서 사용
크롤링이 합법인가 불법인가
모든 크롤링이 불법은 아니다.
- 사이트 운영자의 의사에 상관없이 무단으로 크롤링하는 것은 불법
robots.txt(검색을 허용할것인가 허용하지 않을 것인가의 정보등이 담겨있다.)에서 크롤링 여부 확인가능
https://searchadvisor.naver.com/guide/seo-basic-robots
- 검색엔진 크롤링 봇들이 해당 파일을 열어본 뒤 수집 유무를 결정
검색 허용 여부 예시
네이버 로봇은 검색 허용, 야후 로봇은 검색 불가로 하고 싶다면 robots.txt에서 아래처럼 수정
- User-agent: 네이버
- Allow: /
- User-agent: 야후
- Disallow:/
4차 산업 혁명 시대에 데이터는 곧 ‘돈’
- 데이터의 가치가 올라감에 따라 크롤링이 범죄에 활용되는 경우가 많이 발생
크롤링 분쟁이 많다.
- 후발 주자가 선행주자를 빨리 따라잡기 위해 불법으로 데이터를 가져오는 행위들
예) 잡코리아 VS 사람인, 야놀자 VS 여기 어때
웹 크롤링 기초
HTTP는 요청과 응답으로 이루어져 있음
- 사용자가 원하는 정보를 요청하게 되면, 서버는 해당 요청을 확인 후 적절한 응답을 해주는 구조
HTTP 요청과 응답
1) 요청일 때
- 사용자가 서버에 요청을 할 때 크게 4개로 구분하여 요청할 수 있음
- URL로 요청하여 요청할 때는 메서드로 변경하여 기능을 구분
메소드 | 설명 |
GET | 정보를 가져오기 위해 요청 |
POST | 새로운 정보를 보내기 위해 요청 |
PUT | 수정할 정보를 보내기 위해 요청 |
DELETE | 정보를 지우기 위해 요청 |
2) 응답일 때
- 서버가 사용자에게 요청에 대한 응답을 보낼 때 크게 5개의 경우가 있음
- 응답 코드로 요청의 진행 사항과 서버의 상태를 예측가능
응답코드 | 설명 |
1XX | 요청을 받았고, 작업 진행중 |
2XX | 사용자의 요청이 성공적으로 수행 됨 |
3XX | 요청은 완료 되었으나, 리다이렉션이 필요 |
4XX | 사용자의 요청이 잘못됨 |
5XX | 서버의 오류를 응답 |
파이썬에서의 크롤링
requests 모듈을 활용한 크롤링 환경
- !pip install requests 명령어로 설치
- Anaconda를 설치했다면 기본으로 함께 설치가 되어있음
- import requests로 모듈 호출 후 사용
크롤링에 항상 쓰이는 디폴트 코드
#크롤링 디폴트
import requests
URL = "https://www.*****.com" #URL 객체 생성
response = requests.get(URL) #response 객체 생성 requests모듈의 get메서드로 URL을 받음
print(response.status_code) #상태코드 호출, URL을 잘 받았다면 200 출력
print(response.text) #받은 정보를 텍스트로 출력
특정 사이트의 검색 결과를 가져오는 예시
#검색 결과를 가져오기
#포털에서 "파이썬"이라는 검색어의 결과 정보 가져오기
#params라는 객체에 검색결과를 담으려면 해당 사이트가
#어떤 구조로 검색결과를 호출하는지 알수 있어야 매개변수를 작성할 수 있다. 고정된 답이 있는게 아님
#URL = "https://search.*****.com/search.*****"
import requests
URL = "https://search.*****.com/search.*****"
params = {'query':'파이썬'} #
response = requests.get(URL, params) #requests모듈로 URL과 params를 적용, 정보를 가져온 뒤 response 객체에 담음
print(response.text)
urllib 모듈을 활용한 크롤링 환경
- 파이썬의 표준 모듈로써 URL을 다루기 위한 모듈 패키지
- 설치가 필요하지 않고, import urllib로 활용
- requests 모듈과 마찬가지로 URL과 관련된 여러가지 기능들을 제공
- 공식문서: https://docs.python.org/3/library/urllib.html
- request : URL을 열고 읽는 모듈(HTTP 요청)
- error : request 모듈에서 발생하는 에러들을 포함하는 모듈
- parse : URL을 파싱(해석)하는 모듈(URL 해석 및 조작)
- robotparser: robots.txt 파일을 파싱하는 모듈
urllib.request.Request()
해당 URL 요청 객체 생성
HTTPRequest 객체 반환
여러가지 함수들을 제공: 전체 URL, 프로토콜, 호스트 등
#urllib 모듈 사용 urllib.request.Request()
import urllib
URL = ""
response = urllib.request.Request(URL)
print(response) #객체에 대한 주소지
print(response.full_url) #객체에 대한 풀 URL
print(response.type) #객체에 대한 타입
print(response.host) #객체에 대한 호스트(서버주소)
urllib.request.urlopen()
해당 URL을 열기
응답 데이터는 바이트 형식의 HTTPResponse 객체를 반환한다.
request 객체 또는 URL을 직접 넣어도 가능
#urllib 모듈의 urlopen는 request 객체 또는 URL을 직접 넣어도 가능
import urllib
URL = ""
request = urllib.request.Request(URL)
response1 = urllib.request.urlopen(request)#객체를 넣은 경우
response2 = urllib.request.urlopen(URL)#URL을 넣은 경우
print(response1)
print(response2)
print(response1.geturl())
print(response2.geturl())
print(response1.getheaders())#헤더 정보 출력
print(response2.getheaders())
urllib.request.read()
urlopen으로 연 객체를 읽고, 인자로 전달하는 숫자만큼 데이터를 읽음
- read()로 읽으면 바이트형식의 데이터를 반환한다.
- 그러므로 decode()를 해줘야 한다.
urllib.request.readlines()
홈페이지 데이터를 줄 단위로 읽어 리스트에 반환
urllib.request.decode()
바이트 형식의 데이터를 원하는 형식으로 변환
- 기본값은 utf-8 사용
#urllib 모듈 사용 urllib.request.urlopen()
import urllib
URL = ""
response_urllib = urllib.request.urlopen(URL)
byte_data = response_urllib.read()#바이트 단위로 읽어와줘
text_data = byte_data.decode("utf-8")#바이트 데이터를 utf-8로 디코딩 해줘야 한다
print(text_data)
#urllib.request.read()
import urllib
URL = ""
response_urllib = urllib.request.urlopen(URL)
byte_data = response_urllib.read(500)#500번째 글자까지만 읽어라, 바이트코드로 나옴
text_data = byte_data.decode()#utf-8을 안넣어도 기본으로 utf-8이 적용된다.
print(text_data)
urllib.request.urlretrive()
- 웹 상에서 이미지를 다운로드
#urllib.request.urlretrive()
import urllib
img_src = "https://newsimg.hankookilbo.com/cms/articlerelease/2017/11/13/201711131465792477_1.jpg"
new_name = 'ryan.jpg' #저장할 이름 지정
urllib.request.urlretrieve(img_src, new_name) #urlretrieve(가져올 이미지 주소, 저장할 이름)
urllib.parse()
- 공식문서: https://docs.python.org/ko/3/library/urllib.parse.html
urllib.parse — URL을 구성 요소로 구문 분석 — Python 3.9.7 문서
urllib.parse — URL을 구성 요소로 구문 분석 소스 코드: Lib/urllib/parse.py 이 모듈은 URL(Uniform Resource Locator) 문자열을 구성 요소(주소 지정 체계, 네트워크 위치, 경로 등)로 분리하고, 구성 요소를 다시
docs.python.org
- url을 파싱하여 분석하기 위한 모듈
url은 인터넷 공간에 존재하는 데이터들을 가리키기 위한 절대 주소
url 형식: 프로토콜://아이디:비밀번호@호스트:포트번호/하위경로?파라미터#색인(프래그먼트)
url 참고: https://ko.wikipedia.org/wiki/URL
예1) http://www.somehost.com/a.gif
- IP 혹은 Domain name 정보가 필요한 형태 ( www.somehost.com에 있는 a.gif를 가리키고 있음 )
예2) ftp://id:pass@192.168.1.234/a.gif
- IP 혹은 Domain name 정보가 필요한 형태 (192.168.1.234에 있는 a.gif를 가리키고 있음 )
예3) mailto:somebody@mail.somehost.com
- IP정보가 필요없는 프로토콜 ( mailto 프로토콜은 단지 메일을 받는 사람의 주소를 나타냄 )
urllib.parse.urlparse()
- url을 6개로 분리하여 반환
#urllib.parse.urlparse()
import urllib
parse = urllib.parse.urlparse('http://thisishomepage.com/home;a=1?b=2#c')#샘플 URL
print(parse)#총 6개로 url를 분리하여 반환한다.
print()
print(parse.scheme)#스키마 출력
print(parse.netloc)#도메인 출력
print(parse.path)#패스 출력
print()
for i in range(len(parse)):#urlparse로 분리된 요소를 모두 출력
print(parse[i])
urllib.parse.urlsplit()
- 파라미터를 분할하지 않음, 그래서 5개로 나눠짐
urllib.parse.urlunparse()/urllib.parse.urlunsplit()
- 분리된 url을 다시 합침
- 튜플로 반환되기 때문에 리스트로 변경하여 활용
#urllib.parse.urlparse()
import urllib
parse = urllib.parse.urlsplit('http://thisishomepage.com/home;a=1?b=2#c')
#파라미터를 분할하지 않음, 그래서 5개로 나눠짐
for i in range(len(parse)):
print(parse[i])
print(type(parse))
print(parse.query)
print()
parse = list(parse)#리스트로 변경뒤 parse
parse[1] = 'cafe.daum.net'#두번째 요소를 지정한 요소로 변경
parse = urllib.parse.urlunsplit(parse)#분할된 요소를 다시 합치고 문자열로 출력
print(parse)
print(type(parse))
print()
urllib.parse.parse_qs(), parse_qsl()
- 쿼리(query)를 파싱해서 사전(sq) 및 리스트(qsl) 로 반환
- 쿼리(query)를 변경하여 요청할 때 활용
import urllib
parse = urllib.parse.urlparse('https://www.nnnnnnn.com?a=1&b=2&c=3&d=4')
print(parse)
print(parse.query)
print(type(parse.query))
#qs()
qs = urllib.parse.parse_qs(parse.query)#쿼리를 사전형태로 만들어줌
print(qs)
print(type(qs))
#qul()
qsl = urllib.parse.parse_qsl(parse.query)#쿼리를 리스트형태로 만들어줌
print(qsl)
print(type(qsl))
ParseResult(scheme='https', netloc='www.nnnnnnn.com', path='', params='', query='a=1&b=2&c=3&d=4', fragment='')
a=1&b=2&c=3&d=4 #쿼리만 출력
<class 'str'> #쿼리 타입 조회결과
{'a': ['1'], 'b': ['2'], 'c': ['3'], 'd': ['4']}
<class 'dict'>
[('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')]
<class 'list'>
urllib.parse.urljoin(a,b)
- a와 b url을 합쳐주는 기능
- ‘/’ 에 따라 URL 주소가 달라지는 것 주의!!
import urllib.parse
url = "https://www.naver.com/a/b"
print(urllib.parse.urljoin(url,'c'))#가장 하위 패스가 수정됨
print(urllib.parse.urljoin(url,'/c'))#전체 패스가 수정됨
import urllib.parse
url = "https://www.naver.com/a/b/"#주소 뒤에 / 로 끝나면
print(urllib.parse.urljoin(url,'c')) #c가 패스 마지막에 추가됨
print(urllib.parse.urljoin(url,'/c'))#전체 패스가 수정됨
# 페이지 이동에 사용할 수도 있음
#‘/’ 에 따라 URL 주소가 달라지는 것 주의!!
urllib.parse.quote() / unquote()
- 아스키 코드가 아닌 문자들을 퍼센트 인코딩으로 변환
- URL에 한글이 섞이면 오류 발생
import urllib
#URL에 한글이 섞여있으면 에러가 난다.
url = "https://search.naver.com/search.naver?query=파이썬"
response_urllib = urllib.request.urlopen(url)
byte_data = response_urllib.read()
text_data = byte_data.decode()
#여기 오지도 못함
print(urllib.parse.queat('파이썬'))
print(urllib.parse.quote('파이썬'))
print(urllib.parse.unquote('%ED%8C%8C%EC%9D%B4%EC%8D%AC'))
%ED%8C%8C%EC%9D%B4%EC%8D%AC
파이썬
홈페이지를 로컬에 파일로 저장
파이썬의 파일 입출력 함수 활용
-- open : 파일 객체 생성
-- write : 생성한 파일에 데이터 입력
-- close: 파일 객체 종료
홈페이지를 모바일로 저장하려면 헤더(headers)를 추가해서 모바일 페이지로 저장
request 함수에 헤더(headers) 인자에 값을 전달
(*호출할 때 전달하는 값을 인자, 받는 걸 파라미터)
#pc 버전
import urllib
request = urllib.request.Request("https://www.naver.com")
data = urllib.request.urlopen(request).read()
#리퀘스트 모듈에서 request로 받은 유알엘 정보를 읽어와서 data에 담음
f = open("pc.html","wb")
f.write(data)
f.close()
#mobile 버전
import urllib
header = {"User-Agent":"Mozilla/5.0 (iphone)"}#헤더에 접속정보 전달. 나 아이폰이야~
request = urllib.request.Request("https://www.naver.com", headers = header)#어 아이폰으로 접속했구나.
data = urllib.request.urlopen(request).read()
f = open("mo.html","wb")#mo.thml로 저장, wb: 바이너리 버전으로
f.write(data)
f.close()
파라미터를 변경해 여러 정보 가져오기
여러가지 검색어의 naver 검색 결과 출력
- 한글을 인코딩
- 리스트를 통하여 검색어를 저장
import urllib
query_list = ['파이썬', 'python'] #-- 리스트를 통하여 검색어를 저장
URL = "https://search.naver.com/search.naver?query="
for i in query_list:
new_URL = URL + urllib.parse.quote(i) #quote로 한글을 인코딩하고 리스트 검색어를 주소와 합침
response_urllib = urllib.request.urlopen(new_URL)
byte_data = response_urllib.read()
text_data = byte_data.decode()#utf-8로 디코딩, ()안에 뭐 안넣으면 기본이 utf-8이라구
print(text_data)
'AI > StudyNote' 카테고리의 다른 글
Python #웹 제어 #selenium 모듈 (0) | 2021.09.10 |
---|---|
Python #웹크롤링 #BeautifulSoup 모듈 (0) | 2021.09.10 |
Python #예외처리 (0) | 2021.09.08 |
Python #오버로딩 #연산자 오버로딩 #상속 #오버라이딩 #다형성 (0) | 2021.09.07 |
Python #클래스 변수와 인스턴스 변수 #정적 메소드 #생성자 #소멸자 (0) | 2021.09.07 |