23.02.08 Day08

오윤범·2023년 2월 8일
0

웹크롤링(OpenAPI) / BeautifulSoup(v4)

위키독스(개발시 참조)

https://wikidocs.net/

웹 크롤링

from urllib.request import urlopen, Request #라이브러리 불러오기
#도시별 날씨 검색 함수
def get_weather(city):
    #기상청 홈페이지 도시별 날씨
    url = 'https://www.weather.go.kr/w/obs-climate/land/city-obs.do'
    page=urlopen(url=url)
    text=page.read().decode('utf-8')
    text = text[text.find(f'>{city}</a'):]#>부산</a> html 코드 있는부분 찾아옴
    # 기온 가져오기(기상청 홈페이지 7번째 칸)
    for i in range(7): #기상청 홈페이지의 7번째칸 가져오고
        text=text[text.find('<td>')+1:]
    start=3
    end=text.find('</td>') 
    current_temp=text[start:end]
    print(f'{city}의 현재 기온은 {current_temp}˚C 입니다.')
    # 습도 가져오기(기상청 홈페이지 10번째 칸)
    for i in range(3): #7번째 이후 3번째 뒤 10번째 칸 가져오게됨
        text=text[text.find('<td>')+1:]
    start=3 #html 코드 td> 뒷부분에 실제 내용부터 가져오겠다
    end=text.find('</td>') 
    current_humid=text[start:end]
    print(f'{city}의 현재 기온은 {current_humid}% 입니다.')
get_weather('부산')
----------------------출력-------------------------
----------------------출력-------------------------
부산의 현재 기온은 7.1˚C 입니다.
부산의 현재 기온은 41% 입니다.
import requests
from urllib.parse import quote,unquote,urlencode # 한글을 URL encode로 변환하기위한 함수 ex)롯데
import json
import ssl
def getDataPortalSearch(stationName,type):
    api_url="https://apis.data.go.kr/6260000/BusanTblBusinfoeqStusService/getTblBusinfoeqStusInfo"
    queryString="?"+ urlencode( # 각 주소는 모두 대소문자를 구분하므로 URL 과 동일하게 작성해야함
        {
            'servicekey':'te5/ahqxnGW00Gw1jJ92lJYLwkOvVrP9DZdSdffoIyZB8Jb+zHMrpMxU0VQOlxdvK+RzzcNsLTr+LaoLfFzUQg==',
            'pageNo':'1',
            'numOfRows':'10',
            'resultType': type,
            'stationLoc':stationName
        }
    )
    total_url=api_url+queryString #전체주소
    response=requests.get(total_url, verify=False)#total_url을 request로 받아오고
    return response.text #text형태로 반환
try:
    result=getDataPortalSearch('백화점','json')
    json_data=json.loads(result)
    station_data = json_data['getTblBusinfoeqStusInfo']['body']['items']['item']
    for item in station_data:
        print(item)
except Exception as e:
    print('찾는 데이터가 없습니다')
----------------------출력-------------------------
----------------------출력-------------------------
{'stationNum': '09283', 'stationLoc': '롯데백화점센텀시티점', 'lat': '35.16967324', 'lng': '129.1317843', 'addr': '해운대구 우동 1496', 'insYear': '', 'dataDay': '2023-02-03'}
{'stationNum': '09336', 'stationLoc': '롯데백화점센텀시티점', 'lat': '35.16997953', 'lng': '129.1320357', 'addr': '해운대구 우동 1498', 'insYear': '', 'dataDay': '2023-02-03'}
{'stationNum': '05718', 'stationLoc': '서면역.롯데호텔백화점', 'lat': '35.15776525', 'lng': '129.0566948', 'addr': '부산진구 부전동 576-1', 'insYear': '', 'dataDay': '2023-02-03'}
{'stationNum': '05719', 'stationLoc': '서면역.롯데호텔백화점', 'lat': '35.15748116', 'lng': '129.0561774', 'addr': '부산진구 부전동 576-1', 'insYear': '', 'dataDay': '2023-02-03'}
{'stationNum': '06030', 'stationLoc': '롯데백화점동래점.명륜역', 'lat': '35.21276314', 'lng': '129.0781263', 'addr': '동래구 온천1동 474-25', 'insYear': '', 'dataDay': '2023-02-03'}
{'stationNum': '06046', 'stationLoc': '롯데백화점동래점', 'lat': '35.2101971', 'lng': '129.0778307', 'addr': '동래구 온천2동 503-46', 'insYear': '', 'dataDay': '2023-02-03'}

--> '백화점'이 들어간 부산 버스정류소를 공공데이터포털에서 크롤링 해와서 json 형태로 출력
--> total_url 에 api_url(service key 전까지) 과 queryString(service key부터 내가 찾고자하는 정류장까지 )

문제점

  • https를 일반 request로 부르면 SSL 오류 발생
  • 해결하려면 외부모듈 requests를 사용, verify=False 옵션을 지정
  • OpenAPI 웹크롤링 + Folium

import folium
if len(station_data)>0: # 정류소 중 제일 첫번째 인덱스 정류소 위경도를 중심으로
    center_lat = station_data[0]['lat'] #위도
    center_lng = station_data[0]['lng'] #경도 
m = folium.Map(location=[center_lat,center_lng],zoom_start=12)
# 전체 정류소 위치값 마커 표시
for item in station_data:#stationdata : 정류소 위치값들을 json형태로 뽑아온 변수
    stop_str = '<h4>'+item['stationLoc']+'</h4>'
    stop_str+=item['stationNum']+'<br>'
    stop_str+=item['addr'] #popup에 정류소명/정류장번호/주소 출력하기 위함
    iframe=folium.IFrame(stop_str)
    popup=folium.Popup(iframe,min_width=200,max_width=200)
    folium.Marker(location=[item['lat'],item['lng']],popup=popup,icon=folium.Icon(icon='pushpin')).add_to(m)
    #부산이면서 '롯데백화점'이 포함된 정류장의 위/경도를 찾으면서 Mark 찍는다
m
----------------------출력-------------------------
----------------------출력-------------------------

문제점

  • 딕셔너리 구조와 문자열 포맷팅 f'{}' 호환 안됨
  • 구식방법인 문자열 결합방식으로 해야함

BeautifulSoup(version 4)

  • 네이버 지식IN 검색 자료 크롤링(검색 시 나오는 파란 글씨 a 태그들 가져오기)
    #!pip install beautifulsoup4 <- 뷰티풀솝 install
    from bs4 import BeautifulSoup
    import requests
    url = 'https://kin.naver.com/search/list.naver?query=bmw320d'#지식인에 bmw320d 질문
    response=requests.get(url)
    if response.status_code==200:#정상적으로 실행중이라면
       html=response.text
       soup=BeautifulSoup(html,'html.parser')
       ul=soup.select_one('ul.basic1')#ul태그 중 basic1 클래스 가진 애들 뽑아옴
       titles=ul.select('li>dl>dt>a')#지식인에bmw320d 검색했을때 나오는 파란글씨 제목들의 경로가 li>dl>dt>a 임
       for title in titles:
           print(title.get_text())
    else:
       print(f'Error : {response.status_code}')
    ----------------------출력-------------------------
    ----------------------출력-------------------------
    쏘렌토mq4 디젤과 bmw320d 중
    BMW 320d 320i 중 근본은?
    Bmw 320D f30 부품명칭 알수
    BMW 320D 수입 타이어 교체
    bmw 320D 투어링 f30 엔진오일 문의
    BMW 320D F30 2015년 중고 매입금액
    bmw320d 타이어
    19년식 bmw 320d msp 21년식 k5 시그니처
    bmw320d 블랙박스 문의
    BMW 320D 13년식 전체랩핑... 
    --> 네이버 지식IN 에 bmw320d 검색 시 보여지는 제목들 가져옴

0개의 댓글