파이썬으로 웹 크롤링할때 쓸만한 테크닉을 정리했습니다.
1. Beautiful Soup
기본 구조는 아래와 같습니다.
requests 는 웹 페이지를 가져오기 위한 라이브러리
bs4(BeautifulSoup) 는 웹 페이지 파싱을 위한 라이브러리입니다.
soup 에 HTML을 파싱한 정보가 들어갑니다.
import requests from bs4 import BeautifulSoup res = requests.get('가져올 웹 페이지 주소') soup = BeautifulSoup(res.content,'html.parser')
☑️ 테스트 코드 작성하는 방법
실제 웹페이지에서 가져오기 전 테스트 코드를 작성하고 싶을때 아래와 같이 사용 합니다.
from bs4 import BeautifulSoup # html 구조 만들기 html=""" <p>요소1</p><p>요소2</p><p>요소3</p> """ # html 파싱 soup=BeautifulSoup(html,'html.parser') # 메소드로 원하는 부분 추출 p = soup.find('p') print(p) print(p.next_sibling) print(p.next_sibling.next_sibling) 실행결과 <p>요소1</p> <p>요소2</p> <p>요소3</p>
1.1 find
태그로 요소를 선택합니다.
<h1>제목입니다</h1> data = soup.find('h1')
아이디로 요소를 선택합니다.
<div id="title">제목입니다</div> data = soup.find(id='title')
태그와 클래스 이름을 지정해 선택합니다.
<p class="title">제목입니다</p> data = soup.find('p', class_='title')
태그 안 속성으로 선택합니다.
<p data = soup.find('p', attrs = {'align': 'center'}) 📌 속성 추출attr
태그 안에 있는 속성들을 전부 key : value 형태의 딕셔너리로 추출합니다.
p class="tag" href="http://example.com" style="text-align:center">요소1</p> data = soup.find('p').attrs 실행결과 {'class': ['tag'], 'href': 'http://example.com', 'style': 'text-align:center'} href
태그에서 링크를 추출할때 사용합니다.
이미지에서 링크 추출할 때 많이 씁니다.
<p href="http://example.com">요소</p> data = soup.find('p')['href'] 실행결과 http://example.com 속성 검증
try except 를 사용하는 대신 아래 속성 검증을 통해
오류를 방지할 수 있습니다.
if 'href' in a.attrs : ... 추출하는 코드 ...
1.2 css select
select_one 은 요소를 반환합니다.
select 는 요소의 리스트를 반환합니다.
soup.select_one('선택자') soup.select('선택자') 선택자
태그명으로 가져옵니다.
'p'
아이디로 가져옵니다.
'#main'
자식들 중 해당 태그를 가져옵니다.
`ul.items li`
바로 아래에 있는 자식 태그를 가져옵니다
`ul.items > li`
href의 값이 특정 문자열로 시작하는 태그를 가져옵니다.
`a[href^='http://www.testsite.co.kr/']`
href의 값이 특정 문자열로 끝나는 태그를 가져옵니다. 입니다.
'[href$='contact/']'
href의 값이 특정 문자열을 포함하는 태그를 가져옵니다.
a[href*='news']
class의 값이 특정 문자(열)와 같지 않은 태그를 가져옵니다
`a[class!='문자열']`📌 속성 추출
문서 전체에서 a 태그 중 속성 값 href를 갖은 태그를 찾습니다.
soup.select('a[href]')
id가 bodyContent인 태그의 자손 태그 중에서 a 태그 속성 값 href를 갖은 태그를 찾습니다.
soup.select('#bodyContent a[href]')
1.3 텍스트 추출
아래와 같이 태그 내부의 글자를 추출할 수 있습니다.
<div>글자</div> data = soup.find('div') # 글자 추출 data.get_text() data.string
2. Selenium
셀레니움을 이용하면 브라우저를 제어해서 크롤리을 할 수 있습니다.
스크롤, 클릭, 키보드입력 등이 가능하기 때문에 인스타그램, 페이스북 등 로그인이 필요한 사이트들의 소스를 가져올 수 있습니다.
pip install selenium
기본 코드 구조입니다.
from selenium import webdriver from selenium.webdriver.common.keys import Keys import time chromedriver = '설치한 chromedriver 경로' driver = webdriver.Chrome(chromedriver) driver.get('가져올 웹 페이지 주소') # 검증 코드입니다. assert '웹 페이지 타이틀' in driver.title ... driver.quit()
2.1 페이지 로드 대기
브라우저에서 해당 웹 페이지의 요소들을 로드하는 데 시간이 걸리기 때문에 대기가 필요합니다.
driver.implicitly_wait(time_to_wait=3)
찾으려는 element가 로드될 때까지 지정한 시간만큼 대기할 수 있도록 설정합니다.
이는 한 webdriver에 영구적으로 작용합니다.
time.sleep(3)
time.sleep(secs) 함수를 사용하여 무조건 몇 초간 대기하는 방법도 있습니다.
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome('chromedriver') driver.get(url='https://www.google.com/') try: element = WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.CLASS_NAME , 'gLFyf')) ) finally: driver.quit()
위의 코드는 웹페이지에서 class가 gLFyf인 어떤 element를 찾을 수 있는지를 최대 5초 동안 매 0.5초마다 시도합니다.
expected_conditions(EC)는 element를 찾았다면 True를, 아니라면 False를 반환합니다.
2.2 키보드 입력
input 태그를 선택하고 키보드 입력을 명령으로 텍스트를 입력할 수 있습니다.
clear() : 기존에 입력값이 있었다면 지웁니다.
send_keys('입력할 값') : 키보드 입력값을 input 태그에 전달합니다.
Keys.RETURN : 엔터키를 누릅니다.
dir(Keys) 로 키에 대응되는 이름을 찾습니다.
elem = driver.find_element_by_name('username') elem.clear() elem.send_keys('Ywoosang') elem.send_keys(Keys.RETURN)
2.3 클릭하기(click)
find_element 함수로 요소를 선택한 다음 click() 함수를 호출합니다.
tag = driver.find_element_by_tag_name('button') tag.click()
2.4 스크롤
scrollTo 이용driver.execute_script("window.scrollTo(0, Y)")
페이지 끝까지 가려면 Y 값을 아래와 같이 설정합니다. (Y 는 height 을 의미합니다.)
document.body.scrollHeight
동적 웹페이지에서 스크롤 다운하면서 데이터를 조회할 경우입니다.
SCROLL_PAUSE_SEC = 1 # 스크롤 높이 가져옴 last_height = driver.execute_script("return document.body.scrollHeight") while True: # 끝까지 스크롤 다운 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 1초 대기 time.sleep(SCROLL_PAUSE_SEC) # 스크롤 다운 후 스크롤 높이 다시 가져옴 new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break #time.sleep(1) #if new_height == last_height: # break last_height = new_height
간혹 로딩이 걸려 중간에 코드가 멈춘다면 SCROLL_PAUSE_SEC 를 증가시켜봅니다.
ActionChains 의 move_to_element 이용
ActionChains 에 대해 아래에서 자세히 다룹니다.
특정한 element 를 알고 있을 때 그 위치까지 스크롤 할 수 있습니다.
# ActionChains 를 사용하기 위해서. from selenium.webdriver import ActionChains # id가 something 인 element 를 찾음 some_tag = driver.find_element_by_id('something') # somthing element 까지 스크롤 action = ActionChains(driver) action.move_to_element(some_tag).perform()특정 시간동안 계속해서 scroll down 하기
아래와 같이 datetime 을 이용해서 정해진 초 동안 1초에 한번씩 스크롤 다운합니다.
동적 웹페이지의 데이터를 다 가져올 수 없을 때 시간을 정하고 그 시간동안 크롤링을 실행합니다.
import datetime def doScrollDown(whileSeconds): start = datetime.datetime.now() end = start + datetime.timedelta(seconds=whileSeconds) while True: driver.execute_script('window.scrollTo(0, document.body.scrollHeight);') time.sleep(1) if datetime.datetime.now() > end: break
2.5 JavaScript 코드 실행
driver.execute_script() 함수로 자바스크립트 코드를 실행할 수 있습니다.
아래는 Name이 search_box인 요소의 값을 query의 값으로 변경하는 코드입니다.
driver.execute_script("document.getElementsByName('id')[0].value=\'"+query+"\'")
2.6 태그 가져오기
element 는 최초로 발견한 태그만 가져옵니다.
elements 는 조건에 해당하는 모든 태그를 리스트로 가져옵니다.
아래와 같이 다양한 검색 조건이 존재합니다.
필요에 맞는 것을 가져다 쓰면 됩니다.
find_element_by_tag_name(), find_element_by_id() find_element_by_css_selector() driver.find_element_by_xpath() ind_element_by_name()
아래처럼 사용합니다.
diver.find_element_by_css_selector('div > a[href="http://example.com"]') driver.find_element_by_css_selector('html head title') driver.find_element_by_css_selector('h3.tit_view') driver.find_element_by_css_selector("div#harmonyContainer")
2.7 ActionChains 사용방법
마우스 클릭, Drag & Drop, 키보드 입력 등을 연속적으로 수행할 수 있습니다.
메소드수행 동작
click(on_element=None) | 인자로 주어진 요소를 왼쪽 클릭한다. |
double_click(on_element=None) | 인자로 주어진 요소를 왼쪽 더블클릭한다. |
key_down(value, element=None) | value 로 주어진 키를 누르고 떼지 않는다. |
key_up(value, element=None) | value로 주어진 키를 뗀다. |
send_keys(*keys_to_send) | 키보드 입력을 현재 focused된 요소에 보낸다. |
send_keys_to_element(element, *keys_to_send) | 키보드 입력을 주어진 요소에 보낸다. |
perform() | 이미 쌓여 있는(stored) 모든 행동을 수행한다(chaining). |
예를들어 Ctrl + C를 누르고 싶다면 아래와 같이 입력합니다.
ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
참고
on_element인자를 받는 함수는, 해당 인자가 주어지지 않으면 현재 마우스 위치를 기준으로 합니다.
element 인자를 받는 함수는, 해당 인자가 주어지지 않으면 현재 선택이 되어 있는 요소를 기준으로 합니다.
key_down, key_up 함수는 Ctrl 등의 키를 누를 때 사용합니다.링크를 참조합니다.
2.8 뒤로가기, 앞으로 가기
뒤로가기(back)와 앞으로 가기(forward) 입니다.
driver.forward() driver.back()
2.9 텍스트 추출
태그에 .text 를 붙여 문자열로 가져옵니다.
data.text
2.10 브라우저 크기 설정
브라우저 크기를 원하는대로 조정합니다.
driver.set_window_size(1920, 1080)
브라우저 크기를 최대, 최소로 조정할 수 있습니다.
driver.minimize_window() driver.maximize_window()
2.11 XPath
XPath 문법입니다.
nodename : nodename을 name으로 갖는 모든 요소 선택
/ : root 요소에서 선택
// :현재 요소의 자손 요소를 선택
. :현재 요소를 선택
.. :현재 요소의 부모 요소를 선택
@ :속성(attibutes)를 선택
* : 모든 요소에 매치됨
@* : 모든 속성 요소에 매치됨
node() : 모든 종류의 모든 요소에 매치됨
| : OR 조건의 기능
아래는 예시입니다.
/div/p[0] : root > div > p 요소 중 첫 번째 p 요소를 선택합니다.
/bookstore/book[price>35.00] : root > bookstore > book 요소 중 price 속성이 35.00 초과인 요소들을 선택합니다.
/div/p[position()<3] : root > div > p 요소 중 첫 두 p 요소를 선택합니다.
//*[@id="tsf"]/div[2]/ : id가 tsf인 모든 요소의 자식 div 요소 중 3번째 요소를 선택합니다.
2.12 Headless Chrome
셀레니움을 이용하면 크롬창이 열립니다.
이를 보고싶지 않다면 Headless Chrome 을 이용합니다.
from selenium import webdriver options = webdriver.ChromeOptions() options.add_argument('headless') options.add_argument('window-size=1920x1080') options.add_argument("disable-gpu") agent="User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131" options.add_argument(agent) options.add_argument("lang=ko_KR") chromedriver = '설치한 chromedriver 경로' driver = webdriver.Chrome(chromedriver, chrome_options=options) driver.get('가져올 웹 페이지 주소') ... driver.quit()
'내마음대로만들어보자 > 참고자료' 카테고리의 다른 글
[참고자료] 자바스프링 기본개념 (0) | 2021.06.18 |
---|---|
[참고내용] selenium 스크롤하기 (0) | 2021.06.07 |
[참고자료] 바닐라 자바스크립트 웹 프로젝트 소스 (0) | 2021.06.07 |