KT 에이블스쿨 복습

[0319 복습] 웹 크롤링_동적 페이지, REST API, HTML, CCS-Selector

리니끄적 2024. 3. 19. 19:56

웹 크롤링(Web Crawling) (2)

크롤링 심화

- 파이썬 코드로 웹 서버에 데이터를 긁어오면  Was는 abuser로 판단해서 request를 차단

- request할 때 Client, header 영역에 user-agent라는 정보가 자동으로 전달됨

- user-agent: 컴퓨터가 윈도우인지, OS인지 접속한 브라우저 정보 들어있는 것!

**파이썬으로 불러오면 user-agent에 python이 들어가 있음 ! → 정상적인 request 보내지 말아야 겠다고 판단하는 것

** 이 경우 파이썬 코드로 데이터를 수집할 수 없음!

→ 회피 방법? request는 client쪽에서 만들어지는 data이기 때문에,
 파이썬에서 코딩으로 user-agent 정보를 설정해서 서버로 보내는 것!

 

 

크롤링 절차

- 기존대로 url을 가져오고, request > response 과정에서 403 에러가 발생 !

- url을 이용해서 request 했더니 403 에러 메시지를 서버에서 전달함!

- 아래 이미지는 에러일 때 response.text 결과값

- Was 입장에서 403 띄운 이유는 정확히 알 수 없음!

- 따로 설정하지 않으면 header의 user agent가 파이썬으로 들어감 → user agent확인 referer확인 

 

 

import pandas as pd
import requests

url = '링크'
# User-Agent, Referer을 헤더로 지정
headers = {'User-Agent': '개발자도구에서 복붙','Referer': '개발자도구에서 복붙',}
response = requests.get(url, headers=headers)
data = response.json()['data']
df = pd.DataFrame(data)[['가져올 열이름1','가져올 열이름2','가져올 열이름3' ]]

 

- header 사이에 콤마를 쓰는 이유: 코드를 확인할 때 어떤 코드가 바뀌었는지를 알기 위함! (콤마를 찍어놓으면 콤마 바로 앞줄만 확인하면 됨!)

- referer: url1에서 url2로 이동함! 이때도 request가 일어남, referer라는 곳은 url1로 들어가서 request를 요청

→ 현재 보고 있는 사이트 이전에 보고 있던 (url1) 사이트가 무엇인지 확인할 수 있는 방법!

 

 

 

REST API

- kakao developers 접속 후 로그인

- 내 애플리케이션 > 애플리케이션 추가하기 > KT라는 새로운 앱 생성

- 문서 > KoGPT > REST API > 도큐먼트에 친절히 사용방법 설명되어 있음!

- 쿼리 파라미터를 확인: 필수 파라미터가 2개 prompt, max_tokens

 

- 아래는 다음 문장 만들기 코드!

# 1. document : url
REST_API_KEY = 키 값 가져오기 (내 애플리케이션에서)
url = '링크'

prompt = '원자폭탄을 발명한 사람은'
params = {'prompt': prompt, 'max_tokens' : 50(가져올 개수)}
headers = {'Content-Type': 'application/json', 'Authorization': f'KakaoAK {REST_API_KEY}'}

# 2. request(url, headers, params) > response(data): json(str)
response = requests.post(url, json.dumps(params), headers=headers)
response

# 3. json(str) : text
response.json()['generations'][0]['text'].strip()

- jump.dumps: 파라미터에 한글이 있는 경우 인코딩하는 것

 

 

직방 매물 데이터 실습_매물 아이디로 매물 정보 가져오기

- 사이트 접속 > 원룸 > 망원동 검색 > 두번 검색하면 망원동 검색한 내용이 브라우저에 저장됨!

→ 개발자 도구에서 네트워크가 새로 뜨지 않음

- headers확인:  payload 탭 확인하면 한글 깨진 내용 알 수 있음

https://meyerweb.com/eric/tools/dencoder/

 

URL Decoder/Encoder

 

meyerweb.com

→ 영어로 되어있는 것 한글로 디코딩

 

- geohash: wydjx 를 설정해줘서, response에 x,y에  위도 경도값이 나타남!
(특정 위치가 아니라 매물정보가 모인 영역 전체를 설명할 때 → geohash로 지리정보 시스템에서 사용함!)

 

#%%~부분은 모듈 저장
%%writefile zigbang.py  
import pandas as pd     # 모듈에 저장할 때는 새로 불러와야 함
import requests 
import geohash2
def oneroom(addr):
    url = f'{addr}포함된 링크'
    response = requests.get(url)
    data = response.json()['items'][0]   #ㅇㅇ동에 대한 결과값이 여러개일 수도 있기 때문에 리스트로 출력됨, 가장 먼저 나오는 데이터를 가져오기 위해 인덱싱 [0] 해줌
    lat, lng = data['lat'], data['lng']
    
    
# precision : 영역 범위 : 커질수록 영역이 작아짐
# 다른 동에 대한 검색도 파이썬에서 가능할 수 있도록 하기 위해 geohash값을 복붙이 아니라, 
# geohash 패키지를 사용해서 값을 가져오는 것!

    geohash = geohash2.encode(lat, lng, precision=5)
    
    url = f'{geohash}포함된 링크'
    response = requests.get(url)
    items = response.json()['items']
    ids = [item['itemId'] for item in items]
    
    url = '리스트 링크'
    params = {'domain': 'zigbang', 'item_ids': ids}
    response = requests.post(url, params)
    items = response.json()['items']
    df = pd.DataFrame(items)
    df = df[df['address1'].str.contains(addr)].reset_index(drop=True)
    columns = ['불러올 열 이름1', '불러올 열 이름2', '불러올 열 이름3']
    return df[columns]
    
    %ls zigbang.py   # 모듈 저장 확인
 

HTML

HTML

- HTML: 웹 문서를 작성하는 마크업 언어

 

HTML 구성요소

- Document: 한 페이지를 나타내는 단위

- Element: 하나의 레이아웃을 나타내는 단위(시작태그, 끝태그, 텍스트로 구성)

**element는 계층적 구조를 가지고 있음, 시작태그와 끝태그의 결합

- Tag: 엘리먼트의 종류를 정의: 시작태그(속성값), 끝태그

- Attribute: 시작태그에서 태그의 특정 기능을 하는 값

 - id: 웹 페이지에서 유일한 값

 - class: 동일한 여러개의 값 사용 가능 : element를 그루핑할 때 사용

 - attr: id와 class를 제외한 나머지 속성들

- Text: 시작태그와 끝태그 사이에 있는 문자열

 

 

HTML 구조

- DOCTYPE: 문서의 종류를 선언하는 태그

- html

 - head

   - meta: 웹페이지에 대한 정보를 넣음

   - title: 웹페이지의 제목 정보를 넣음

- body: 화면을 구성하는 엘리먼트가 옴

 

<!-- HTML 웹문서의 기본적인 구조 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
</html>

 

HTML 태그

- html에서 문자를 나타내는 태그

 

head

- title을 나타낼 때 사용, Head는 총 6가지 종류의 태그가 있음, 숫자가 커질수록 문자의 크기가 줄어듦

%%html     
<h1>Data1</h1> #제목을 사용할 때 h태그 사용 h1 > h3 문자 크기 작아짐

 

p

- 한 줄의 문자열을 출력하기 위한 태그

%%html
<p>data1</p>
<p>data2</p>

 

span

- 한 블럭의 문자열을 표현하기 위한 태그

%%html
<span>data1</span>
<span>data2</span>

 

 

문자 이외의 HTML 태그

div

- 레이아웃을 나타내는 태그

%%html
<div>
    <p>data1</p>
    <p>data2</p>
</div>
<div>data3</div>
<div>data3</div>

 

ul, li

- 리스트를 나타내는 태그

%%html
<ul>
    <li>data1</li>
    <li>data2</li>
</ul>

 

a

- 링크를 나타내는 태그, href 속성에 url을 넣음, url과 상대경로를 모두 사용 가능, target='blank' 옵션

# 타겟이 없으면 -> 현재 페이지가 KT 페이지로 바뀜, 기존 페이지는 사라짐!
# 타겟을 넣으면 기존 페이지가 열려있는 상태로 새로 KT 페이지가 뜸!
%%html
<a href = '링크' target='blank'>'문자열'</a>

 

image

- 이미지를 나타내는 태그

# 텍스트가 없으면 엘리먼트에 끝태그가 없어도 됨
%%html
<img src='이미지 링크' alt='kt'>

CSS Selector

 

Element Selector

- 엘리먼트를 이용해 선택할 때 사용

- css selector로 div를 사용하면 가장 위에 있는 dss1 이 선택됨!

 

ID Selector

- 아이디를 이용해 선택할 때 사용

- 아이디를 셀렉할 때는 #(아이디 이름)으로 선택, css selector #ds2를 사용하면 dds2가 선택

- 여러개를 셀렉할 때는 ,로 구분

- css selector로 #ds2, #ds3를 사용하면 dds2와 dds3가 선택

 

Class Selector

- 클래스를 이용해 선택할 때 사용, 클래스를 셀렉할 때는 .(클래스 이름)으로 선택

- 아이디를 셀렉할 때는 #(아이디 이름)으로 선택, css selector #ds2를 사용하면 dds2가 선택

 

Not Selector

- 셀렉터로 엘리먼트를 하나만 제거하고 싶을 때 사용

- not을 사용해 셀렉할 때에는 :not(선택에서 제거하고 싶은 셀렉터)으로 선택

- 아래에서 .ds:not(.ds2)로 셀렉하면 class가 ds2인 클래스를 제외하고 나머지 ds1, ds3, ds4, ds5가 선택

 

nth-child Selector

- 엘리먼트로 감싸져있는 n번째 엘리먼트가 설정한 셀렉터와 일치하면 선택

- .ds:nth-child(3), .ds:nth-child(4)로 설정하면 ds4, ds5가 선택

- nth-child의 ()안의 숫자는 가장 첫번째가 0이 아니라 1로 시작

 

 

모든 하위 depth(공백) Selector

- 공백문자로 하위 엘리먼트를 셀렉트했을 때, 모든 하위 엘리먼트를 선택

- .contants h1를 선택하면 inner_1, inner_2가 선택

 

바로 아래 depth(>) Selector

- > 문자로 하위 엘리먼트를 셀렉트 했을때, 바로 아래 엘리먼트를 선택

- .contants > h1를 선택하면 inner_1이 선택

 

 

네이버 연관 검색어 수집 실습

import pandas as pd
import requests
from bs4 import BeautifulSoup  #css-selector로 엘리먼트 선택 가능

query = '검색어'
url = f'https://search.naver.com/search.naver?query={query}'

# request(URL) > response:str(html)
response = requests.get(url)

#str(html) > bs object
dom = BeautifulSoup(response.text, 'html.parser')

# bs object > .select(css-selector), select_one(css-selector) > str(text)
selector = '개발자도구에서 copy한 css-selector'
elements = dom.select(selector)
len(elements), elements[0]
keywords = [element.text.strip() for element in elements]