[selenium]셀레니움 사용시 특정 element의 클릭이 되지 않을때 대처법

셀레니움을 통해 특정 element를 클릭하려고 할때 보통은 아래와 같은 방법을 사용하곤 한다.

1
body.find_element_by_class_name("btn_more").click()

click() 함수를 사용하게 되면 간단하게 해당 element를 클릭할 수 있는데, 원인 미상으로 가끔씩 클릭이 되지 않는 상황이 발생했다.

클릭을 구현하는 방법으로는 click() 함수와 submit() 함수를 사용할 수 있지만, 위의 상황처럼 보통의 방법으로는 클릭이 수행되지 않을때 아래의 코드 처럼 구현하면 문제 없이 사용할 수 있었다.

1
2
3
from selenium.webdriver.common.keys import Keys

driver.find_element_by_id("TOTAL").send_keys(Keys.ENTER)

하지만,,
위의 방법을 통해도 클릭이 되지 않을 수 있는데, 아래와 같은 방법을 시도해보자.

1
2
element = driver.find_element_by_id("TOTAL")
driver.execute_script("arguments[0].click();", element)

[참고]
https://wkdtjsgur100.github.io/selenium-does-not-work-to-click/

Share

[python]파이썬의 타입 힌트

파이썬은 동적 타이핑 언어로서 코드를 작성하는 시점이 아닌 프로그램이 진행될때 자료형이 정해진다. 파이썬 버전 3.5부터 도입되기 시작되었으며 타입 힌트를 적용할 수 있는 범위가 점진적으로 넓어지고 있다.

typing 패키지

파이썬에서 타입 힌트를 사용하기 위해 typing 모듈을 임포트해야 한다. 물론 밑의 예시처럼 *를 써서 모든 기능을 가져오는 것은 좋지 않다. 실제 사용시에는 필요한 것만 임포트할 수 있도록 한다.

1
from typing import *

1. 변수에 사용하기

타입 힌트가 등장했던 3.5 버전에서는 사용이 불가하다. 3.6 이상부터 사용할 수 있다. 변수명 뒤에 자료형을 적어준다. 어떻게 보면 golang과 비슷한거 같기도 하다.

1
2
text: str = 'Hello world!!'
num: int = 123

만약 사용자가 직접 만든 클래스가 있다면 클래스의 인스턴스를 생성할때에도 적용할 수 있다.

1
2
3
4
class Test():
pass

ins_a: Test = Test()

2. 함수의 인자에 사용하기

함수의 인자와 리턴에 타입 힌트를 적용할 수 있다. 어떠한 자료형의 인자를 받고 함수의 리턴형을 유추할 수 있도록 돕는다. 아래의 예시는 문자열 인자 title과 숫자형 인자 num을 사용하며 이 함수의 리턴형은 str이어야한다.

1
2
def test_func(title: str, num: int) -> str:
pass

만약 특정한 반환값이 없는 함수라면 이렇게 할 수 있다.

1
2
def test_func1(text: str) -> None:
print(text)

3. 리스트 / 딕셔너리 / 튜플

리스트 / 딕셔너리 / 튜플을 타입 힌트로 표현하는 방법은 아래와 같다.

1
2
3
num_list = List[int]
test_dict = Dict[str, int]
test_tuple = Tuple(int)

결론

파이썬 3.5부터 등장한 타입 힌트에 대해서 아주 간단하게 정리했다. 함수와 변수에서 사용되는 타입 힌트에 대해서만 나열했지만 사실은 더 많은 기능들이 존재한다. 또한 mypy라는 툴을 pip로 설치하여 같이 사용하면 정적 타입 검사기로써 사용할 수 있어 타입 힌트를 사용하는 데에 도움을 줄 수 있을 것이다.


[참고]
https://item4.blog/2017-09-14/Python-Typing-with-mypy/
https://minwook-shin.github.io/python-type-hint-typing-using-mypy/
https://lewisxyz000.tistory.com/35

Share

[파이썬]추상클래스

추상클래스란?

추상화된 클래스이다. 상속받을 서브 클래스를 위한 클래스이다. 공통된 속성(필드, 메소드)을 가지는 것은 일반적인 클래스와 같으며 아래와 같은 차이점(특징)이 있다.

  • 객체를 생성할 수 없다.
  • 서브클래스에서 메소드의 구현을 강제한다.

예시

일반 abc 모듈이 필요하다(abc는 Abstract Base Class의 약자)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import abc

# 추상클래스
class RandomMachine(abc.ABC):

@abc.abstractmethod
def load(self, iterable):
pass

@abc.abstractmethod
def pick(self, iterable):
pass

def inspect(self):
items = []
while True:
try:
items.append(self.pick())
except LookupError:
break
return tuple(sorted(items))

# a = RandomMachine()
# TypeError: Can't instantiate abstract class RandomMachine with abstract methods load, pick

추상클래스를 만들기 위해서는 abc.ABC를 상속 받아야한다. 만약 파이썬 3.4 이전 버전을 사용 중이라면 아래와 같이 상속받아야 한다.

1
2
class RandomMachine(metaclass=abcABCMeta):
pass

@abc.abstractmethod 데코레이터를 통해서 서브클래스에서 강제할 메소드를 만들어 주었다. 만약 메소드를 생성하지 않았다면 객체를 생성하는 시점에서 에러가 발생할 것이다.

이제 실제로 사용할 클래스를 생성해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import random

class NumberMachine(RandomMachine):

def __init__(self, items):
self._randomizer = random.SystemRandom()
self._items = []
self.load(items)

def load(self, items):
self._items.extend(items)
self._randomizer.shuffle(self._items)

def pick(self):
try:
return self._items.pop()
except IndexError:
raise LookupError('에러!!')

def __call__(self):
return self.pick()

ins = NumberMachine(range(1, 101))
ins()

NumberMachine 클래스를 정의했고 추상클래스에서 강제한 메소드를 구현했다. 만약 load와 pick 메소드 중에서 하나라도 구현이 되어 있지 않는다면 TypeError가 발생한다. 그리고 객체를 호출가능하게 만들기 위해 __call__ 특별 메소드도 구현했다.

Share