자택경비대

Python scrapy 사용법

Programming

개요

기본적으로 scrapy crawler의 조작은 scrapy 명령어를 통해 이루어진다.

scrapy는 해당 모듈을 global이 아닌 virtualenv등을 이용하여 프로젝트 단위로 관리하는 것을 권장한다.

Spider class?

CrawlerRule, 즉 규칙을 구체화 시킬 수 있도록 만든 클래스이다. 디자인 패턴에서는 Template Method Pattern과 같이 scrapy.Spider 클래스 자체로는 특별한 일을 하지 않지만, 크롤러의 행동을 정의해 놓았기 때문에 이를 상속된 하위 클래스에서 구현해주는 패턴으로 생각하면 될 것 같다.

하위 클래스에서는 기본적으로 scrapy.Spider 클래스를 상속받도록 구현해야 한다. 흐름은 start_requests 함수에서 반환된 scrapy.Request객체를 시작으로, 각 응답 scrapy.http.Responsecallback 매개변수의 인자로서 넘겨주게 된다.
start_requests는 일련의 scrapy.Request객체들을 반환하는데, 이는 start_urls라는 URL을 모은 list타입의 Property로 대체할 수 있다. (이 때는, scarpy.Request처럼 callback 지정이 없기 때문의 자동으로 self.parsecallback으로 사용한다.)
callback 매개변수는 보통 parse 함수를 지정하게 되는데, 여기서 받아온 응답에 대한 처리를 진행하게 된다.
callback에서 인자로 받은 응답 값을 처리하여 직접 파일로 저장하게 하거나, 반환하여 scrapy에서 처리하도록 할 수 있다.
parse에서 반환된 객체들은 결과물로서 scrapy 옵션에 따라 파일에 저장되거나 stdout 으로 출력되게 할 수 있다.
parse 함수 또한 scrapy.Request객체를 돌려주도록 할 수 있는데, 이 경우 다시 start_requests로 흐름이 넘어가 응답을 받아오게 된다.
따라서 파싱 된 결과물에서 다음페이지로 이동 등의 링크를 추출하여 다시 start_requests로 넘겨주는 것이 가능하게 된다. 이 때는 보통 response.follow라는 축약 명령을 사용해서 가독성을 높이고, 불필요한 타이핑도 줄일 수 있다.

scrapy command

scrapy 프로젝트 생성하기
scrapy startproject [project_name]

구현한 spider를 실행
scrapy crawl [spider_name]

특정 URL의 spider구현을 위한 interactive 모드
scrapy shell [URL]

scrapy.Spider를 상속하는 템플릿 코드 생성
scrapy genspider [spider_name] [URL]

spider의 목록을 출력
scrapy list

파이썬의 GIL(Global Interpreter Lock)

Programming

GIL(Global Interpreter Lock)의 존재 이유

멀티스레딩 환경에서 CPython의 경우 메모리 관리목적으로 reference count를 측정하는데, 이때 race condition이 일어나서 메모리 누수가 일어나거나, 사용중인 객체의 해제등의 치명적인 문제가 발생할 수 있기 때문에 각 객체에 락을 거는 방안을 생각했으나, 이 또한 동시에 여러개의 객체에 락이 걸리게 되면서 데드락의 문제가 발생할 수 있어, 파이썬 바이트코드 단위에 락을 걸어 두가지의 문제를 해결 할 수 있지만 한편으로는 이로 인해서 싱글 스레드로 동작할 수 밖에 없는 환경이 만들어지게 되었다.

GIL이 최선의 방안이었을까? 혹은, 단순히 파이썬 개발진의 잘못된 선택은 아니었을까?

역설적으로 GIL로 인해서 파이썬이 추구하던 쉽고 빠른 개발의 디자인을 완성할 수 있게 되었다. C로 작성된 많은 확장 프로그램들이 파이썬으로 옮겨질때 양측의 조화를 위해 thread-safe한 메모리의 제공이 필요했는데 GIL이 이 역할에 제격이었던 것이다. 이로써 thread-safe하지 않은 C 프로그램들이 python으로 쉽게 확장 될 수 있었다.

Reference

'Programming' 카테고리의 다른 글

XPath 사용방법  (0) 2020.04.21
Python scrapy 사용법  (0) 2020.04.21
pre-emptive multitasking vs cooperative multitasking  (0) 2020.04.12
Python2 pwntools SyntaxError: invalid syntax 해결방법.  (0) 2020.04.03
Bash 매개변수 확장  (0) 2020.03.31

pre-emptive multitasking vs cooperative multitasking

Programming
  • pre-emptive multitasking (i.e. threading)

    • 운영체제가 언제든지 태스크에 개입하여 switch 가능
    • 시간기반으로 스케줄러에 의해 관리됨"
  • copperative multitasking (i.e. asyncio)

    • 코드 상에서 어디에서 태스크가 끝나고 switching이 되는지 조절 가능
    • 프로세스가 자발적으로 주도권을 양보한다

Python timeit 모듈 사용법 (성능 측정)

Programming
# 기본적인 사용법
# import timeit
# timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
#
# stmt: 성능을 측정할 코드를 뜻한다.
#         '''code''', """code""" 등의 멀티라인 스트링을 이용해서 작성할 수도 있다.
# e.g.)
# >>> timeit('''\
# ... for i in range(100):
# ...     n += i
# ... ''', setup='n=0')
#
# setup: 측정 전 필요한 코드를 나타낸다. 유닛 테스트의 setup, teardown 과 같은 개념이라고 봐도 무방하다.
# timer: 측정에 사용할 타이머 함수를 지정한다. 이는 파이썬을 실행하는 플랫폼에 따라 달라질 수 있다.
# number: 테스트를 몇 번 시행할 지 나타낸다.

>>> from timeit import timeit
>>> timeit('"number is " + str(n)', setup='n=123')
0.26701879501342773
>>> timeit('"number is %d" % (n,)', setup='n=123')
0.6445150375366211

Python curses 모듈 사용법

Programming
curses.echo()  # 키보드 입력값이 화면에 출력되도록 설정
curses.noecho()  # 키보드 입력값이 화면에 보이지 않도록 설정

curses.cbreak() # 일반적으로는 키보드 입력값이 버퍼링 되며, Enter키를 눌렀을때 입력이 되지만 
                # cbreak 모드를 설정하면 버퍼링 없이 입력을 받을 수 있다
curses.nocbreak() # 위에서 언급한 cbreak 모드를 해제

curses.initscr() # stdscr을 초기화
curses.endwin()  # 프로그램이 실행 되기 이전의 터미널 세션을 복원한다

from curses import wrapper  # wrapper는 위의 curses.initscr()과 curses.endwin()의 과정을
                            # 중간에 Exception이 발생하여 강제종료 되었을 경우에도 핸들링 되도록 한다

wrapper(main)  # 이런식으로 callable 객체를 파라미터로 넘겨주면 된다

def main(stdscr):
    print('LINES:', curses.LINES, ', COLS:', curses.COLS)  # LINES, COLS 값을 가져 올 수 있다
    y = x = 0
    stdscr.move(y, x)  # 커서를 y, x 좌표로 이동시킨다.

파이썬의 다중 대소비교

Programming

파이썬에서 1 < 3 and 3 > 21 < 3 > 2 식으로 줄여서 사용이 가능하다.

물론 result = 1 < 3; result > 2 식으로 여러 행에 걸쳐 처리하게 되면, 예상대로 문제가 발생하지만 (True > 2 == False이기 때문에..) 한 줄로 처리하게 되면 and로 결합한 것 과 같은 결과를 나타낸다.

범위 표현식을 간결하게 표현 할 때 상당히 유용할 것 같다.

몰랐던 사실..

>>> 1 < 3 > 2
True
>>> 1 < 3
True
>>> True > 2
False
>>> 1 < 3 and 3 > 2
True