[왕초보 웹크롤링 무작정 따라하기] 웹크롤링, 셀레니움, 절대좌표, 상대좌표, 요소위치 확인, 자바스크립트 사용
업무지옥을 탈출한 건에 대하여(feat.업무자동화)
#15 셀레니움 절대좌표/상대좌표 활용하기
대표적인 동적페이지라고 할 수 있는 인스타그램 크롤링에 성공했다! 하지만 아직 나는 목마르다. 최근 게시물 뿐만 아니라 전체 피드의 데이터를 크롤링하고 싶다. 하지만 그러기 위해서는 몇가지 문제를 해결해야 한다. 바로 스크롤에 따른 데이터의 변화다. 인스타그램의 html을 확인해보면 스크롤을 내리는 것에 따라 경로가 갱신되며 경로가 늘었다 줄었다 한다. 동일한 경로임에도 데이터가 달라지기도 한다. 이 문제를 어떻게 해결해야 할까?
해결방법은 데이터 경로 이외의 선택기준을 만드는 것이다. 변경되는 경로를 대체하는 것이다. 이를 위해 브라우저 상의 상대좌표를 사용하기로 했다. (절대좌표는 요소 자체가 가지고 있는 좌표이고, 상대좌표는 특정 요소를 기준으로 계산한 좌표이다.)
상대좌표를 사용하면 스크롤이 내려가든 보여지는 콘텐츠가 바뀌든 상관없이 브라우저 상의 특정 위치를 클릭할 수 있다. 인스타그램 피드들은 브라우저 상으로도 고정적인 규칙으로 배치되어 있기에, 이를 활용해 각 피드가 위치할 좌표를 미리 지정하는 것이다. 경로 직접 코드에 넣는 방식이 대상을 지정하면 자동으로 맞는 타겟팅이라면, 상대좌표로 피드가 올 자리를 기준으로 잡는 것은 미리 예측해서 상대를 맞추는 논타겟팅으로 이해할 수 있다.
논타게팅, 즉 사격과 비슷하다. 현재 위치(절대좌표)와 타겟의 위치(상대좌표)를 파악하고 거리와 영영점을 조절해 발사한다. 피드 클롤링은 타겟을 추적하며 사격하는 것이라고 생각할 수 있다. 이를 위해선 사격할 위치(스크롤에 따라 이동하는 절대 좌표)와 타겟의 범위(상대좌표로 설정할 수 있는 범위)을 알아야한다. 인스타그램 페이지에서 스크롤이 달라져도 고정되어 있는 요소, 인스타그램 로고를 사격위치(절대좌표)로 삼기로 했다.
요소의 절대 좌표 확인하기
요소의 좌표를 구하는 메소드는 .location이다. 브라우저 상 눈에 보이는 위치는 변하지 않지만 스크롤의 이동에 따라서 좌표값은 달라지게 된다. 타겟을 따라가며 사격 위치를 바꾸는 것이라고 이해하면 된다. 위치를 옮기기 때문에 현재 좌표는 달라지는 것이다.
# 요소 좌표 확인
dr.find_element_by_xpath('').location
상대 좌표 활용하기
다음은 타겟의 범위이다. 웹개발자 도구의 Computed 창에서 각 요소의 크기를 확인할 수있다. 피드의 크기는 가로세로 174.8px에 주변으로 3px의 간격을 갖는 것을 확인할 수 있었다. 상대좌표 값이 (a+174.8, b+174.8)만 벗어나지 않는다면 명중이다. 이는 각 피드에서 일정한 값이 늘어나는 규칙성을 갖게 된다.
마지막으로 첫 시작 지점을 설정해주자. 시작점의 스크롤 위치를 고정해 줘야 코드를 반복할 때 이상이 생기지 않는다. 나는 첫 피드가 상단 네비게이션바에 걸치는 곳을 기준으로 삼기로 했다. 상대 좌표는 요소가 화면상 어디에 위치하느냐에 따라 달라지기 때문에 스크롤 위치를 알아야 한다. 웹 상의 스크롤 현 위치나 전체 길이, 이동 등은 자바스크립트를 사용해야 하는데, 파이썬에서 자바 스크립트를 사용하기 위해 .execute_script("자바스크립트 코드")를 사용한다.
현재 스크롤 위치를 확인하는 코드 execute_script("return window.pageYOffset")로 좌표를 구하니 {'x': 20, 'y': 479}이다. 스크롤 이동 코드 execute_script("window.scrollTo(0, 479)")로 시작점을 설정해 주었다.
# 현재 스크롤 전체 길이 추출
dr.execute_script("return document.body.scrollHeight")
# 현재 스크롤 좌표 추출
dr.execute_script("return window.pageYOffset")
# 지정 좌표로 스크롤 이동
dr.execute_script("window.scrollTo(0, 0)")
이제 타겟의 범위에서 벗어나지 않는 임의의 좌표를 로고 좌표에 더해주는 것으로 각 피드에 위치하는 상대좌표를 구할 수 있다. 각 피드 범위가 x,y 174.8이니 피드를 옮길 때 x,y값에 175씩 더 해줘도 각 피드 범위에 충분히 들어온다.
이런 원리로 로고 좌표까지의 거리도 계산하여 반영하면 아래와 같은 규칙이다. 이를 브라우저 상 12개의 피드를 대상으로 코드를 짜면 다음과 같다.
로고 = (x,y) |
||
1열 1번째 피드 = (x, y+110) *110 =로고 영역 y 값 23 + 피드 영역을 벗어나지 않는 임의의 값 87(대충 피드 중간) |
1열 2번째 피드 = (x+175, y+110) |
1열 2번째 피드 = (x+175+175, y+110) |
2열 1번째 피드 = (x, y+110+175) |
2열 2번째 피드 = (x+175, y+110+175) |
2열 3번째 피드 = (x+175+175, y+110+175) |
... | ... | ... |
#시작점으로 스크롤 이동
dr.execute_script("window.scrollTo(0, 479)")
#로고의 좌표 추출
standard_logo = dr.find_element_by_xpath('//section/nav/div[2]/div/div/div[1]/a/div/div')
#상대좌표를 통한 대상 변경 반복문
for line in range(0, 4):
y = 110 + 175 * line #열 번호를 기준으로 175씩 y좌표를 더함
for box in range(0, 3):
x = 175 * box #박스 번호를 기준으로 175씩 y좌표를 더함
act = ActionChains(dr)
#로고 좌표에 상대좌표를 더해 피드 마우스 오버
act.move_to_element(standard_logo).move_by_offset(x, y).perform()
이제 각 피드의 경로를 넣어주지 않아도 피드를 클릭할 수 있게 되었다. 여기에 전체 스크롤까지 제어한다면 모든 피드를 크롤링 할 수 있다!
- 계속 -
[system]
자바스크립트에 대해 이해하기 시작합니다.
'스킬 : 자바스크립트 활용' 획득
'스킬 : 동작 제어'를 습득률: 90%
[보유 스킬]
자바스크립트 활용, 주문연계,
데이터시각화, 데이터필터링, 웹데이터 소환
[보유 칭호]
브라우저를 제어하는 자, 웹데이터를 불러내는 자
'데이터 스킬업 > 웹크롤링' 카테고리의 다른 글
[ep01:웹크롤링] #19 인스타그램 웹크롤링 자동화(예제) with 파이썬 (0) | 2021.08.13 |
---|---|
[ep01:웹크롤링] #18 오류 무시/예외 처리(Try/Except) with 파이썬 (0) | 2021.08.12 |
[ep01:웹크롤링] #17 셀레니움 로딩될 때까지 시간/조건 설정하기 with 파이썬 (1) | 2021.08.05 |
[ep01:웹크롤링] #16 셀레니움 스크롤 조절하기 with 파이썬 (0) | 2021.08.03 |
[ep01: 웹크롤링 (번외3) ] 디버깅과 콘솔 기초(같은 브라우저에서 셀레니움 실행하기) with 파이썬출처 (0) | 2021.07.21 |
댓글