Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 머신러닝
- 파이썬 이미지 처리
- YouTube
- ASAC5기
- JSON
- 데이터분석
- pandas
- 파이썬
- join
- CCP자격증
- SQL
- Python
- ML
- 뷰티 광고
- text summarization
- Shorts
- ASAC
- Machine learning
- 크롤링
- Crawling
- DFS
- 프로그래머스
- selenium
- BFS
- 백준
- cnn optuna
- deep learning
- sql eda
- EDA
- ASAC14일차
Archives
- Today
- Total
낼름낼름 동동이
[ASAC 16일차] Crawling 본문
4월 12일의 기록
오전에는 실업 급여 인정을 위해 수업을 가지 못하였다. 오전에 놓쳤던 부분은 점심 시간에 따로 공부를 하면서 실습을 따라해보았다. 오히려 혼자서 블로그에 정리해가면서 실습 내용을 따라가니 빠른 시간에 고효율을? 낼 수 있는 것 같아서 좋았다! 다음주부터는 수업 진도가 살짝 느리니까… 코테 문제나 자격증 공부를 좀 해두고 점심시간에 혼자 정리해봐야겠다. 물론 너무 어려우면 수업을 들어야겠지만..
1. Crawling
크롤링의 목적:
- 기본적으로 명확하게 데이터를 주고 받으려면 API를 활용해야 한다.
- 단, 하루 할당량, 주간 할당량이 제한되어 있고 일반적인 사이트에서는 API를 제공하지 않는 곳도 존재함.
기능 체크 방법
- 숨겨져 있는 주소는 어떻게 찾지? ⇒ 브라우저 개발도구
- 일반적인 html에서 정보를 찾는 방법은? ⇒ 페이지의 정확한 주소 + 태그 체크
- 전체 페이지를 돌리는 방법은? (롤링 방법)
# ---> 웹 브라우저에서 개발자도구 & 네트워크
# 우리가 찾으려는 페이지의 정확한 주소!!!!!
# + 되는지 안되는지 체크
# : Dart는 주소만 찾아내면 코드로 접속해도 금지는 안 당함!!
# ---> 찾은 주소의 주요한 인자를 보면
# <https://dart.fss.or.kr/dsac001/mainAll.do?selectDate=2024.04.08&sort=&series=&mdayCnt=0¤tPage=9>
# <https://dart.fss.or.kr/dsac001/mainAll.do>? : BaseURL
# selectDate : 요청하려는 날짜 YYYY.MM.DD
# currentPage : 내가 그 날의 어느 페이지 정보를 접근하려는지
실습 1
1. 필요한 패키지 import
# 필요한 패키지들
# 1) 통신 : urllib, requests etc
import requests
# 2) html --> tag중심의 언어
# html의 테그를 중심으로 정보 추출 : BeautifulSoup
from bs4 import BeautifulSoup
# 3) 데이터 처리
import pandas as pd
# 4) +++ 데이터 처리를 하는데 있어서.....
# ===> 정규식, 시간에 대한 지연처리(일반 사이트)->실험
import re
import time
2. 요청하려는 URL 세팅
# Step1) 내가 요청하고자 하는 URL을 완성해야 함!!!!!
# --> API는 문서보고 하면 되는데,,
# --> 일반 사이트는 내가 열심히 필요한 정보를 요청하는 url탐색!!
# 예시 날짜 : 2024.03.05
# --> 698건의 공시 정보를 요청을 하려고 함...
# --> 1페이지가 아니라 여러 페이지를 롤링해야 함...
date = "2024.03.05" # <--- selectDate=
page = "1" # <--- currentPage=
url = f"<https://dart.fss.or.kr/dsac001/mainAll.do?selectDate={date}&sort=&series=&mdayCnt=0¤tPage={page}>"
url
3. request 패키지로 요청
# Step2) requests 패키지로 요청
res = requests.get(url)
res
# 참고) requests 패키지로 받은 정보를 열어보는 방식 2가지...
# 1) res.text : 알아서 자기가 인코딩/디코딩을 처리를 함!!!
# 특별하게 신경쓸 부분이 거의 없음!!!!
# 2) res.content : 이미지, 동영상 --> 바이트값으로 들어옴...
# --> 일반적으로 특수한(이미지, 동영상) .text를 주로 활용
4. Tag에 접근하기 위해 BeautifulSoup패키지 사용
# 위의 요청한 웨사이트의 내용을 필요한 정보에 쉽게
# Tag중심으로 접근하기 위해서는 BeautifulSoup패키지로 변환!!!!
# ==> 모든 텍스트로 필요 정보를 접근하는게 아니라
# Tag중심으로 정보를 접근하자!!!
soup = BeautifulSoup(res.text, "html.parser")
soup
5. Tag + Tag의 속성값 사용
# 방법1) dict로 상세 속성을 지정하는 방식!!!!!
len(soup.find_all("div"))
soup.find_all("div", {"class":"headerTop"})
# 방법2) tag중에서 bs4가 이미 미리 파라미터로 만들어둔 것!!!
# ex) class 파라미터의 경우에는 : class_
soup.find_all("div",class_="headerTop" )
실습 2) 공시 자료의 수를 체크
# Q) 전체 그 날의 공시 자료의 수를 체크!!!!
# --> 내가 몇 개의 페이지를 돌려야 할지!!!
# (그냥 1페이지부터 쭉 돌리면서 ,체크를 하는 방법도 있음.)
temp = soup.find_all("div", {"class","pageInfo"})[0].text
# 총 몇 페이지인지 확인
# + 참고 정규식)
# --> 정규식에서 특정 문자 패턴을 찾는 :
# re.findall(패턴,어디서)
# --> 정규식에서 특정 문자 패턴을 변경/제거 :
# re.sub(패터,무엇으로변경, 어디서)
1. 찾을 패턴 : 숫자 + 건
# Try1) 찾을 패턴 : 숫자들+건
temp = re.findall(r"\\d+건", temp)[0] # 698건
temp = re.sub(r"건","", temp) # 698 ---> 숫자...
# 만약, 페이지 계산을 하겠다하면 1페이지 최대 100건이다.
# 그러면 100으로 나눠서 몫을 올림!!
# 100건 --> 1페이지 : 100/100 =1
# 102건 --> 2페이지 : 102/100 = 1.XXX
# ===> 몫에 대한 올림
if int(temp) % 100 == 0:
tot_page = int(temp) // 100
else:
tot_page = int(temp) // 100 + 1
# 참고) 파이썬의 올림 연산자/함수를 사용해도 된다.
1. 페이지 정보 추출
# Try2) 이번에는 아래 정보에서 /???] --> ???페이지 정보추출
temp = soup.find_all("div", {"class","pageInfo"})[0].text
temp # ex: [1/7] [총 698건]
# 정규식에 패턴에 구별 : 정규식의 미리 지정된 문자
# or 특수문자
# [ ] : 정규식에서 묶음
# [ ]위의 문자열에서는 정규식의 []가 아니라 그냥 단순 괄호[]
# ==> 파이썬 문자열에서 단순 문자 그자체로 인식해줘 \\
temp = re.findall(r"/\\d+\\]", temp)[0]
temp # ex: /7]
re.findall(r"[0-9]+",temp) # ]정규식 규칙을 나타태는 ]
# /, ] 지우고 싶다
# temp = re.sub(r"\\/","", temp)
# temp = re.sub(r"\\]","", temp)
temp = re.sub(r"\\/|\\]","", temp)
temp # ex: 7
정리
- 일반적인 사이트에서는 내가 필요한 정보를 알아서 잘 찾아야 한다.
- 규칙화와 정규식에 대한 기본적인 사용이 중요하다.
실습 3 공시(Dart) 관련 추출
- 1번 공시 정보에 대한 tr 태그 찾아보기
# Q) 1개 공시 정보에 대한 tr 테그를 찾아보자!!!
len(soup.find_all("tr"))
# -> 정확하게 공시 정보들에 대해서 접근을 하기 위해서...
# tbody 속에 있는 tr로 접근하는게 좀 더 나아보인다.
# why? thead에도 tr이 포함되어 있으니...
# tbody속에 있는 tr만 다 빼기! ==> 공시들만
len(soup.find("tbody").find_all("tr"))
# --> 1번 공시에 대한 정보 접근...
soup.find("tbody").find_all("tr")[0]
idx = 0 # --> 보려는 공시 위치..
temp = soup.find("tbody").find_all("tr")[idx]
temp.find_all("td")[0] # <td>
temp.find_all("td")[0].text
# 출력 결과: \\r\\n\\t\\t\\t\\t\\t\\t\\t\\t\\r\\n\\t\\t\\t\\t\\t...
# + 참고) 원하는 정보가 있지만,,,눈에 안 보였던
# 공백문자들이 존재를 함!!!: strip():양쪽 or 정규식
temp.find_all("td")[0].text.strip()
# " 19: 29 " ---> strip()
# "19: 29" ---> 정규식으로 공백처리를 해야함!!!
t_str = "\\r\\n\\t\\t\\t\\t\\t\\t\\t\\t\\r\\n\\t\\t\\t\\t\\t\\t\\t\\t\\r\\n\\t\\t\\t\\t\\t\\t\\t\\t\\r\\n\\t\\t\\t\\t\\t\\t\\t\\t19\\r\\t:\\t\\t29\\r\\n\\t\\t\\t\\t\\t\\t\\t"
t_str.strip()
re.sub(r"\\r|\\n|\\t|\\s", "", t_str) # --> 어디라도 공백은 싹 제거.
# 공백을 제거 하는 정규식!
# 최종 출력 결과 : 19:29
1. 1번 공시 회사가 속한 시장
# 예) 코 : 코스닥, 유 : 유가증권, 넥: 코넥스, 기:기타법인
temp.find_all("td")[1].find_all("span")[1]
temp.find_all("td")[1].find_all("span")[1].get("title")
#출력 : 코스닥시장
2. 1번 공시 회사의 이름
temp.find_all("td")[1].text.strip()
# ---> 처리할 수는 있는데,,,좀 더 정확히 타켓팅을 해보자!!!!
temp.find_all("td")[1].text.strip()[1:].strip()
# --> 이러면 처리는 가능은 함....
temp.find_all("td")[1].find("a").text.strip()
# a 태그를 최종 찾아서 그 뒤에 값을 바로 가져오기
3. 회사 코드값 출력
temp.find_all("td")[1] # --> 01375822에 대한 코드값 추출
temp.find_all("td")[1].find("a").get("href")
# 출력 결과
# javascript:openCorpInfoNew('01375822',
# 'winCorpInfo', '/dsae001/selectPopup.ax');
re.findall(r"\\d{8}",
temp.find_all("td")[1].find("a").get("href"))[0]
#정규식을 사용해서 숫자 8개만 뽑아내기
# 출력 결과 : 01375822
공시의 고유값 : rcpNo
temp.find_all("td")[2].find("a").get("href")
re.findall(r"\\d+", temp.find_all("td")[2].find("a").get("href"))
# 출력: ['001', '20240305901186']
re.findall(r"\\d{14}",
temp.find_all("td")[2].find("a").get("href"))[0]
# 출력: 20240305901186
4. 공시 이름 출력
temp.find_all("td")[2].find("a").text
# 출력 : [기재정정]매출액또는손익구조30%(대규모법인은15%)이상변동\\r\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\r\\n\\t\\t \\t\\t\\t\\t\\t\\t\\t\\r\\n\\t\\t\\t\\t\\t\\t\\t\\t
temp.find_all("td")[2].find("a").text.strip()
# ??--> 중간에 혹시 보다고 공시 정보 사이에 공백/줄바꿈이 있으면
# re.sub(r"\\n|\\t|\\r","", ~~~)
# ---> 나중에 공백/줄바꿈에 대한 정규식도...
# 출력: [기재정정]매출액또는손익구조30%(대규모법인은15%)이상변동
5. 공시에 대한 요청 일자
temp.find_all("td")[4].text
# 출력 : 2024.03.05
temp.find_all("td")[4].text.strip()
# 출력 : 2024.03.05
실습과제
# Q1) for 문을 이용해서 지금 페이지의 100개 공시 정보를 출력!!!
# ==> 제출 시간, 회사가 속한시장(fullname),회사이름
# 회사 코드, 공시 이름, 공시의 고유값, 요청일자
# ----> 12시 10분에 1번은 같이 보겠습니다!!!!!!!!!
# Q2) 1번에서 출력한 내용을 DF에 저장을 해보세요!!
# ==> 컬럼 이름을 스스로 정해보세요!!!!!!
# ------------------------------------------------------------\\
# Q3) 2024년 3월 5일 같은 경우에는 7페이지를 다 돌아서
# 698건의 공시 정보에 대한 위의 Q1에서 추출한 정보들을
# 1개의 DF에 담아보세요!!!
# -----------------------------------------------------
# + opt) 이것을 함수로 만들어 보는 것!!!!
# 입력 : 조회시작일자, 종료일자
# 출력 : 입력 기간 동안의 모든 공시 처리
# DF/csv/ excel etc
# -----------------------------------------------------
# 1) 날짜에 대해서 몇 페이지를 돌릴지?
date = "2024.03.05"
page = "1"
url = f"<https://dart.fss.or.kr/dsac001/mainAll.do?selectDate={date}&sort=&series=&mdayCnt=0¤tPage={page}>"
res = requests.get(url)
soup = BeautifulSoup(res.text, "html.parser")
tot_page = soup.find_all("div", {"class" : "pageInfo"})[0].text
tot_page = re.findall(r"/\\d+\\]", tot_page)[0]
tot_page = re.sub(r"/|\\]","",tot_page )
tot_page = int(tot_page)
tot_data = []
for page in range(1,tot_page+1):
url = f"<https://dart.fss.or.kr/dsac001/mainAll.do?selectDate={date}&sort=&series=&mdayCnt=0¤tPage={page}>"
# 직접 요청 후 필요한 정보 처리하고 담아두기
res = requests.get(url)
soup = BeautifulSoup( res.text, "html.parser")
# ---> 그 날의 공시 page에서 할 일: page의 공시 롤링!!!
# 100개로 하드코딩하면 마지막에서 문제가 생김!!!
table_row = soup.find("tbody").find_all("tr")
# 그냥 table_row 그냥 값 자체로 롤링하면 됨!!!!!
for temp in table_row:
# --> temp는 기본적으로 1개 공시에 대한 정보!! : 샘플단위!
d_time = temp.find_all("td")[0].text.strip()
# --> 회사의 속한 시장
d_market = temp.find_all("td")[1].find_all("span")[1].get("title")
# --> 회사의 코드값
d_co_id = re.findall(r"\\d{8}",temp.find_all("td")[1].find("a").get("href"))[0]
# --> 회사의 이름
d_co_name= temp.find_all("td")[1].find("a").text.strip()
# --> 공시 내용의 고유값
d_rcp = re.findall(r"\\d{14}",temp.find_all("td")[2].find("a").get("href"))[0]
# --> 공시 내용에 대한 이름
d_rcp_name = temp.find_all("td")[2].find("a").text.strip()
# --> 공시 요청 일자
d_req = temp.find_all("td")[4].text
tot_data.append( [d_time, d_market, d_co_id,d_co_name,
d_rcp,d_rcp_name,d_req])
print( str(page)+"Done!!!!")
print("Done!!!!")
추가 과제
4월 9일의 유가증권 시장에 공시된 정보 DF으로 만들기
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import re
# 1) 날짜에 대해서 내가 몇 페이지를 돌려야할지
date = "2024.04.09" # <--- selectDate=
page = "1" # <--- currentPage=
url = f"<https://dart.fss.or.kr/dsac001/mainY.do?selectDate={date}&sort=&series=&mdayCnt=0¤tPage={page}>"
res = requests.get(url)
soup = BeautifulSoup( res.text, "html.parser")
# --> 앞에서 한 부분대로 내가 몇 페이지를 해야할지 찾아야 함!!!
tot_page = soup.find_all("div", {"class":"pageInfo"})[0].text
tot_page = re.findall(r"/\\d+\\]", tot_page)[0]
tot_page = re.sub(r"/|\\]","",tot_page )
tot_page = int(tot_page)
# 2) 전체 page에 대해서 요청
tot_data = [] # <----- 그 날의 모든 공시정보를 담을 리스트
for page in range(1,tot_page+1):
url = f"<https://dart.fss.or.kr/dsac001/mainY.do?selectDate={date}&sort=&series=&mdayCnt=0¤tPage={page}>"
# ---> 직적 요청하고,필요 정보 처리하고,담아두면 됨!!!
res = requests.get(url)
soup = BeautifulSoup( res.text, "html.parser")
# ---> 그 날의 공시 page에서 할 일: page의 공시 롤링!!!
# 100개로 하드코딩하면 마지막에서 문제가 생김!!!
table_row = soup.find("tbody").find_all("tr")
# 그냥 table_row 그냥 값 자체로 롤링하면 됨!!!!!
for temp in table_row:
# --> temp는 기본적으로 1개 공시에 대한 정보!! : 샘플단위!
d_time = temp.find_all("td")[0].text.strip()
# --> 회사의 속한 시장
d_market = temp.find_all("td")[1].find_all("span")[1].get("title")
# --> 회사의 코드값
d_co_id = re.findall(r"\\d{8}",temp.find_all("td")[1].find("a").get("href"))[0]
# --> 회사의 이름
d_co_name= temp.find_all("td")[1].find("a").text.strip()
# --> 공시 내용의 고유값
d_rcp = re.findall(r"\\d{14}",temp.find_all("td")[2].find("a").get("href"))[0]
# --> 공시 내용에 대한 이름
d_rcp_name = temp.find_all("td")[2].find("a").text.strip()
# --> 공시 요청 일자
d_req = temp.find_all("td")[4].text
tot_data.append( [d_time, d_market, d_co_id,d_co_name,
d_rcp,d_rcp_name,d_req])
print( str(page)+"Done!!!!")
print("Done!!!!")
df_tot = pd.DataFrame(
data = tot_data,
columns = ["time","market","co_id","co_name",
"report_code","report_name","req_date"]
)
df_tot
참고) 웹에 있는 데이터 수집 방법
- API
- 메뉴얼 보고 따라하면 됨
- 일반적인 사이트
- 숨겨진 주소를 잘 찾아서 크롤링
- 숨겨진 주소 찾아도 안되면,
- referer, user-agent ect…
- header에 필요 정보를 실어서 요청
- 웹 드라이버
- 브라우저를 통해 접근
- 패키지 : 셀리니움으로
2. 셀레니움 Selenium
- 네이버에 접속해서 bts를 검색한 뒤, 화면을 끄는 것까지 진행한 실습이다.
- 단, mac에서 진행 할 때는 ‘개인정보 보호 및 보안’ 의 설정을 진행 해야 정상적으로 작동하게 된다
import selenium
import urllib.request
url = "<https://finance.daum.net/>"
res = urllib.request.urlopen(url)
res.read().decode("utf-8")
# ---> 403 접근 금지가 나오는 경우에는
# http통신에서 header 다른 정보도 실어서 보내야 함!!!!
# 간단한 경우들은 : referer, user-agent 고려!!!
url = "<https://finance.daum.net/api/search/ranks?limit=10>"
# 부가적인 정보들 바탕으로 FM적은 통신 내용 작성..
req = urllib.request.Request(
url,
data = None,
headers = {
"referer": "<https://finance.daum.net/>",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
)
res = urllib.request.urlopen(req).read().decode("utf-8")
# 브라우저를 통해서 컨트롤 하기 위한 작업...
s = Service(path)
driver = webdriver.Chrome( service=s)
# 브라우저에서 할 수 있는 여러가지 일들
# ---> 간단하게 창 크기를 조절
driver.set_window_size( 1000,1000)
# 내가 접속하려는 사이트
url ="<https://naver.com>"
driver.get(url)
# --> 검색창에 검색어를 넣고 싶은 것
element = driver.find_element( By.XPATH, '//*[@id="query"]')
element.send_keys("bts")
# 검색 버튼을 찾아서 클릭 해줘
driver.find_element(By.XPATH, '//*[@id="search-btn"]').click()
# 종료를 하기 위해서는
driver.quit()
#네이버 검색창 개발자 도구에서 찍으면
# //*[@id="query"] # xpath copy 했을 때
# /html/body/div[2]/div[1]/div/div[3]/div[2]/div/form/fieldset/div/input # full xpath 하면 이렇게
'데이터분석 > 파이썬' 카테고리의 다른 글
[ASAC 17일차] 셀레니움, pandas to csv,excel (0) | 2024.04.15 |
---|---|
[ASAC 15일차] XML, JSON crawling 연습 (0) | 2024.04.12 |
[ASAC 14일차] DataFrame, JSON (0) | 2024.04.09 |
[ASAC 13일차] SQL EDA, Numpy, Pandas (0) | 2024.04.08 |
[ASAC 9일차] 파이썬 + SQL 기초 (0) | 2024.04.02 |