2019-02-25

BeautifulSoup의 selector를 조금만 더 고급스럽게 사용하기

0. 공식 홈페이지에선 굳이 네 가지를 구분하고 있다.

(Blogger에서 글자가 깨져서 사진으로 가져오는 미천한 수준)

가만히 보면 href 뒤의 특수문자들이 붙어있는데, 이것의 의미를 눈치로 배워보았다.



1. a[href= 는 정말 단순하게 a 태그의 하이퍼링크가 http://example.com/elsie로 연결되는 엘리먼트만을 찾는다. 가장 많이 사용하는 형태이지 않을까 싶다.

2. a[href^= 는 "..." 안에 들어갈 문장으로 시작하는 주소를 찾는다. 그래서 반환된 엘리먼트들이 모두 .com/까지는 똑같지만 elsie, lacie, tillie 처럼 뒤가 다르다. 마치 RegEx같다.

3. a[href$= 는 "..." 안에 들어갈 문장으로 끝나는 주소를 찾는다.

4. a[href*= 는 "..." 안에 들어갈 문장이 가운데에 끼어있는 경우를 찾는다. 예시를 보면 ".com/el"을 줬는데, 저 문장 앞과 뒤에 무엇이 오건간에 상관없이, ".com/el"가 들어있기만 하면 찾아서 리턴해주는 것이다. 마치 와일드카드처럼 작동한다.

2019-02-24

Selenium + Python: 특정 엘리먼트가 로드되고 나서 페이지 로딩을 멈추는 방법

0. 출처

원본 : https://stackoverflow.com/questions/44503576/selenium-python-how-to-stop-page-loading-when-certain-element-gets-loaded
아카이브 : https://web.archive.org/web/20190224122739/https://stackoverflow.com/questions/44503576/selenium-python-how-to-stop-page-loading-when-certain-element-gets-loaded



1. 질문

접속하려는 페이지가 AJAX를 사용할 때 implicit waits나 explicit waits를 사용할 수 있다. 하지만 driver.get()을 사용해 로딩하는 중간에, 충분한 엘리먼트를 얻었을 경우엔 해당 로딩을 중단시키고 싶다. driver.get()은 오직 페이지 로딩이 끝났을 때에만 객체를 반환하다보니 이게 가능할지가 궁금하다.



2. 대답

된다. 'pageLoadStrategygy'의 설정을 사용하면 가능하다. 그리고 나서 해당 엘리먼트가 존재하는 것이 확인되면 'window.stop()'을 호출해 로딩을 멈추게 만든다.



from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

capa = DesiredCapabilities.CHROME
capa["pageLoadStrategy"] = "none"

driver = webdriver.Chrome(desired_capabilities=capa)
wait = WebDriverWait(driver, 20)

driver.get('http://stackoverflow.com/')

wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#h-top-questions')))

driver.execute_script("window.stop();")



일단 import하는 것이 많아보인다.

2019-02-22

pip install PyAutoGUI 중 UnicodeDecodeError: 'cp949'를 만나다..

(클릭하면 확대됨)

0. 문제는 여기서부터 시작됐다.



나는 그저 terminal에 'pip install pyAutoGUI'를 입력한 다음 엔터를 눌렀을 뿐이고

컴퓨터는 내게 "cp949를 코덱으로 쓰는 열등한 너네 민족이

감히 이 패키지를 설치하려 드는거야?"라며 에러를 퉤 뱉어냈다.



1. cp949가 뭐지..

cp949라는 녀석을 처음 만난 것은 아니다.

with open('text.html', 'r') as f:

    f.read()

라고 입력해서 만난 cp949 에러 때문에 encoding='utf-8'을 붙였던 적이 잦았다.

그럼 대체 cp949는 뭐하는 녀석인걸까.



2. 코드 페이지 949의 약자이다.

마이크로소프트에서 도입한 코드 페이지로,

'통합형 한글 코드(Unified Hangul Code)라는 명칭으로 부르기도 한다.

한글 언어팩 정도인 것 같다.

이게 만들어진 이유는..

이전의 인코딩에선 '쌰', '쓩'등의 글자가 표시되지 않는 문제가 있어서

이를 확장시킨 버전이 등장했는데 이게 cp949다.

더 많은 이야나무위키에서도 찾을 수 있었다.



3. 내 컴퓨터에서 기본 인코딩이 cp949로 되어있는 모양이다.



...


...


라고 생각해서 많은 시행착오를 거쳤다.

Python 3.6을 3.7로 업그레이드도 해보고, Pycharm을 지웠다가 재설치도 해보고,

PyPI에 들어가 pyautogui를 수동으로 다운받은 다음

해당 패키지의 setup.py 중 fh.read() 위의 open() 함수에서

encoding='utf-8'까지 붙여보았지만 여전히 먹통이었다.



4. 뜻밖의 해결... 허무하다.

어떤 사람은

pip install pyautogui===0.9.39

를 써보라고 권하기도 했다. 하지만 버전을 낮추기엔 뭔가 아쉬움이 남았다. 그러던 중..

pip install pygetwindow==0.0.1

을 써보라는 말을 듣고 바로 실천해보았다.



아주 잘 된다.

PyAutoGUI를 윈도우10에서 설치하다가 UnicodeDecodeError를 만나게 된다면

위의 방법을 시도해보길 바란다.

의존성이라는 것을 너무 맹신해선 안된다던 어느 글이 생각난다..



5. 여담.

실은 이미 CentOS에서 PyAutoGUI를 설치해보았는데,

해당 OS는 기본 언어가 영어로 되어있다보니 설치하는 데에 전혀 문제가 없었다.

하지만 공식 홈페이지에 따르면 리눅스에서는 'pip3 install python3-xlib' 처럼

추가적인 패키지를 설치해야 하는 경우가 생길 수 있다.

윈도우즈의 AppData 폴더는 왜 있을까

0. 그저 유저의 입장에서는 딱히 알 필요도 없고, 알아서 도움이 될 것도 별로 없다. 흔히 윈도우즈에 프로그램을 설치하면 "C:\Program Files" 혹은 "C:\Program Files (x86)" 등에 모든 파일이 저장되는 줄로만 알았다. 그런데 실제론 "C:\Nexon"에 저장되거나, "C:\Users\사용자이름\AppData\Local"에 저장되는 경우가 더 많았다. 대체 이 차이는 왜 생기게 된걸까? 무엇을 프로그램 폴더에 저장하고, 무엇을 AppData라는 폴더에 저장하게 된걸까?

검색을 통해 내용을 짜깁기하고 정리해보았다. 순전히 호기심을 따라가며 알아본 내용이고, 내용을 정리하는 소양이 부족한 점은 양해 부탁드립니다.



1. AppData에는 총 3 개의 폴더가 있다. Roaming, Local, localLow이다.

Roaming 폴더는 유저의 계정을 통해 사용자의 PC와 '같은 도메인에 연결된 다른 PC'를 연결함으로써 주고받을(로밍) 데이터를 저장하는 용도로 사용된다. 다른 PC는 대표적으로 서버 컴퓨터가 될 수 있고, 웹 브라우저를 통해 북마크를 연동시키는 경우처럼 내 계정을 통해 데이터를 sync할 수 있는 기능을 담당한다. 로밍 유저의 장점이라면, 네트워크에 접속되어 있고 계정이 연동되어 있기만 하다면 별도의 프로파일을 만들거나 프로그램의 설정을 다시 맞춰주는 수고를 할 필요가 없다는 점이다.

Local 폴더는 단일 컴퓨터의 특정한 데이터가 저장된다. 이 폴더의 데이터들은 유저의 프로필을 따라 다른 곳으로 이동하거나 연동되지 않는다. 서버와 연동하기엔 너무 파일이 크거나, 고유해야만 하는 데이이터, 웹 브라우저의 임시 파일들이 주로 이 폴더에 저장된다.

사용자의 PC가 도메인에 연결되어 있지 않은 경우, Roaming 폴더와 Local 폴더는 실제 차이가 없다. 그러나 응용 프로그램 개발자는 경우에 따라 서로 다른 유형의 데이터를 분할할 때에 두 폴더를 구분하여 사용한다.

LocalLow은 Local 폴더처럼 이동하지 않는 데이터를 포함하고 있지만, 낮은 수준의 접근은 허용되는 폴더이다. 예를 들어서, 구글 크롬의 시크릿 모드를 사용하는 경우에 구글 크롬과 그 내부 앱들은 오직 LocalLow 폴더에만 접근할 수 있다.

프로그램이 설치되는 과정에서 해당 애플리케이션들은 설치 설정에 따라 Local, LocalLow, Roaming 폴더에 나누어져 저장된다. 대부분의 데스크탑 애플리케이션들은 Roaming 폴더에 들어가고, Windows Store에서 받은 애플리케이션들은 Local 폴더에 저장된다.



2. 평범한 사용자라면 이 폴더를 백업할 일이 별로 없다.

대부분의 윈도우즈 사용자들은 이 폴더의 존재조차 알 필요조차 없다. 그게 바로 이 폴더가 숨겨진 상태로 존재하는 이유이다. 프로그램이 애플리케이션 데이터를 이 폴더에 저장하고 있으니.. 원한다면 이 폴더를 들쑤시고 다녀도 좋겠지만, 유저가 그럴 필요가 생기는 경우는 별로 없다.

따라서 이 폴더를 전부 백업할 필요는 더더욱이 없다. 그럼에도 불구하고 내가 가진 모든 데이터를 백업하고 싶어지는 경우엔 이 폴더를 백업해도 된다. 예를 들어서 특정 프로그램의 설정들이나 게임 세이브 파일을 백업해서 다른 컴퓨터로 옮기고 싶다면, 이 폴더를 찾아 들어와서 해당 프로그램의 디렉토리를 찾아낸 후 복사해서 다른 PC의 같은 위치로 붙여넣으면 된다. 그러면 같은 환경에서 프로그램을 조작할 수 있게 된다. 

물론 이 방법은 전적으로 해당 프로그램이 어떠느냐에 따라 다르다. 즉, 개발자들이 항상 이 가이드라인을 지킨다는 의미는 아니다. 어떤 프로그램은 설정이나 파일들을 레지스트리에 저장하기도 하고, 어떤 프로그램은 '내 문서'같은 폴더에 저장해놓을 수도 있기 때문이다('카카오톡 받은 파일'처럼) 

많은 프로그램들이 해당 프로그램을 다른 PC로 연동할 수 있도록 sync 기능 혹은 설정 내보내기를 지원한다. 그런 기능이 존재한다면 먼저 사용하는 것이 깔끔할지도.



3. 그러면 Program Files, ProgramData 폴더는 왜 존재할까?

Program Files 폴더는 실행 파일(executable file)과 정적 파일(static file)을 보관하는 용도로 쓴다. ProgramData는 exe 파일을 실행할 때 공유되는 캐시, 공유되는 데이터베이스, 공유되는 환경설정 등이 정의된 파일을 담아둔다. 

한편 AppData 폴더는 사용자 계정(User profile)을 따라 움직이는 데이터들을 저장해두는 공간이다. 그래서 Local, LocalLow, Roaming 폴더는 모두 "C:\Users\사용자이름\AppData\"의 하위에 존재하고, Program Files와 ProgramData는 C드라이브 최상위(C:\)에 위치하고 있다.















2019-02-15

Open Babel을 사용해보자.

0. 오픈 바벨(Open Babel)은 chemical file formats간 변환을 도와주는 컴퓨터 소프트웨어다.



1. 윈도우즈, 유닉스, 리눅스, 맥OS, 심지어 안드로이드 운영체제에서까지 작동할 수 있는

광범위한 cross-platform을 지원하고 있다.

그도 그럴것이.. 이 소프트웨어의 개발자인 Open Babel development team에서 말하길

이 프로젝트의 목표는 다음과 같다고 한다.

"Open Babel is a community-driven scientific project assisting both users and developers as a cross-platform program and library designed to support molecular modeling, chemistry, and many related areas, including interconversion of file formats and data."

분자 모델링, 화학, 파일 포맷과 데이터 간의 상호변환을 다루는 관련 영역들의 분야를

지원하기 위한 학술 프로젝트이다.



2. 공식 홈페이지에서 다운로드 가능하다.

Windows 64-bit 호환되는 2.4.1 버전을 다운받아서 설치해보았다.

(OpenBabelGUI의 실행모습)

3. 왼쪽엔 input format이 있고 오른쪽엔 output format이 있다.

나는 SMILES 포맷에서 sdf 파일로 만들어보려 한다.

역시 stereoisomer는 3D로 만들어야 한다, 

그래서 'Generate 3D coordinates'에 체크하고 30개 정도의 SMILES text를 입력해서

CONVERT를 눌러보았다.



4. 결과는


(날 이렇게까지 몰아세운건 스카이림 모드떡칠 이후로 너가 처음이야)

아마도 뭔가 문제가 있는 모양이다.



5. 그래서 30개를 하나하나 확인하던 중... 특정 SMILES 파일이 

유독 에러를 일으키는 것을 확인했다.

문제의 시퀀스는 바로 이것.

[H][C@@]1(CC[C@]2(O)[C@]3([H])CC[C@]4([H])C[C@H](CC[C@]4(C)[C@@]3([H])CC[C@]12C)O[C@H]1C[C@H](O)[C@H](O[C@H]2C[C@H](O)[C@H](O[C@H]3C[C@H](OC(C)=O)[C@H](O)[C@@H](C)O3)[C@@H](C)O2)[C@@H](C)O1)C1=CC(=O)OC1

이 시퀀스만 들어가면 RAM 사용량이 4GB까지 뛰고, 일에 진척이 없다.

문제가 무엇일까 고민하기 이전에, 일단 내게는 변환해야 할 파일이 많이 남아있다.

(약 2500개 정도...)

그래서 이렇게 띵깡부리는 녀석들은 제치고 억지로 진행시키기 위해

옵션을 더 살펴보고 'Continue with next object after error, if possible'을 체크 후

다시 CONVERT를 눌러보았다.

... 역시나 실패.



6. 그래서 이번엔 output format을 바꿔보기로 했다.

mol, mol2, pdb, xyz 모두 실패.

이쯤되면 이 녀석의 정체가 궁금해진다.

그래서 입체구조를 확인해보기로 한다.


유명한 녀석이었다. 강심제로 쓰이는 약물 중 하나.

심장 세포(myocytes)의 세포막에 있는 Na+/K+ ATPase 펌프의 alpha-subunit의 extracellular 부위에 결합하는 약물로, 결과적으론 울혈성 심부전이 발생했을 때 심박 수축을 강하게 만들어주는 역할을 한다(Used for fast digitalization in congestive heart failure). 자세한건 여기를 참조.

여담이지만, digitalization이란 말은 디기탈리스(digitalis)라는 식물에서 유래했다고 한다.



7. 정체는 알았으니 이 녀석을 skip할 방법을 알아보자.

...

...

딱히 옵션이 없다.

에러가 나면 다음 객체로 넘어가자던 옵션은 말을 듣지 않는다.

그래서 요 녀석 하나만 빼놓고 29개를 CONVERT 해보았다.


아까는 욕해서 미안해.

속 편하게 강심제 그 녀석은 다른 곳에서 다시 만나기로 하자.

솔직히 SMILES formatted text를 보고 직접 구조를 그려보고 싶지만

이미 그걸 그려주는 온라인 툴도 손 놓아버린 마당에, 그럴 필요는 없을 것 같다.



8. 수천 개의 파일 중에서 에러를 일으키는 것만 쏙쏙 지나갈 방법이 딱히 떠오르지 않는다.

그런 녀석만 골라서 제외할 방법도 아직 잘 모르겠다.



시간은 흐르고 흘러... 2019년 2월 26일



9. 사실 obgui.exe는 GUI를 위한 프로그램이었을 뿐, 본체는 babel.exe와 obabel.exe였다.

그리고 그 사이에 python module에 관해 알아보았다.

문서에 따르면 python 인터페이스에서 사용할 수 있는 모듈은 총 두 개.

하나는 openbabel module이고 다른 하나는 Pybel module이다.

설치법은 어느 패키지와 마찬가지로 그것이겠거니와 싶어서

PyCharm에서 찾아보았다.

(PyCharm - Setting - Project:{your project name} -
 Project Interpreter - click plus sign)

사실 이 패키지를 설치하기 앞서 python binding for Open Babel을 설치해줘야만 한다.

이 Python bindings라는 것은 OpenBabel과 Python 사이를 연결해주는 일종의

징검다리 역할을 하고 있는 것 같았다.

그리고 OpenBabel에게 명령을 보내는 역할을 할 코드들이 바로 위 사진에 있는

파이썬의 openbabel package인 것 같다.

근데 여기에서 또 문제가 발생했다.



10. Python binding이 설치되지 않는다.


(ㅇㅇ?)

난 분명 파이썬이 깔려있는데 무슨 소리..

그래서 구글링했더니 이러한 답변이 있었다.

"Open Babel DLL은 32-bit python만을 지원하고 있습니다. 64-bit python까지 호환되는

배포버전을 유지관리 하기엔 너무 힘들더라구요."



11. 그래서 python x86을 side-by-side 설치하려 하는데, 설치법에 특이사항이 있었다.

'Register Extensions'에 체크를 해제하라는데,

위의 에러에서 봤듯이, 레지스트리에 아예 파이썬 설치가 뜨질 않았다.



12. 이쯤 되니 귀찮아졌다.

이 방법을 고집할 필요가 있을까 하는 생각이 슬슬 올라오기 시작한다.

나의 목적은 SMILES format을 3D SDF coordinate format으로 변환시키는 것.

그냥 기본으로 돌아가서 파이썬 빼고 사용법대로 응용해보자.



13. 기본 사용법

기본적으로 input 대비 output을 주는 프로그램이다.

나의 경우는 설치 경로가 "C:\Program Files\OpenBabel-2.4.1"이었고

해당 위치에서 Windows PowerShell을 실행해 명령어를 입력해보았다.

(꿀팁: 윈도우 탐색기에서 shift + 우클릭을 하면 해당 위치에서 파워쉘 실행 가능)

(꿀팁)

파일을 디렉토리에 놓고 실행시켜보았다.

obabel -i smi test.smi -o sdf -O test.sdf --gen3d -h

obabel -i {input_format} {input_file} -o {output_format} -O {output_file} --{option}


이렇게 사용했다.

-h 옵션은 explicit로 만들어주기 위해 hydrogens를 추가시켜주는 옵션이다.

반대로 implicit로 만들고 싶을 땐 hydrogens을 제거하기 위해 -d 옵션을 주면 된다.

If you want to add hydrogens (i.e. make them all explicit) when doing the conversion the command would be:


왜 babel.exe 대신에 obabel.exe를 사용하는지는 홈페이지에서 설명해주고 있었다.

요약하면, babel에서 기능을 더 추가해 만든 것이 obabel이라고 하고

앞으론 obabel이 babel을 대체할 것이니 그걸 쓰는 것이 권장된다는 이야기였다.



그런데 간과한 사실이 있었다. 여기는 프로그램이 저장되는 곳이지

데이터가 저장되는 곳이 아니었다. 그래서 권한 설정이 없는 곳에서 다시 실행시켰다.

(잘 작동한다.)

14. 하지만 내겐 아직 2360개의 파일이 더 남아있었다.

딱히 이 작업을 편리하게 만들어주는 UI를 만들 필요는 없어보이고

나의 파일을 처리하기 위한 코드만 만들기로 했다.

이 과정은 개인적으로 파이썬을 사용했다. 얼마 걸리지도 않는다.



15. 그런데 또 간과한 사실이 있었다.

일단 파일명에 스페이스바 ' '가 들어있으면 '_'로 치환해주는 편이 좋다는 점.